spring mvc json及各类视图解析 源码分析

附上自己项目的配置文件:




    
        
            
            
                
                    
                        text/html
                        application/json
                        application/javascript
                        text/plain
                    
                
                
            
            
                
            
        
    

    
    

    
        
        
    

    
    
    
    
    
    

    
        
        
        
        
        
            
                
                
                
            
        
    

    
    
        
        
        
            
                
            
        

        
            
                
                auto_detect
                
                UTF-8
                UTF-8
                zh_CN
                yyyy-MM-dd
                HH:mm:ss
                /spring.ftl as spring
                yyyy-MM-dd HH:mm:ss
                #
                
                true
                
                html_debug
                
            
        
    

    

    
    
        
        
            
                
                    
                    
                    
                    
                    
                    
                
                
                    
                    
                    
                    
                
            
        
        
            
                
                    
                    
                    
                
                
                    
                    
                
                
            
        
    

    
        
            
                com.dianping.emidas.merchant.**.domain
            
        
        
        
        
        
        
    

    
    
    
    
    
   
       
        
        
        
        
        
            
                error/error-page
                error/error-page
                error/error-page
                error/error-page
            
        
        
        
            
                500
                
            
        
        
        

        
        
    


首先谈一下,mvc中对各种请求及返回类型的一些认识。(以下内容皆基于springmvc 4.0之后的版本)
项目中基本的使用情况,有以下几类
请求:
1、path、parameter,key/value形式绑定数据
2、requestBody,json格式字符串映射controller参数对象,只支持post请求,并且contentType需设置为contentType: "application/json"
返回:
1、freemarker、velocity基础请求返回基于模板引擎渲染的html页面
2、rest形式,返回json/jsonp/xml形式的对象,具体返回类型由请求头 accept与提供的messageconverter决定 accept与contentType概念参考

http://blog.csdn.net/z69183787/article/details/52313101
3、excel或pdf类文件流以供下载

requestbody、responsebody(messageConverter处理):


3.X版本后spring 使用 RequestMappingHandlerMapping和RequestMappingHandlerAdapter 处理requestbody及responsebody及一些注解
同样也可以使用默认配置 ,相当于注册了上述两个处理器及对应的messageConverter
messageConverter用于对请求及响应的对象及消息进行对应的处理转换,有如下几个实现:
StringHttpMessageConverter:将请求信息转换为字符串,T为String,可读取所有媒体类型(*/*),可通过supportedMediaTypes属性指定媒体类型
ByteArrayHttpMessageConverter:读写二进制数据,T为byte[]类型,可读取*/*,可通过supportedMediaTypes属性指定媒体类型,响应信息媒体类型为application/octer-stream
MarshallingHttpMessageConverter:T为Object,可读取text/xml和application/xml媒体类型请求,响应信息的媒体类型为text/xml或application/xml
Jaxb2RootElementHttpMessageConverter:通过JAXB2读写XML信息,将请求消息转换到标注XmlRootElement和XmlType注解的类中,T为Object,可读取text/xml和application/xml媒体类型请求,响应信息的媒体类型为text/xml或application/xml
MappingJackson2HttpMessageConverter:利用jackson的ObjectMapper读写Json数据,T为Object,可读取application/json,响应媒体类型为application/json
FormHttpMessageConverter/XmlAwareFormHttpMessageConverter/ResourceHttpConverter
通常使用的比较多的就是MappingJackson2HttpMessageConverter:



    
text/html
application/json
application/javascript
text/plain
    



简单描述一下此转换器的属性及工作方式

springmvc初始化时,会根据


        
        
        
        
        
            
                
                
                
            
        
    

中的配置项生成ContentNegotiationManager,并将对应策略mediaType的解析strategies注入

其中配置项ignoreAcceptHeader true:忽视请求头中的accept中的contentType,去除HeaderContentNegotiationStrategy策略;false为默认项

favorPathExtension标示启动后缀匹配mediaType,比如a.xml匹配excel

defaultContentType标识默认contentType,启动FixedContentNegotiationStrategy策略

当defaultContentType生效时,会忽略header中的accept,chrome中浏览器访问接口的 accept为

  1. Accept:
    text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
可以看到最后又 */*,该mediaType可以兼容任何响应mediaType。

完。

接上,其中supportedMediaTypes指定了该转换器可以支持的响应contentType,当请求中的contentType与该转换器的支持类型匹配时,springmvc会选择该消息转换器进行消息响应及格式处理。
在项目中最常见的情况就是,浏览器直接访问请求,返回http406,就是因为当浏览器直接访问同时(ignoreAcceptHeader 为true)时,

当设置defaultContentType时即返回 默认contentType,若恰好设置的值无法与转换器中的匹配,比如设置为text/html ,返回requestedMediaTypes 为 text/html,

当json转换器中没有配置该mediaType时,即会返回406(无法处理该类请求)。

当未设置defaultContentType时 由于所有策略均无法解析,mediaType为空 ,返回requestedMediaTypes 为 */*,即可匹配所有messageConverter


当如下请求进入时,并有@ResponseBody注解时,

@ResponseBody
    @RequestMapping(method = RequestMethod.GET, value = "/test")
    public Test index(Test t) throws Exception {
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(t.getA()));
        return new Test();
    }
