zoukankan      html  css  js  c++  java
  • SpringMVC @RequestBody的使用

    @RequestBody的作用

    @RequestBody用于读取Request请求的body数据,然后利用SpringMVC配置的HttpMessageConverter对数据进行转换,最后把转换后的数据绑定到被@RequestBody注解的参数上;

    @RequestBody的使用场景

    根据request header中 Content-Type和被@RequestBody注解的参数不同,最常见的应用场景如下:

    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:

    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来读取数据;

        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":,.....}, 这样的写法
  • 相关阅读:
    ASP.NET MVC学习笔记-----ActionInvoker
    quartz启动报错
    THUSC 2021 游记
    C++下随机数的生成
    友链
    memset一些技巧
    CodeForces Round #705 总结&题解
    php计算两坐标距离
    vue中使用keepAlive组件缓存遇到的坑
    vue 中 keepAlive
  • 原文地址:https://www.cnblogs.com/canger/p/10333132.html
Copyright © 2011-2022 走看看