• HttpMessageConverter和ContentNegotiatingViewResolver


    HttpMessageConverter

    在SpringMVC中,可以使用@RequestBody和@ResponseBody两个注解,分别完成请求报文到对象和对象到响应报文的转换,HttpMessageConverter完成了这种消息转换机制。

    HttpMessageConverte接口定义:

    package org.springframework.http.converter;
    
    import java.io.IOException;
    import java.util.List;
    
    import org.springframework.http.HttpInputMessage;
    import org.springframework.http.HttpOutputMessage;
    import org.springframework.http.MediaType;
    
    public interface HttpMessageConverter<T> {
    
        boolean canRead(Class<?> clazz, MediaType mediaType);
    
        boolean canWrite(Class<?> clazz, MediaType mediaType);
    
        List<MediaType> getSupportedMediaTypes();
    
        T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
                throws IOException, HttpMessageNotReadableException;
    
        void write(T t, MediaType contentType, HttpOutputMessage outputMessage)
                throws IOException, HttpMessageNotWritableException;
    
    }
    

    HttpMessageConverter接口的定义出现了成对的canRead(),read()和canWrite(),write()方法,MediaType是对请求的Media Type属性的封装。举个例子,当我们声明了下面这个处理方法。

    @RequestMapping(value="/string", method=RequestMethod.POST)
    public @ResponseBody String readString(@RequestBody String string) {
        return "Read string '" + string + "'";
    }
    

    在SpringMVC进入readString方法前,会根据@RequestBody注解选择适当的HttpMessageConverter实现类来将请求参数解析到String变量中,具体来说是使用了StringHttpMessageConverter类,它的canRead()方法返回true,然后它的read()方法会从请求中读出请求参数,绑定到readString()方法的string变量中。

    当SpringMVC执行readString方法后,由于返回值标识了@ResponseBody,SpringMVC将使用StringHttpMessageConverter的write()方法,将结果作为String值写入响应报文,当然,此时canWrite()方法返回true。

    将上述过程集中描述的一个类是org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor,这个类同时实现了HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler两个接口。前者是将请求报文绑定到处理方法形参的策略接口,后者则是对处理方法返回值进行处理的策略接口。RequestResponseBodyMethodProcessor这个类,同时充当了方法参数解析和返回值处理两种角色。而在此过程中,以是否有@RequestBody和@ResponseBody为条件,然后分别调用HttpMessageConverter来进行消息的读写。

    ContentNegotiatingViewResolver

    主要完成同一资源,多种展现的功能。

    三种指定资源格式的方式

    Http Request Header: Accept
    GET /test/123 HTTP/1.1
    Accept: application/json  //返回json格式数据
    
    GET /test/123 HTTP/1.1
    Accept: application/xml  //返回xml格式数据
    

    如果你的资源是通过浏览器访问的,那么由于浏览器的差异,传递到服务器的Accept Header是有差异的,将导致服务器不知道返回何种格式的数据给浏览器。下面是各种浏览器的Accept Header:

    chrome:  
    Accept:application/xml,application/xhtml+xml,textml;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5  
      
    firefox:  
    Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8  
      
    IE8:  
    Accept:image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/x-silverlight, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocument, application/xaml+xml, */*  
    
    使用扩展名
    /test/123.xml  //返回xml格式数据
    /test/123.json  //返回json格式数据
    

    丧失了同一url多种展现的方式,但现在这种在实际环境中是使用最多的,因为更加符合程序员的审美观。

    使用参数
    /test/123?format=json  //返回json格式数据
    /test/123?format=xml  //返回xml格式数据
    

    现在很多open API是使用这种方式,但可能由于要编写的字符较多,所以较少使用。

    ContentNegotiatingViewResolver配置

    内容协商(content negotiation)的工作是由ContentNegotiatingViewResolver来完成的。它的工作模式支持我上面讲的三种,ContentNegotiatingViewResolver是根据客户提交的MimeType(如 text/html,application/xml)来跟服务端的一组viewResover的MimeType相比较,如果符合,即返回viewResover的数据。

    ContentNegotiatingViewResolver配置:

    <bean id="contentNegotiationManager"
          class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
        <property name="favorPathExtension" value="true" />
        <property name="favorParameter" value="true" />
        <property name="parameterName" value="format" />
        <property name="ignoreAcceptHeader" value="false" />
        <property name="mediaTypes">
            <value>
                json=application/json
                xml=application/xml
            </value>
        </property>
        <property name="defaultContentType" value="text/html" />
    </bean>
    
    <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="contentNegotiationManager" ref="contentNegotiationManager"/>
        <property name="viewResolvers">
            <list>
                <bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
                <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                    <property name="prefix" value="/WEB-INF/jsp/"/>
                    <property name="suffix" value=".jsp"/>
                </bean>
            </list>
        </property>
        <property name="defaultViews">
            <list>
                <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
            </list>
        </property>
    </bean>
  • 相关阅读:
    0-完全开源的 Vue.js 入门级教程:HelloVue,发车啦!
    [Java 开源项目]一款无需写任何代码,即可一键生成前后端代码的工具
    用 Java 做个“你画手机猜”的小游戏
    PowerJob 从 0 到 1.9k star 的经历
    最后一篇:结束不想说再见,那就扬帆再次起航!
    shell 常用快捷键
    微服务网关评测对比
    Docker加入自定义iptables规则链
    CentOS.7防火墙firewalld属性
    bash和shell的差别
  • 原文地址:https://www.cnblogs.com/coderland/p/5902671.html
Copyright © 2020-2023  润新知