SpringMVC配置多视图-内容协商原理
Spring Framework 3.2增强了ContentNegotiationManager,使得配置多视图变得尤为轻松。并且对于多视图的解析的实现都可以有多种供你选择。如果你想使用Spring作为网站后台,并且想完全分离 前后台的代码依赖,那么了解如何配置Spring的基于内容协商多视图是非常必须而且有用的。下面就来看看如何配置Spring,让它支持JSON/XML视图吧。
先看看Spring的官方文档关于Content Negotiation的improvements
可见,内容协商其实说白了很简单,就是根据请求规则决定返回什么样的内容类型。后缀规则、参数规则、Accept头规则、固定的内容类型等。注意,这里只是决定,不是具体提供内容类型的地方。
好了,现在正式开始配置的介绍:
这里默认你已经配置好Spring的DispatcherServlet,并设置映射路径是“/”,例如下面的配置:
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
- id="WebApp_ID" version="3.0">
- <display-name>lab-order</display-name>
- <welcome-file-list>
- <welcome-file>index.html</welcome-file>
- <welcome-file>index.htm</welcome-file>
- <welcome-file>index.jsp</welcome-file>
- <welcome-file>default.html</welcome-file>
- <welcome-file>default.htm</welcome-file>
- <welcome-file>default.jsp</welcome-file>
- </welcome-file-list>
- <context-param>
- <description>上下文配置地址</description>
- <param-name>contextConfigLocation</param-name>
- <param-value>/WEB-INF/mvc-servlet.xml</param-value>
- </context-param>
- <context-param>
- <description>log4j配置位置</description>
- <param-name>log4jConfigLocation</param-name>
- <param-value>/WEB-INF/log4j.properties</param-value>
- </context-param>
- <servlet>
- <description>核心Servlet</description>
- <servlet-name>mvc</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- </servlet>
- <servlet-mapping>
- <servlet-name>mvc</servlet-name>
- <url-pattern>/</url-pattern>
- </servlet-mapping>
- <listener>
- <description>log4j配置侦听</description>
- <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
- </listener>
- <listener>
- <description>Spring上下文侦听加载器</description>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
- <filter>
- <description>编码过滤器</description>
- <filter-name>encodingFilter</filter-name>
- <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
- <init-param>
- <param-name>encoding</param-name>
- <param-value>UTF-8</param-value>
- </init-param>
- <init-param>
- <param-name>forceEncoding</param-name>
- <param-value>true</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>encodingFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- </web-app>
然后配置核心Sevlet的上下文环境,这里是文件“mvc-servlet.xml”。如下:
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
- xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p"
- xmlns:c="http://www.springframework.org/schema/c"
- xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
- http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
- <!-- 开启注解驱动 -->
- <!-- 这样可以使用@Controller这些注解 -->
- <mvc:annotation-driven
- content-negotiation-manager="contentNegotiationManager"></mvc:annotation-driven>
- <!-- 开启默认处理 -->
- <!-- 这样静态资源就可以访问了 -->
- <mvc:default-servlet-handler />
- <!-- 开启上下文注解配置 -->
- <!-- 使@Autowire注解被支持 -->
- <context:annotation-config></context:annotation-config>
- <!-- 配置注解扫描包 -->
- <context:component-scan base-package="org.laohu.modules"
- annotation-config="true"></context:component-scan>
- <!-- 导入hibernate配置 -->
- <import resource="hibernate-beans.xml" />
- <!-- 导入视图解析配置 -->
- <import resource="view-resolve.xml" />
- <!-- 导入模块配置 -->
- <import resource="school-module.xml" />
- </beans>
“mvc-servlet.xml”中
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"></mvc:annotation-driven>
content-negotiation-manager属性就是指定内容协商管理器的bean,按照官方文档是这样的配置,但是有一个问题,这个问题稍后再和大家讨论。contentNegotiationManager这个bean配置在“view-resolve.xml中”:
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c"
- xmlns:p="http://www.springframework.org/schema/p"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
- <!-- 配置内容协商视图解析 -->
- <bean id="contentNegotiatingViewResolver"
- class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
- <!-- 设置内容协商管理器 -->
- <property name="contentNegotiationManager" ref="contentNegotiationManager"></property>
- <!-- 设置默认视图 -->
- <property name="defaultViews">
- <list>
- <ref bean="mappingJacksonJsonView" />
- <ref bean="marshallingView" />
- </list>
- </property>
- <!-- 设置视图解析器 -->
- <property name="viewResolvers">
- <list>
- <ref bean="defalutViewResolver" />
- </list>
- </property>
- </bean>
- <bean id="defalutViewResolver"
- class="org.springframework.web.servlet.view.InternalResourceViewResolver">
- <property name="prefix" value="/WEB-INF/view"></property>
- <property name="suffix" value=".jsp"></property>
- </bean>
- <!-- JSON视图 -->
- <bean id="mappingJacksonJsonView"
- class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"></bean>
- <!-- XML视图 -->
- <bean id="marshallingView"
- class="org.springframework.web.servlet.view.xml.MarshallingView">
- <property name="marshaller">
- <bean class="org.springframework.oxm.xstream.XStreamMarshaller">
- <property name="supportedClasses">
- <list>
- <value>java.util.Collection</value>
- <value>org.laohu.modules.school.model.School</value>
- <value>org.laohu.modules.school.model.Laboratory</value>
- <value>org.laohu.modules.school.model.stuff.LabMgr</value>
- </list>
- </property>
- <property name="aliases">
- <map>
- <entry value="org.laohu.modules.school.model.School" key="school"></entry>
- <entry value="org.laohu.modules.school.model.Laboratory"
- key="laboratory"></entry>
- <entry value="org.laohu.modules.school.model.stuff.LabMgr"
- key="labmgr"></entry>
- </map>
- </property>
- </bean>
- </property>
- </bean>
- <bean id="contentNegotiationManager"
- class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
- <property name="mediaTypes">
- <props>
- <prop key="json">application/json</prop>
- <prop key="xml">application/xml</prop>
- </props>
- </property>
- </bean>
- </beans>
这里配置了多个bean,先从contentNegotiateManager说起,contentNegotiateManager并不是直接使用ContentNegotiateManager构造的,而是使用其工厂bean生产的,给他配置属性mediaTypes这个属性是告诉contentNegotiateManager将每一个mediaTypes里的entry作为文件名/URL后缀,其内容类型就是entry对应的value值。也就是说,如果请求的url为http://hostname/xxx/xxx/data.json?p1=2332&p2=abc的话,contentNegotiateManager就会认为你请求的内容类型(Content-Type)为application/json,那么它就要将响应的内容类型(Content-Type)设置为application/json;如下图:
为了方便大家理解,这里贴一下火狐的请求头和服务器的响应头:
- GET /lab-order/school/.json HTTP/1.1
- Host: localhost:8080
- User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:19.0) Gecko/20100101 Firefox/19.0 FirePHP/0.7.1
- Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
- Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
- Accept-Encoding: gzip, deflate
- Cookie: ext-mainnav.west=o%3Acolumns%3Da%253Ao%25253Aid%25253Ds%2525253Aheader-1041; ext-mainnav.east.description=o%3Acollapsed%3Ds%253Atop; ext-mainnav.east=o%3Awidth%3Dn%253A322; ext-stateGrid=o%3Awidth%3Dn%253A650%5Eheight%3Dn%253A350%5Ecolumns%3Da%253Ao%25253Aid%25253Ds%2525253Aheader-1247%255Eo%25253Aid%25253Ds%2525253Aheader-1248%255Eo%25253Aid%25253Ds%2525253Aheader-1249%255Eo%25253Aid%25253Ds%2525253Aheader-1250%255Eo%25253Aid%25253Ds%2525253Aheader-1251%255Eo%25253Aid%25253Ds%2525253Aheader-1252
- x-insight: activate
- Connection: keep-alive
- Cache-Control: max-age=0
- HTTP/1.1 200 OK
- Server: Apache-Coyote/1.1
- Pragma: no-cache
- Cache-Control: no-cache, no-store, max-age=0
- Expires: Thu, 01 Jan 1970 00:00:00 GMT
- Content-Type: application/json;charset=UTF-8
- Content-Language: zh-CN
- Transfer-Encoding: chunked
- Date: Thu, 04 Apr 2013 17:38:00 GMT
可以看到请求头是普通的text/html请求,但服务器相响应的是application/json的内容类型,表明内容协商工作正常,为了进一步测试内容协商管理器是否是按照这个基于后缀的映射内容类型,我们改变映射关系,修改mediaTypes:
- <prop key="json">application/json</prop>
- <prop key="xml">application/json</prop>
即将xml也映射到application/json上,再次使用.xml访问:
请求头:
- GET /lab-order/school/.xml HTTP/1.1
- Host: localhost:8080
- User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:19.0) Gecko/20100101 Firefox/19.0 FirePHP/0.7.1
- Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
- Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
- Accept-Encoding: gzip, deflate
- Cookie: ext-mainnav.west=o%3Acolumns%3Da%253Ao%25253Aid%25253Ds%2525253Aheader-1041; ext-mainnav.east.description=o%3Acollapsed%3Ds%253Atop; ext-mainnav.east=o%3Awidth%3Dn%253A322; ext-stateGrid=o%3Awidth%3Dn%253A650%5Eheight%3Dn%253A350%5Ecolumns%3Da%253Ao%25253Aid%25253Ds%2525253Aheader-1247%255Eo%25253Aid%25253Ds%2525253Aheader-1248%255Eo%25253Aid%25253Ds%2525253Aheader-1249%255Eo%25253Aid%25253Ds%2525253Aheader-1250%255Eo%25253Aid%25253Ds%2525253Aheader-1251%255Eo%25253Aid%25253Ds%2525253Aheader-1252
- x-insight: activate
- Connection: keep-alive
响应头:
- HTTP/1.1 200 OK
- Server: Apache-Coyote/1.1
- Pragma: no-cache
- Cache-Control: no-cache, no-store, max-age=0
- Expires: Thu, 01 Jan 1970 00:00:00 GMT
- Content-Type: application/json;charset=UTF-8
- Content-Language: zh-CN
- Transfer-Encoding: chunked
- Date: Thu, 04 Apr 2013 17:50:55 GMT
响应正文:
{"schools":[{"id":1,"name":"江苏科技大学","position":"江苏镇江","content":30,"labMgrs":[],"laboratorys":[]}]}
以上就证明了当内容协商管理器使用后缀策略时的工作规律。
那么现在内容管理器知道了该响应给浏览器的内容类型后,该如何响应该内容类型给浏览器呢?contentNegotiationManager并不负责视图(数据如何呈现,JSON视图/XML视图等等),真正处理呈现的叫ViewResolver,视图解析器OR视图渲染器(姑且这么翻译),例如上面配置的defaultViewResolver就是默认的视图解析器他解析普通的jsp视图,这里不对它进行讨论,在稍后的文章中或许会专门讲一下它。但在ContentNegotiationViewResolver中配置的ViewResolver是在配置的defaultViews都没有匹配的时候才进行交接的。
那我们看看defaultViews都有些什么:mappingJacksonJsonView——传说中的JSON视图、marshallingView——编组视图XML视图。在defaultViews里注册的视图会在ContentNegotiationViewResolver中注册自己支持的内容类型,当contentNegotiationManager决定好响应的内容类型后,ContentNegotiationViewResolver就会根据该内容类型选择一个兼容的View进行渲染输出,当注册的内容类型都不兼容时,会查询viewResolver中的ViewResolver是否支持该请求,如果ViewResolver表示支持该请求,那么就由该ViewResolver负责视图渲染,如果ViewResolver表示不支持该请求,则查询下一个ViewResolver,直至所有的ViewResolver查询完毕。一旦有View对请求内容匹配,就直接渲染输出,不会进行ViewResolver的查询。由于这里配置了defaultViewResolver是InternalResourceViewResolver,它会对所有的请求说yes,所以这里的其他请求类型(非JSON/XML)都会交给它处理。查看Spring的类库,有不少ViewResolver的实现,有兴趣的同学可以去看看,我还没来得及细看这些实现,所以不会多讲这方面内容。
SpringMVC配置多视图-内容协商原理的更多相关文章
- SpringMVC整合freeMarker实现页面静态化+SpringMVC配置多视图
一.背景 1.什么是FreeMarker FreeMarker是一个模板引擎,一个基于模板生成文本输出的通用工具,使用纯Java编写 FreeMarker被设计用来生成HTML Web页面,特别是基于 ...
- springmvc 配置多视图(jsp,freemarker,HTML等)
SpringMVC 的 Controller 可以返回各种各样的视图.比如 JSP, JSON, Velocity, FreeMarker, XML, PDF, Excel, 还有Html字符流 等等 ...
- SpringMvc配置自定义视图
1.在dispatcherServlet-servlet.xml配置自定义视图 <!-- 配置视图 BeanNameViewResolver 解析器: 使用视图的名字来解析视图 --> & ...
- springmvc配置多视图 - tiles, velocity, freeMarker, jsp
转自: http://www.cnblogs.com/shanheyongmu/p/5684595.html <!-- Velocity --> <bean id="vel ...
- springmvc 配置多视图,返回jsp,velocity,freeMarker,tiles(模板)等等
springmvc-servlet.xml配置 <!-- Velocity --> <bean id="velocityViewResolver" class = ...
- SpringMVC源码分析6:SpringMVC的视图解析原理
title: SpringMVC源码分析6:SpringMVC的视图解析原理 date: 2018-06-07 11:03:19 tags: - SpringMVC categories: - 后端 ...
- springMVC+ freemark多视图配置
<!--通用视图解析器--> <bean id="viewResolverCommon" class="org.springframework.web. ...
- SpringMVC 返回 html 视图页面,SpringMVC与Servlet,Servlet重定向与转发
1. SpringMVC与Servlet的关系 SpringMVC框架是建立在Servlet之上的,提供各种功能,各种封装,各种方便的同时,它一点儿也没有限制Servlet,我们完全可以在Spring ...
- SpringMVC配置版到注解版
什么是springmvc? 1.1.什么是MVC MVC是模型(Model).视图(View).控制器(Controller)的简写,是一种软件设计规范. 是将业务逻辑.数据.显示分离的方法来组织代码 ...
随机推荐
- JS中substring与substr的用法
substring方法用于提取字符串中介于两个指定下标之间的字符 substring(start,end) 开始和结束的位置,从零开始的索引javascript 参数 描述 start 必需.一个非负 ...
- ajax知识点
什么是AJAX? AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML). AJAX 不是新的编程语言,而是一种使用现有标准的新方法. ...
- vue从入门到进阶:简介(一)
前言 用了这么久的vue了,但是一直没有时间写个系列文章,现在抽一定时间总结下vue的知识点. 首先,Vue 不支持 IE8 及以下版本,因为 Vue 使用了 IE8 无法模拟的 ECMAScript ...
- 13.Odoo产品分析 (二) – 商业板块(6) –采购(3)
接上一篇 查看Odoo产品分析系列--目录 接上一篇Odoo产品分析 (二) – 商业板块(6) –采购(2) 7. 仓库 仓库是在安装采购管理模块时出现的菜单.用于管理工厂库存,包括已经在手的货物 ...
- 银盒子智慧餐厅硬件尺寸规格&推荐机型
- 监控mysql主从同步
1,昨天看到shell一道面试题,需求如下: 监控MySQL主从同步是否异常,如果异常,则发送短信或者邮件给管理员.提示:如果没主从同步环境,可以用下面文本放到文件里读取来模拟:阶段1:开发一个守护进 ...
- 移动端 input样式在安卓与ios上不同的解决方案
input{ -webkit-appearance:none; }
- Sql Server XML
实验数据: Create table xmldata (name NVARCHAR(20), age int, sex NVARCHAR(5) ) INSERT INTO xmldata VALUES ...
- Windows Server 2016-管理站点复制(一)
可以使用Active Directory站点和服务管理单元来管理实现站点间复制拓扑的特定于站点的对象.这些对象存储在Active Directory域服务 (AD DS) 的站点容器中.同一个站点内的 ...
- NPOI 笔记
前言 文档:http://npoi.codeplex.com/documentation 示例:https://npoi.svn.codeplex.com/svn/ 下载:https://www.nu ...