由AbstractMessageConverterMethodProcessor的writeWithMessageConverters进行处理,其中有如下关键方法

Class returnValueClass = getReturnValueType(returnValue, returnType);
HttpServletRequest servletRequest = inputMessage.getServletRequest();
List requestedMediaTypes = getAcceptableMediaTypes(servletRequest);
List producibleMediaTypes = getProducibleMediaTypes(servletRequest, returnValueClass);

其中List requestedMediaTypes = getAcceptableMediaTypes(servletRequest);将根据之前ContentNegotiationManager注入的strategies返回该请求所需要响应的contentType的mediaType。

List producibleMediaTypes = getProducibleMediaTypes(servletRequest, returnValueClass);根据returnValueClass的类型,对xml中的配置messageConverter进行匹配,若满足序列化或消息处理条件(canWrite),就将此messageConverter的supportedMediaTypes加入到结果集中。每个messageConverter都有默认的mediaType,比如MappingJackson2HttpMessageConverter为application/json;charset=UTF-8与application/*+json;charset=UTF-8;这里的messageConverter为之前 注解注入的 各种消息处理器的实现,其中register-defaults为取消默认messageConverter。

关于messageConverter的其他内容可以参见:

http://blog.csdn.net/z69183787/article/details/52261274 

http://blog.csdn.net/z69183787/article/details/52261238

http://blog.csdn.net/z69183787/article/details/52302172

之后对请求需要的与mvc提供的进行一个匹配,然后得到真实的messageConverter,并调用write方法进行json渲染。


以上是对响应消息时mvc的messageConverter处理模式。下面来看一下请求时的处理方式,这里使用@RequestBody直接接收json来调试,

RequestResponseBodyMethodProcessor负责处理

当如下请求进入时,@RequestBody请求必须为Post

@ResponseBody
    @RequestMapping(method = RequestMethod.POST, value = "/test")
    public Test index(@RequestBody Test t) throws Exception {
        System.out.println(t);
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(t.getA()));
        return new Test();
    }

进入resolveArgument方法 对requestbody中的数据与参数的json对象进行绑定

public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception 

有一点需要注意,如果ajax传入的json字符串中的参数比实际接收java对象的参数多,那么会抛出转换失败的异常org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON

解决方案:http://blog.csdn.net/z69183787/article/details/52302323

http://blog.csdn.net/z69183787/article/details/52302392


视图解析器(viewResolver处理):

ContentNegotiatingViewResolver在我的理解里是对 同一资源请求进行不同形式的返回,参考 http://blog.csdn.net/z69183787/article/details/41654603?locationNum=1

流程:,未完待续。 http://blog.csdn.net/z69183787/article/details/41696709?locationNum=2

jsonp支持

http://blog.csdn.net/z69183787/article/details/52290014

http://blog.csdn.net/z69183787/article/details/52290032

你可能感兴趣的:(SpringMvc-原理分析)