@RequestBody的作用
@RequestBody用於讀取Request請求的body數據,然后利用SpringMVC配置的HttpMessageConverter對數據進行轉換,最后把轉換后的數據綁定到被@RequestBody注解的參數上;
@RequestBody的使用場景
根據request header中 Content-Type和被@RequestBody注解的參數不同,最常見的應用場景如下:
- Content-Type為application/json
- 參數為JavaBean:可實現json反序列化為JavaBean,使用的HttpMessageConverter為 MappingJackson2HttpMessageConverter
- 參數為String:簡單將字符串賦值給參數,使用的HttpMessageConverter為 StringHttpMessageConverter
- Content-Type為application/xml
- 參數為JavaBean:可實現xml反序列化為JavaBean,使用的HttpMessageConverter為 Jaxb2RootElementHttpMessageConverter
- 參數為String:簡單將字符串賦值給參數,使用的HttpMessageConverter為 StringHttpMessageConverter
- application/x-www-form-urlencoded
- 參數為String:簡單將字符串賦值給參數,使用的HttpMessageConverter為 StringHttpMessageConverter
HttpMessageConverter接口
該接口定義了五個方法,分別是讀取數據時的 canRead()、read() ,寫入數據時的canWrite()、 write()方法以及獲取支持類型的 getSupportedMediaTypes()
public interface HttpMessageConverter<T> { // Indicate whether the given class and media type can be read by this converter. boolean canRead(Class<?> clazz, MediaType mediaType); // Indicate whether the given class and media type can be written by this converter. boolean canWrite(Class<?> clazz, MediaType mediaType); // Return the list of MediaType objects supported by this converter. List<MediaType> getSupportedMediaTypes(); // Read an object of the given type from the given input message, and returns it. T read(Class<T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException; // Write an given object to the given output message. void write(T t, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException; }
使用 <mvc:annotation-driven />標簽配置時,默認配置了RequestMappingHandlerAdapter,並為他配置了一下默認的HttpMessageConverter:
ByteArrayHttpMessageConverter: 負責讀取二進制格式的數據和寫出二進制格式的數據;StringHttpMessageConverter: 負責讀取字符串格式的數據和寫出二進制格式的數據;- ResourceHttpMessageConverter:負責讀取資源文件和寫出資源文件數據;
- FormHttpMessageConverter: 負責讀取form提交的數據(能讀取的數據格式為 application/x-www-form-urlencoded,不能讀取multipart/form-data格式數據);負責寫入application/x-www-from-urlencoded和multipart/form-data格式的數據;
- MappingJacksonHttpMessageConverter: 負責讀取和寫入json格式的數據;
- SouceHttpMessageConverter: 負責讀取和寫入 xml 中javax.xml.transform.Source定義的數據;
- Jaxb2RootElementHttpMessageConverter: 負責讀取和寫入xml 標簽格式的數據;
- AtomFeedHttpMessageConverter: 負責讀取和寫入Atom格式的數據;
- RssChannelHttpMessageConverter: 負責讀取和寫入RSS格式的數據;
HttpMessageConverter匹配過程
根據Request對象header部分的ContentType類型和被注解參數類型,逐一匹配合適的HttpMessageConverter來讀取數據;
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException { ...... MediaType contentType; contentType = inputMessage.getHeaders().getContentType(); ....... for (HttpMessageConverter<?> converter : this.messageConverters) { Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass(); if (converter instanceof GenericHttpMessageConverter) { GenericHttpMessageConverter<?> genericConverter = (GenericHttpMessageConverter<?>) converter; if (genericConverter.canRead(targetType, contextClass, contentType)) { if (logger.isDebugEnabled()) { logger.debug("Read [" + targetType + "] as \"" + contentType + "\" with [" + converter + "]"); } if (inputMessage.getBody() != null) { inputMessage = getAdvice().beforeBodyRead(inputMessage, parameter, targetType, converterType); body = genericConverter.read(targetType, contextClass, inputMessage); body = getAdvice().afterBodyRead(body, inputMessage, parameter, targetType, converterType); } else { body = getAdvice().handleEmptyBody(null, inputMessage, parameter, targetType, converterType); } break; } } else if (targetClass != null) { if (converter.canRead(targetClass, contentType)) { if (logger.isDebugEnabled()) { logger.debug("Read [" + targetType + "] as \"" + contentType + "\" with [" + converter + "]"); } if (inputMessage.getBody() != null) { inputMessage = getAdvice().beforeBodyRead(inputMessage, parameter, targetType, converterType); body = ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage); body = getAdvice().afterBodyRead(body, inputMessage, parameter, targetType, converterType); } else { body = getAdvice().handleEmptyBody(null, inputMessage, parameter, targetType, converterType); } break; } } } ....... return body; }
注意
- 在一個方法的參數列表中,@RequestBody只能使用一次;
- json字符串中,如果value為""的話,后端對應屬性如果是String類型的,那么接受到的就是"",如果是后端屬性的類型是Integer、Double等類型,那么接收到的就是null;
- json字符串中,如果value為null的話,后端對應收到的就是null;
- 在傳json字符串給后端時,如果某個key沒有value的話,要么干脆就不寫該key,要么就將value賦值null 或"",不能有類似 {......,"key":,.....}, 這樣的寫法
