SpringMVC配置多视图-内容协商原理

2014年03月06日 16:46:59 日积月累_滴水石穿 阅读数:10964更多

个人分类: SpringMVC
 

Spring Framework 3.2增强了ContentNegotiationManager,使得配置多视图变得尤为轻松。并且对于多视图的解析的实现都可以有多种供你选择。如果你想使用Spring作为网站后台,并且想完全分离 前后台的代码依赖,那么了解如何配置Spring的基于内容协商多视图是非常必须而且有用的。下面就来看看如何配置Spring,让它支持JSON/XML视图吧。

先看看Spring的官方文档关于Content Negotiation的improvements

 
A ContentNeogtiationStrategy is now available for resolving the requested media types from an incoming request. The available implementations are based on the file extension, query parameter, the ‘Accept’ header, or a fixed content type. Equivalent options were previously available only in the ContentNegotiatingViewResolver but are now available throughout. ContentNegotiationManager is the central class to use when configuring content negotiation options. For more details see Section 17.15.4, “Configuring Content Negotiation”. The introduction of ContentNegotiationManger also enables selective suffix pattern matching for incoming requests. For more details, see the Javadoc ofRequestMappingHandlerMapping.setUseRegisteredSuffixPatternMatch.
一个ContentNeogtiationStrategy(是spring官方拼写错了?)现在可以使用了,它可用于解决传入请求所请求的媒体类型。可用的实现有基于文件扩展名(后缀)、请求参数、“Accept”头、或者某一固定的类容类型。与之前可以使用在ContentNegotiatingViewResolver的配置项是等效的。ContentNegotiationManager是用来配置内容协商选项的中心类。更多细节见17.15.4节 “配置内容协商”。ContentNegotiationManager的引进可以使用可选的后缀模式来匹配(映射)传入的请求,更多细节请查看RequestMappingHandlerMapping.setUserRegisteredSuffixPatternMatch.

可见,内容协商其实说白了很简单,就是根据请求规则决定返回什么样的内容类型。后缀规则、参数规则、Accept头规则、固定的内容类型等。注意,这里只是决定,不是具体提供内容类型的地方。

好了,现在正式开始配置的介绍:

