Spring Web MVC框架(九) XML和JSON视图与内容协商
2017-02-14 02:46
507 查看
Spring MVC不仅支持各种网页视图,也支持JSON、XML这样的视图。而且还支持内容协商,也就是根据传入的扩展名、请求参数、Accept Header等信息决定具体采用哪种视图。我们先来看看Spring的JSON和XML视图。
常用的JSON序列化库有Jackson、谷歌的Gson和阿里的FastJason等,可以根据需求选择合适的。Java有很多XML序列化库,也可以直接使用Spring封装的OXM功能(详见Spring文档)。
如果Spring发现类路径上有Jackson库存在,就会自动注册一个
我们如果使用相应的URL来访问,会得到类似下面的输出。
当然也可以对生成的Json进行定制,请参阅Jackson文档。
首先添加FastJson的依赖。
由于Spring没有默认的FastJson支持,所以我们没办法向Jackson那样让Spring自动注册。不过阿里针对Spring框架也编写了相应的支持类。我们只要向Spring注册一个
另外,新版本的FastJson的消息转换器没有指定Content-Type,所以如果我们直接使用的话会收到text/html类型的消息。解决办法就是在消息转换器中设置Content-Type。这样设置以后, 我们直接返回对象的话,FastJson就会将对象转换为JSON字符串了。
和前面的Jackson支持一样,Spring会检查类路径是否包含JAXB的实现。如果包含的话会自动注册一个
首先先来添加XStream的依赖项。
Spring没有命名空间来简化XStream配置。所以我们只能手动声明一个XStream实例。
然后将它配置到消息转换器中。
这样,当我们的方法返回一组User对象时,就可以得到正确的XML输出了。
下面是一个配置内容协定视图解析器的例子。由于我们使用@ResponseBody直接向响应输出结果并通过消息转换器转换。所以我们这里其实不需要配置内容协定视图解析器。
内容协商管理器可定义的东西有很多。这里简单说明一下:
mediaType。指定可接受的媒体类型,需要一些键值对,值为实际的媒体类型。
useJaf。指定是否使用JavaBeans(TM) Activation Framework。这个类库可以自动检测扩展名为实际媒体类型。如果不指定我们就可以使用自己的设置。
ignoreAcceptHeader。指定是否忽略Accept头的类型。
favorPathExtension。指定是否使用路径扩展名判断媒体类型。
favorParameter。指定是否使用参数判断媒体类型。
parameterName。指定参数的名称。
这些属性通过合理配置,就可以得到我们想要的功能了。如果指定了路径扩展名,那么访问
手动实现JSON或XML视图
这是最笨的办法,不过描述起来很简单。我们只要按照自己习惯的方式使用自己熟悉的类库,在控制器中手动将要转换的对象转化成JSON或XML字符串,然后返回给@ResponseBody方法即可。这种方法的缺点是Spring不知道我们具体返回的类型,所以我们需要自己设置响应的Contet-Type和编码。常用的JSON序列化库有Jackson、谷歌的Gson和阿里的FastJason等,可以根据需求选择合适的。Java有很多XML序列化库,也可以直接使用Spring封装的OXM功能(详见Spring文档)。
Spring的多视图支持
除了手动进行对象的转换之外,我们还可以利用Spring提供的多视图功能。这也是本文主要讲的内容。Spring的JSON视图支持
Jackson
Spring提供了对Jackson序列化库的支持,如果使用Gradle的话,在项目中添加如下一行,Gradle会自动引入Jackson和其依赖的几个包。compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.8.6'
如果Spring发现类路径上有Jackson库存在,就会自动注册一个
MappingJackson2HttpMessageConverter。这意味着我们直接在@ResponseBody方法中返回要转换的对象即可,Spring会使用
MappingJackson2HttpMessageConverter来转换。
@RequestMapping("/users") @ResponseBody public List<User> users() { return users; }
我们如果使用相应的URL来访问,会得到类似下面的输出。
[{"name":"yitian","age":24,"gender":"男"},{"name":"zhang3","age":23,"gender":"男"},{"name":"li4","age":24,"gender":"男"},{"name":"meimei","age":22,"gender":"女"}]
当然也可以对生成的Json进行定制,请参阅Jackson文档。
FastJson
另外我又研究了一下,Jackson类库默认不能进行JDK8新日期时间API的转换,需要额外引入几个扩展,配置起来略麻烦。而且现在阿里FastJson的速度应该是最快的。所以我们也来学习一下FastJson。首先添加FastJson的依赖。
compile group: 'com.alibaba', name: 'fastjson', version: '1.2.24'
由于Spring没有默认的FastJson支持,所以我们没办法向Jackson那样让Spring自动注册。不过阿里针对Spring框架也编写了相应的支持类。我们只要向Spring注册一个
FastJsonHttpMessageConverter4即可。如果你使用Spring 4.2以下,那么使用
FastJsonHttpMessageConverter类;如果使用Spring 4.2以上,使用带4的那个。
<mvc:annotation-driven> <mvc:message-converters> <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4"> <property name="supportedMediaTypes"> <list> <value>application/json</value> </list> </property> </bean> </mvc:message-converters>
另外,新版本的FastJson的消息转换器没有指定Content-Type,所以如果我们直接使用的话会收到text/html类型的消息。解决办法就是在消息转换器中设置Content-Type。这样设置以后, 我们直接返回对象的话,FastJson就会将对象转换为JSON字符串了。
Spring的XML视图支持
JAXB
Spring提供了OXM,可以将Java对象映射为XML文件。这里我们先说一说XML序列化库JAXB。自JDK6开始,自带了JAXB的实现。因此我们不需要额外引入类库了。JAXB的缺点是当我们使用注解配置OXM的时候必须注解每个要映射的类。因此如果我们需要返回一个用户集合List<User>,我们就必须定义一个
Users类,它包含一个
List<User>实例。这里用到的User类也进行了相应字段的注解。
@XmlRootElement public class Users { private List<User> users; public List<User> getUsers() { return users; } @XmlElement public void setUsers(List<User> users) { this.users = users; } }
和前面的Jackson支持一样,Spring会检查类路径是否包含JAXB的实现。如果包含的话会自动注册一个
Jaxb2RootElementHttpMessageConverter,所以当我们在
@ResponseBody方法中返回相应的对象。Spring就会自动将它转换为XML。
@RequestMapping("/users") @ResponseBody public Users users() { Users us = new Users(); us.setUsers(users); return us; }
Jackson XML
另外如果Spring检测到类路径上存在jackson-dataformat-xml,就会自动注册一个
MappingJackson2XmlHttpMessageConverter。这样返回的对象就会使用Jackson的XML映射功能转换为XML。
XStream
XStream是一个优秀的XML序列化框架,默认情况下无需配置即可使用,而且要配置也很简单,添加一些aliases即可。缺点就是可以反序列化匿名对象,可能有安全问题,所以我们一般需要使用
supportedClasses控制它可以反序列化的类。
首先先来添加XStream的依赖项。
compile group: 'com.thoughtworks.xstream', name: 'xstream', version: '1.4.9'
Spring没有命名空间来简化XStream配置。所以我们只能手动声明一个XStream实例。
<bean id="xStreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller"> <property name="supportedClasses"> <list> <value>yitian.learn.entity.User</value> <value>java.util.List</value> </list> </property> <property name="aliases"> <props> <prop key="users">java.util.List</prop> <prop key="user">yitian.learn.entity.User</prop> </props> </property> </bean>
然后将它配置到消息转换器中。
<mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter"> <property name="marshaller" ref="xStreamMarshaller"/> <property name="unmarshaller" ref="xStreamMarshaller"/> </bean> </mvc:message-converters>
这样,当我们的方法返回一组User对象时,就可以得到正确的XML输出了。
<users> <user> <name>yitian</name> <age>24</age> <gender>男</gender> </user> ... </users>
内容协作
所谓内容写作,指的是Spring可以根据请求的扩展名、查询参数或者Accept头等信息,决定使用哪种视图展示数据。常用的做法就是为一系列数据指定JSON、XML等不同的数据展示方式。在前面讨论了这么多视图的实现方式之后。我们终于可以来研究一下内容协作了。默认情况下的内容协定
首先来看看这个方法。假如我们引入了Jackson和Jackson XML的依赖,那么这个方法到底会返回什么样的数据呢?Spring文档 内容协作这一节已经说了,Spring默认会注册json,
xml,
rss,
atom这四种类型的内容协定,如果相应的依赖存在的话。Spring会先查找文件扩展名,根据扩展名来返回相应的视图;如果扩展名不存在,就会根据Accept头来判断。所以如果我们访问
/users.json,就会返回JSON视图,如果访问
/users.xml,就会返回XML视图。
@RequestMapping("/users") @ResponseBody public List<User> users() { return users; }
自定义内容协定
上面的Jackson和Jackson XML都是Spring默认自动注册的转换器。如果我们使用其他的转换器,或者希望自己指定内容协定的策略,就需要自定义内容协定了。内容协定需要两个类来支持:内容协定视图解析器用来指定要使用的视图;内容协定管理器用于配置内容协定的策略。内容协定视图解析器
内容协定视图解析器需要配置一个默认视图和一系列视图解析器。它会根据媒体类型(也就是Content-Type)来查找合适的视图解析器。如果没有视图解析器满足需要的媒体类型,就会使用默认视图来渲染。下面是一个配置内容协定视图解析器的例子。由于我们使用@ResponseBody直接向响应输出结果并通过消息转换器转换。所以我们这里其实不需要配置内容协定视图解析器。
<bean id="contentNegotiatingViewResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> <property name="contentNegotiationManager" ref="contentNegotiationManager"/> <property name="defaultViews"> <list> <bean id="jsonView" class="com.alibaba.fastjson.support.spring.FastJsonJsonView"/> <bean id="xmlView" class="org.springframework.web.servlet.view.xml.MarshallingView"> <property name="marshaller" ref="xStreamMarshaller"/> </bean> </list> </property> <property name="viewResolvers"> <list> <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> </list> </property> </bean>
内容协商管理器
内容协商管理器用于指定内容协商的策略。我们在Spring中声明一个ContentNegotiationManagerFactoryBean,然后设置它的属性即可。最后将它的id传给
mvc:annotation-driven的
content-negotiation-manager属性即可。
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"> <bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean"> <property name="mediaTypes"> <map> <entry key="json" value="application/json"/> <entry key="xml" value="application/xml"/> </map> </property> <property name="useJaf" value="true"/> <property name="ignoreAcceptHeader" value="false"/> <property name="favorPathExtension" value="true"/> <property name="favorParameter" value="false"/> <property name="parameterName" value="type"/> </bean>
内容协商管理器可定义的东西有很多。这里简单说明一下:
mediaType。指定可接受的媒体类型,需要一些键值对,值为实际的媒体类型。
useJaf。指定是否使用JavaBeans(TM) Activation Framework。这个类库可以自动检测扩展名为实际媒体类型。如果不指定我们就可以使用自己的设置。
ignoreAcceptHeader。指定是否忽略Accept头的类型。
favorPathExtension。指定是否使用路径扩展名判断媒体类型。
favorParameter。指定是否使用参数判断媒体类型。
parameterName。指定参数的名称。
这些属性通过合理配置,就可以得到我们想要的功能了。如果指定了路径扩展名,那么访问
/users.xml会返回XML,访问
/users.json会返回JSON;如果指定了Accept头,那么当Accept头包含
application/json会返回JSON,XML也是类似;如果指定了请求参数,那么当访问
/users?type=xml时返回XML,JSON类似。由于一般内容协定常用于Rest程序,所以最常用的还是通过路径扩展名和Accept头来判断媒体类型。
相关文章推荐
- ContentNegotiatingViewResolver spring REST中的内容协商(同一资源,多种展现:xml,json,html)
- ContentNegotiatingViewResolver spring REST中的内容协商(同一资源,多种展现:xml,json,html)
- spring REST中的内容协商(同一资源,多种展现:xml,json,html)
- Spring-MVC框架下对web.xml文件及spring_mvc.xml文件内容的释义资料整理
- spring REST中的内容协商(同一资源,多种展现:xml,json,html)
- Spring MVC 多视图协商配置(json、xml、freemarker)
- 关于使用spring需要在web.xml配置的内容的解析
- spring+springmvc+druid+oscache+mybatis整合web.xml 配置内容
- Spring 3.x MVC 入门3-1 -- 使用内容协商来实现多视图 示例
- Spring 4 MVC 视图解析器(XML JSON PDF等) 纯注解(带源码)【推荐】
- SSM(spring-springmvc-mybatis)整合开发xml配置文件内容springmvc-config.xml,application.xml,web.xml
- Spring MVC 3.1多视图协商配置(json、xml、freemarker)
- shh整合后web.xml、spring配置文件和struts.xml的内容
- 在Spring MVC Controller的同一个方法中,根据App还是WEB返回JSON或者HTML视图。
- Spring 3.x MVC 入门3 -- 使用内容协商来实现多视图
- shh整合后web.xml、spring配置文件和struts.xml的内容
- Spring3 MVC Restful 多请求类型(json,xml,k-v),多视图配置(Json,Xml,JSP,Freemarker,Volacity等)
- Spring 3.x MVC 入门3 -- 使用内容协商来实现多视图
- Spring MVC 3.1多视图协商配置(json、xml、freemarker)
- springMVC+Mybatis的maven-web项目的pom.xml文件内容