使用ContentNegotiatingViewResolver将model中的数据渲染到MappingJackson2JsonView(model转成json)

来源:互联网 发布:mac版搜狗输入法 编辑:程序博客网 时间:2024/06/03 07:56
问题:
public @ResponseBody() Model indexData(Model model)
把model中的数据转成json返回客户端

小编一开始使用这样的配置:

<beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/jsp/"></property><property name="suffix" value=".jsp"></property></bean><bean    class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"></bean>


但是并没有什么用,太单纯了。根据下图DispatchServlet中的方法 resolveViewName(), 小编猜测DispatchServlet只会扫描试图解析器    类似*****ViewResolver, 根本没有使用 MappingJackson2JsonView.
protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,HttpServletRequest request) throws Exception {for (ViewResolver viewResolver : this.viewResolvers) {View view = viewResolver.resolveViewName(viewName, locale);if (view != null) {return view;}    }return null;}


So,问题来了,怎么才能使用 MappingJackson2JsonView 视图来解析呢?
经过百度,查看spring文档,看到了一个ContentNegotiatingViewResolver视图解析器,该视图解析器本身并不去解析,而是委托给其他视图解析器,关键的一点是 还可以配置默认视图 defaultViews.
这是ContentNegotiatingViewResolver的属性 defaultViews和viewResolvers很明显是用来解析视图的,读者可以看一看ContentNegotiatingViewResolver源码中的 resolveViewName(String viewName, Locale locale) 方法,他调用getCandidateViews(viewName, locale, requestedMediaTypes) 方法,后者遍历viewResolvers,分别调用每个viewResolver 的 resolveViewName(String viewName, Locale locale) 方法获得 视图 View。然后在解析出来的视图上再加上defaultView,resolveViewName(String viewName, Locale locale) 方法 最后调用 getBestView 方法得到最适合的 视图View。
ps:有些读者对视图解析的流程有点模糊,简单来说就是  视图解析器ViewrResolvers 根据 viewName 调用 resolveViewName(String viewName, Locale locale) 获得一个具体的 视图 View,然后再调用 该视图View 的render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) 方法进行渲染。



那么 ContentNegotiationManager contentNegotiationManager 和 ContentNegotiationManagerFactoryBean cnmFactoryBean 是干啥的? 很明显(如果你熟悉spring的factorybean原理的话,不熟悉可以看看《深入分析javaweb技术内幕》) ContentNegotiationManagerFactoryBean cnmFactoryBean 是用来生成ContentNegotiationManager contentNegotiationManager 的 ,那么 contentNegotiationManager 用来干什么? 
截取一段spring文档的解释如下:
其实就是用来  determined(判断)一个请求的mediatype,为什么要判断一个请求的  mediatype (attention:这个mediatype 和 http协议的请求头 Accept 中的 mediatype 不一样,后者可用来判断请求的mediatype),简单来说的话就是 ContentNegotiatingViewResolver 根据一个请求的mediatype来选择合适的 viewResolver。
 ContentNegotiatingViewResolver 会默认生成一个 ContentNegotiationManager,默认的 ContentNegotiationManager 封装了一系列解析请求的mediatype的策略(使用的策略模式),但是默认生成的

ContentNegotiationManager 只用了两个解析策略,首先根据请求的 urlpath 的后缀(例如  /***/*.json,后缀为json,该请求的mediatype为   application/json)来匹配mediatype,若找不到,则使用 http 协议请求头Accept字段判断请求的 mediatype。所以最后 你只要这样配置:
<beanclass="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"><property name="viewResolvers"><list><beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/jsp/"></property><property name="suffix" value=".jsp"></property></bean></list></property><property name="defaultViews"><list><beanclass="org.springframework.web.servlet.view.json.MappingJackson2JsonView"></bean></list></property></bean>

InternalResourceViewResolver 用来渲染jsp视图,MappingJackson2JsonView 用来解析json请求就行。
只要你把访问的地址加上 .json 后缀,或者把 请求头 Accept 设置成 application/json (可直接使用jquery的$.getJson())  就能匹配到默认视图MappingJackson2JsonView 。
同样的,只要你把访问的地址加上 .html 后缀,或者把 请求头 Accept 设置成 text/html 就可以匹配到
InternalResourceViewResolver 视图解析器。

ContentNegotiationManager 还可以可以自定义url 后缀 和 mediatype的对应关系,Accept 头 和 mediatype的对应关系等等,但是 ContentNegotiationManager 字段的作用不仅仅是这些。详细的可以看spring文档和分析源码


总结:这只是很简单的概括了一下,如果看源码的话是有很多细节的,有些细节小编没搞懂,只能这样简单的概括一下,大概的思路,共勉。这算是小编第一篇呕心原创,求支持。




















阅读全文
0 0
原创粉丝点击