这里默认你已经配置好Spring的DispatcherServlet,并设置映射路径是“/”,例如下面的配置:

  1.  
    <?xml version="1.0" encoding="UTF-8"?>
  2.  
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3.  
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
  4.  
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  5.  
    id="WebApp_ID" version="3.0">
  6.  
    <display-name>lab-order</display-name>
  7.  
    <welcome-file-list>
  8.  
    <welcome-file>index.html</welcome-file>
  9.  
    <welcome-file>index.htm</welcome-file>
  10.  
    <welcome-file>index.jsp</welcome-file>
  11.  
    <welcome-file>default.html</welcome-file>
  12.  
    <welcome-file>default.htm</welcome-file>
  13.  
    <welcome-file>default.jsp</welcome-file>
  14.  
    </welcome-file-list>
  15.  
     
  16.  
    <context-param>
  17.  
    <description>上下文配置地址</description>
  18.  
    <param-name>contextConfigLocation</param-name>
  19.  
    <param-value>/WEB-INF/mvc-servlet.xml</param-value>
  20.  
    </context-param>
  21.  
     
  22.  
    <context-param>
  23.  
    <description>log4j配置位置</description>
  24.  
    <param-name>log4jConfigLocation</param-name>
  25.  
    <param-value>/WEB-INF/log4j.properties</param-value>
  26.  
    </context-param>
  27.  
     
  28.  
    <servlet>
  29.  
    <description>核心Servlet</description>
  30.  
    <servlet-name>mvc</servlet-name>
  31.  
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  32.  
    </servlet>
  33.  
    <servlet-mapping>
  34.  
    <servlet-name>mvc</servlet-name>
  35.  
    <url-pattern>/</url-pattern>
  36.  
    </servlet-mapping>
  37.  
     
  38.  
    <listener>
  39.  
    <description>log4j配置侦听</description>
  40.  
    <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
  41.  
    </listener>
  42.  
     
  43.  
    <listener>
  44.  
    <description>Spring上下文侦听加载器</description>
  45.  
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  46.  
    </listener>
  47.  
     
  48.  
    <filter>
  49.  
    <description>编码过滤器</description>
  50.  
    <filter-name>encodingFilter</filter-name>
  51.  
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  52.  
    <init-param>
  53.  
    <param-name>encoding</param-name>
  54.  
    <param-value>UTF-8</param-value>
  55.  
    </init-param>
  56.  
    <init-param>
  57.  
    <param-name>forceEncoding</param-name>
  58.  
    <param-value>true</param-value>
  59.  
    </init-param>
  60.  
    </filter>
  61.  
    <filter-mapping>
  62.  
    <filter-name>encodingFilter</filter-name>
  63.  
    <url-pattern>/*</url-pattern>
  64.  
    </filter-mapping>
  65.  
     
  66.  
    </web-app>
 
主要关注点在于核心DespatcherSevlet的映射路径,是“/”而不是“*.do”。

然后配置核心Sevlet的上下文环境,这里是文件“mvc-servlet.xml”。如下:

  1.  
    <beans xmlns="http://www.springframework.org/schema/beans"
  2.  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
  3.  
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p"
  4.  
    xmlns:c="http://www.springframework.org/schema/c"
  5.  
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
  6.  
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  7.  
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
  8.  
     
  9.  
    <!-- 开启注解驱动 -->
  10.  
    <!-- 这样可以使用@Controller这些注解 -->
  11.  
    <mvc:annotation-driven
  12.  
    content-negotiation-manager="contentNegotiationManager"></mvc:annotation-driven>
  13.  
    <!-- 开启默认处理 -->
  14.  
    <!-- 这样静态资源就可以访问了 -->
  15.  
    <mvc:default-servlet-handler />
  16.  
     
  17.  
    <!-- 开启上下文注解配置 -->
  18.  
    <!-- 使@Autowire注解被支持 -->
  19.  
    <context:annotation-config></context:annotation-config>
  20.  
    <!-- 配置注解扫描包 -->
  21.  
    <context:component-scan base-package="org.laohu.modules"
  22.  
    annotation-config="true"></context:component-scan>
  23.  
     
  24.  
    <!-- 导入hibernate配置 -->
  25.  
    <import resource="hibernate-beans.xml" />
  26.  
    <!-- 导入视图解析配置 -->
  27.  
    <import resource="view-resolve.xml" />
  28.  
     
  29.  
    <!-- 导入模块配置 -->
  30.  
    <import resource="school-module.xml" />
  31.  
    </beans>
 
在“mvc-sevlet.xml”中并没有将所有的bean都放在里面,这是我的个人习惯,使用import指令(标签)将bean的配置分开配置,避免文件过大,修改或者查看比较麻烦,同时对于调试也是很有帮助的。

“mvc-servlet.xml”中

<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"></mvc:annotation-driven>

content-negotiation-manager属性就是指定内容协商管理器的bean,按照官方文档是这样的配置,但是有一个问题,这个问题稍后再和大家讨论。contentNegotiationManager这个bean配置在“view-resolve.xml中”:

  1.  
    <beans xmlns="http://www.springframework.org/schema/beans"
  2.  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c"
  3.  
    xmlns:p="http://www.springframework.org/schema/p"
  4.  
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5.  
     
  6.  
    <!-- 配置内容协商视图解析 -->
  7.  
    <bean id="contentNegotiatingViewResolver"
  8.  
    class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
  9.  
    <!-- 设置内容协商管理器 -->
  10.  
    <property name="contentNegotiationManager" ref="contentNegotiationManager"></property>
  11.  
    <!-- 设置默认视图 -->
  12.  
    <property name="defaultViews">
  13.  
    <list>
  14.  
    <ref bean="mappingJacksonJsonView" />
  15.  
    <ref bean="marshallingView" />
  16.  
    </list>
  17.  
    </property>
  18.  
    <!-- 设置视图解析器 -->
  19.  
    <property name="viewResolvers">
  20.  
    <list>
  21.  
    <ref bean="defalutViewResolver" />
  22.  
    </list>
  23.  
    </property>
  24.  
    </bean>
  25.  
     
  26.  
    <bean id="defalutViewResolver"
  27.  
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  28.  
    <property name="prefix" value="/WEB-INF/view"></property>
  29.  
    <property name="suffix" value=".jsp"></property>
  30.  
    </bean>
  31.  
     
  32.  
    <!-- JSON视图 -->
  33.  
    <bean id="mappingJacksonJsonView"
  34.  
    class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"></bean>
  35.  
    <!-- XML视图 -->
  36.  
    <bean id="marshallingView"
  37.  
    class="org.springframework.web.servlet.view.xml.MarshallingView">
  38.  
    <property name="marshaller">
  39.  
    <bean class="org.springframework.oxm.xstream.XStreamMarshaller">
  40.  
    <property name="supportedClasses">
  41.  
    <list>
  42.  
    <value>java.util.Collection</value>
  43.  
    <value>org.laohu.modules.school.model.School</value>
  44.  
    <value>org.laohu.modules.school.model.Laboratory</value>
  45.  
    <value>org.laohu.modules.school.model.stuff.LabMgr</value>
  46.  
    </list>
  47.  
    </property>
  48.  
    <property name="aliases">
  49.  
    <map>
  50.  
    <entry value="org.laohu.modules.school.model.School" key="school"></entry>
  51.  
    <entry value="org.laohu.modules.school.model.Laboratory"
  52.  
    key="laboratory"></entry>
  53.  
    <entry value="org.laohu.modules.school.model.stuff.LabMgr"
  54.  
    key="labmgr"></entry>
  55.  
    </map>
  56.  
    </property>
  57.  
    </bean>
  58.  
    </property>
  59.  
    </bean>
  60.  
     
  61.  
    <bean id="contentNegotiationManager"
  62.  
    class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
  63.  
    <property name="mediaTypes">
  64.  
    <props>
  65.  
    <prop key="json">application/json</prop>
  66.  
    <prop key="xml">application/xml</prop>
  67.  
    </props>
  68.  
    </property>
  69.  
    </bean>
  70.  
     
  71.  
    </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;如下图:

为了方便大家理解,这里贴一下火狐的请求头和服务器的响应头:

  1.  
    GET /lab-order/school/.json HTTP/1.1
  2.  
    Host: localhost:8080
  3.  
    User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:19.0) Gecko/20100101 Firefox/19.0 FirePHP/0.7.1
  4.  
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  5.  
    Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
  6.  
    Accept-Encoding: gzip, deflate
  7.  
    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
  8.  
    x-insight: activate
  9.  
    Connection: keep-alive
  10.  
    Cache-Control: max-age=0
  1.  
    HTTP/1.1 200 OK
  2.  
    Server: Apache-Coyote/1.1
  3.  
    Pragma: no-cache
  4.  
    Cache-Control: no-cache, no-store, max-age=0
  5.  
    Expires: Thu, 01 Jan 1970 00:00:00 GMT
  6.  
    Content-Type: application/json;charset=UTF-8
  7.  
    Content-Language: zh-CN
  8.  
    Transfer-Encoding: chunked
  9.  
    Date: Thu, 04 Apr 2013 17:38:00 GMT

可以看到请求头是普通的text/html请求,但服务器相响应的是application/json的内容类型,表明内容协商工作正常,为了进一步测试内容协商管理器是否是按照这个基于后缀的映射内容类型,我们改变映射关系,修改mediaTypes:

  1.  
    <prop key="json">application/json</prop>
  2.  
    <prop key="xml">application/json</prop>

即将xml也映射到application/json上,再次使用.xml访问:

请求头:

  1.  
    GET /lab-order/school/.xml HTTP/1.1
  2.  
    Host: localhost:8080
  3.  
    User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:19.0) Gecko/20100101 Firefox/19.0 FirePHP/0.7.1
  4.  
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  5.  
    Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
  6.  
    Accept-Encoding: gzip, deflate
  7.  
    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
  8.  
    x-insight: activate
  9.  
    Connection: keep-alive

响应头:

  1.  
    HTTP/1.1 200 OK
  2.  
    Server: Apache-Coyote/1.1
  3.  
    Pragma: no-cache
  4.  
    Cache-Control: no-cache, no-store, max-age=0
  5.  
    Expires: Thu, 01 Jan 1970 00:00:00 GMT
  6.  
    Content-Type: application/json;charset=UTF-8
  7.  
    Content-Language: zh-CN
  8.  
    Transfer-Encoding: chunked
  9.  
    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配置多视图-内容协商原理的更多相关文章

  1. SpringMVC整合freeMarker实现页面静态化+SpringMVC配置多视图

    一.背景 1.什么是FreeMarker FreeMarker是一个模板引擎,一个基于模板生成文本输出的通用工具,使用纯Java编写 FreeMarker被设计用来生成HTML Web页面,特别是基于 ...

  2. springmvc 配置多视图(jsp,freemarker,HTML等)

    SpringMVC 的 Controller 可以返回各种各样的视图.比如 JSP, JSON, Velocity, FreeMarker, XML, PDF, Excel, 还有Html字符流 等等 ...

  3. SpringMvc配置自定义视图

    1.在dispatcherServlet-servlet.xml配置自定义视图 <!-- 配置视图 BeanNameViewResolver 解析器: 使用视图的名字来解析视图 --> & ...

  4. springmvc配置多视图 - tiles, velocity, freeMarker, jsp

    转自: http://www.cnblogs.com/shanheyongmu/p/5684595.html <!-- Velocity --> <bean id="vel ...

  5. springmvc 配置多视图,返回jsp,velocity,freeMarker,tiles(模板)等等

    springmvc-servlet.xml配置 <!-- Velocity --> <bean id="velocityViewResolver" class = ...

  6. SpringMVC源码分析6:SpringMVC的视图解析原理

    title: SpringMVC源码分析6:SpringMVC的视图解析原理 date: 2018-06-07 11:03:19 tags: - SpringMVC categories: - 后端 ...

  7. springMVC+ freemark多视图配置

    <!--通用视图解析器--> <bean id="viewResolverCommon" class="org.springframework.web. ...

  8. SpringMVC 返回 html 视图页面,SpringMVC与Servlet,Servlet重定向与转发

    1. SpringMVC与Servlet的关系 SpringMVC框架是建立在Servlet之上的,提供各种功能,各种封装,各种方便的同时,它一点儿也没有限制Servlet,我们完全可以在Spring ...

  9. SpringMVC配置版到注解版

    什么是springmvc? 1.1.什么是MVC MVC是模型(Model).视图(View).控制器(Controller)的简写,是一种软件设计规范. 是将业务逻辑.数据.显示分离的方法来组织代码 ...

随机推荐

  1. unable to locate nuget.exe

    今日使用vs 从github fork 一份代码到本地之后,提示项目 unable to locate nuget.exe. 原因:代码托管时未提交 nuget.exe 或其他原因丢失 解决方法:在解 ...

  2. 年会抽奖 抽奖系统 抽奖软件 C# Winform

    年会抽奖软件: Q.Q 358189777 C#.  数据库Access: 1.系统启动,自动全屏展示. 2.背景随心切换. 3.快捷键方便自如: F1:弹出设置界面 F2:查询人员名单.中奖名单 F ...

  3. angularJs - cynthia娆墨旧染-响应式文章发布系统

    (0)功能 a.添加新文章 b.修改已发布文章 c.搜索已经发布的文章 d.demo链接:   http://cynthiawupore.github.io/angularJS (1)界面 a.文章列 ...

  4. CSS样式—— 字体、元素的垂直水平居中

    1.CSS样式与HTML中标签属性的区别: 标签的属性是采用 属性名=“属性值” 表示的 CSS样式是采用名值对 属性名:属性值: 表示的 2.内联元素(行内元素)与块元素 (1)内联元素及其特点: ...

  5. LEDAPS1.3.0版本移植到windows平台----HuCal定标模块

    这个是2012年左右放在百度空间的,谁知百度空间关闭...转移到博客园. 最近项目用到3.1.2版本的LEDAPS,新版本的使用情况会在后续文章中慢慢丰富. HuCal是将LEDAPS项目中的TM/E ...

  6. Java虚拟机(五)Java的四种引用级别

    1.前言 HotSpot采取了可达性分析算法用来判断对象是否被能被GC,无论是引用计算法还是可达性分析算法都是判断对象是否存在引用来判断对象是否存活.如果reference类型的数据中存储的数值代表的 ...

  7. leetcode-13罗马字符转整数

    leetcode-13罗马字符转整数 算法:转换的规律是先逐字符按照对应的阿拉伯数字累加,然后对于特殊的(I.X.C出现在左侧)要处理.处理方法:出现特殊字符组合减去双倍的左侧字符(在开始的处理中已经 ...

  8. 深圳市共创力推出《以用户为中心的设计UCD方法与实战》课程!

    以用户为中心的设计(UCD)方法与实战 课程特色 现在以市场为中心.科技为基础.体验为卖点的商业社会里,用户体验是赢得用户青睐的关键特性.苹果.google.腾讯等顶级企业的成功充分说明了这一点.如何 ...

  9. Markdown:常用语法

    1.标题 说明:一共可以6级标题,几级几个# 一级标题 #一级标题 2.代码 用前后扩上 Hello World! 3.代码块 用前后扩上 Hello World! 4.加粗 加粗了 **加粗了** ...

  10. win7文件搜索技巧

    重要说明   (1)搜索的字符串是大小写不敏感的 (2)字符串带双引号与不带双引号是有区别的 如:hello,搜索包含hello单词开头的文件或目录,名为“aa_HELLOcc...”.“cc-Hel ...