Spring Web MVC框架(九) XML和JSON视图与内容协商

简介: Spring MVC不仅支持各种网页视图,也支持JSON、XML这样的视图。而且还支持内容协商,也就是根据传入的扩展名、请求参数、Accept Header等信息决定具体采用哪种视图。

Spring MVC不仅支持各种网页视图,也支持JSON、XML这样的视图。而且还支持内容协商,也就是根据传入的扩展名、请求参数、Accept Header等信息决定具体采用哪种视图。我们先来看看Spring的JSON和XML视图。

手动实现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-drivencontent-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头来判断媒体类型。

相关文章
|
1月前
|
存储 JSON 安全
如何使用 JSON Web Tokens 进行身份验证?
总的来说,JWT 是一种强大而灵活的身份验证方式,通过正确使用和管理,可以为应用提供可靠的身份验证机制,同时提高系统的可扩展性和安全性。在实际应用中,需要根据具体的需求和场景,合理设计和实施 JWT 身份验证方案。
114 63
|
4月前
|
XML JSON 前端开发
【Web前端揭秘】XML与JSON:数据界的双雄对决,你的选择将如何改写Web世界的未来?
【8月更文挑战第26天】本文深入探讨了XML和JSON这两种广泛使用的数据交换格式在Web前端开发中的应用。XML采用自定义标签描述数据结构,适用于复杂层次数据的表示,而JSON则以键值对形式呈现数据,更为轻量且易解析。通过对两种格式的示例代码、结构特点及应用场景的分析,本文旨在帮助读者更好地理解它们的差异,并根据实际需求选择最合适的数据交换格式。
74 1
|
3月前
|
XML Java 应用服务中间件
springMVC01,springMVC的执行流程【第一个springMVC例子(XML配置版本):HelloWorld】
通过一个HelloWorld实例,介绍了SpringMVC的基本概念、执行流程,并详细讲解了如何创建和配置第一个SpringMVC项目(基于XML)。
springMVC01,springMVC的执行流程【第一个springMVC例子(XML配置版本):HelloWorld】
|
2月前
|
存储 JSON 前端开发
JSON与现代Web开发:数据交互的最佳选择
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也便于机器解析和生成。它以文本格式存储数据,常用于Web应用中的数据传输,尤其是在客户端和服务器之间。
82 0
|
2月前
|
Java 应用服务中间件 Spring
【终极解决方案】Could not open ServletContext resource [/WEB-INF/dispatcher-servlet.xml]
【终极解决方案】Could not open ServletContext resource [/WEB-INF/dispatcher-servlet.xml]
43 0
|
2月前
|
前端开发 Java
【案例+源码】详解MVC框架模式及其应用
【案例+源码】详解MVC框架模式及其应用
167 0
|
2月前
|
XML JSON 前端开发
C#使用HttpClient四种请求数据格式:json、表单数据、文件上传、xml格式
C#使用HttpClient四种请求数据格式:json、表单数据、文件上传、xml格式
574 0
|
4月前
|
XML JSON Java
使用IDEA+Maven搭建整合一个Struts2+Spring4+Hibernate4项目,混合使用传统Xml与@注解,返回JSP视图或JSON数据,快来给你的SSH老项目翻新一下吧
本文介绍了如何使用IntelliJ IDEA和Maven搭建一个整合了Struts2、Spring4、Hibernate4的J2EE项目,并配置了项目目录结构、web.xml、welcome.jsp以及多个JSP页面,用于刷新和学习传统的SSH框架。
131 0
使用IDEA+Maven搭建整合一个Struts2+Spring4+Hibernate4项目,混合使用传统Xml与@注解,返回JSP视图或JSON数据,快来给你的SSH老项目翻新一下吧
|
4月前
|
Java Spring 容器
彻底改变你的编程人生!揭秘 Spring 框架依赖注入的神奇魔力,让你的代码瞬间焕然一新!
【8月更文挑战第31天】本文介绍 Spring 框架中的依赖注入(DI),一种降低代码耦合度的设计模式。通过 Spring 的 DI 容器,开发者可专注业务逻辑而非依赖管理。文中详细解释了 DI 的基本概念及其实现方式,如构造器注入、字段注入与 setter 方法注入,并提供示例说明如何在实际项目中应用这些技术。通过 Spring 的 @Configuration 和 @Bean 注解,可轻松定义与管理应用中的组件及其依赖关系,实现更简洁、易维护的代码结构。
67 0
|
4月前
|
设计模式 存储 前端开发
MVC 框架的主要问题是什么?
【8月更文挑战第30天】
99 0