SpringMVC @RequestBody的使用

 

@RequestBody的做用

@RequestBody用於讀取Request請求的body數據,而後利用SpringMVC配置的HttpMessageConverter對數據進行轉換,最後把轉換後的數據綁定到被@RequestBody註解的參數上;java

@RequestBody的使用場景

根據request header中 Content-Type和被@RequestBody註解的參數不一樣,最多見的應用場景以下:json

  1.  Content-Type爲application/json
    • 參數爲JavaBean:可實現json反序列化爲JavaBean,使用的HttpMessageConverter爲 MappingJackson2HttpMessageConverter
    • 參數爲String:簡單將字符串賦值給參數,使用的HttpMessageConverter爲 StringHttpMessageConverter
  2.  Content-Type爲application/xml
    • 參數爲JavaBean可實現xml反序列化爲JavaBean,使用的HttpMessageConverter爲 Jaxb2RootElementHttpMessageConverter
    • 參數爲String:簡單將字符串賦值給參數,使用的HttpMessageConverter爲 StringHttpMessageConverter
  3. 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:mvc

  1. ByteArrayHttpMessageConverter: 負責讀取二進制格式的數據和寫出二進制格式的數據;
  2. StringHttpMessageConverter:   負責讀取字符串格式的數據和寫出二進制格式的數據;
  3. ResourceHttpMessageConverter:負責讀取資源文件和寫出資源文件數據; 
  4. FormHttpMessageConverter:       負責讀取form提交的數據(能讀取的數據格式爲 application/x-www-form-urlencoded,不能讀取multipart/form-data格式數據);負責寫入application/x-www-from-urlencoded和multipart/form-data格式的數據;
  5. MappingJacksonHttpMessageConverter:  負責讀取和寫入json格式的數據;
  6. SouceHttpMessageConverter:                   負責讀取和寫入 xml 中javax.xml.transform.Source定義的數據;
  7. Jaxb2RootElementHttpMessageConverter:  負責讀取和寫入xml 標籤格式的數據;
  8. AtomFeedHttpMessageConverter:              負責讀取和寫入Atom格式的數據;
  9. RssChannelHttpMessageConverter:           負責讀取和寫入RSS格式的數據;

 

HttpMessageConverter匹配過程

根據Request對象header部分的ContentType類型和被註解參數類型,逐一匹配合適的HttpMessageConverter來讀取數據;app

    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;
    }

 

注意

  1. 在一個方法的參數列表中,@RequestBody只能使用一次;
  2. json字符串中,若是value爲""的話,後端對應屬性若是是String類型的,那麼接受到的就是"",若是是後端屬性的類型是Integer、Double等類型,那麼接收到的就是null;
  3. json字符串中,若是value爲null的話,後端對應收到的就是null;
  4. 在傳json字符串給後端時,若是某個key沒有value的話,要麼乾脆就不寫該key,要麼就將value賦值null  或"",不能有相似 {......,"key":,.....}, 這樣的寫法
相關文章
相關標籤/搜索