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天前
|
设计模式 存储 前端开发
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
|
7天前
|
JSON Java fastjson
Spring Boot 底层级探索系列 04 - Web 开发(2)
Spring Boot 底层级探索系列 04 - Web 开发(2)
15 0
|
13天前
|
前端开发 Java Spring
数据之桥:深入Spring MVC中传递数据给视图的实用指南
数据之桥:深入Spring MVC中传递数据给视图的实用指南
29 3
|
16天前
|
XML JSON JavaScript
Java中XML和JSON的比较与应用指南
本文对比了Java中XML和JSON的使用,XML以自我描述性和可扩展性著称,适合结构复杂、需验证的场景,但语法冗长。JSON结构简洁,适用于轻量级数据交换,但不支持命名空间。在Java中,处理XML可使用DOM、SAX解析器或XPath,而JSON可借助GSON、Jackson库。根据需求选择合适格式,注意安全、性能和可读性。
26 0
|
22天前
|
XML JSON JavaScript
使用JSON和XML:数据交换格式在Java Web开发中的应用
【4月更文挑战第3天】本文比较了JSON和XML在Java Web开发中的应用。JSON是一种轻量级、易读的数据交换格式,适合快速解析和节省空间,常用于API和Web服务。XML则提供更强的灵活性和数据描述能力,适合复杂数据结构。Java有Jackson和Gson等库处理JSON,JAXB和DOM/SAX处理XML。选择格式需根据应用场景和需求。
|
22天前
|
前端开发 安全 Java
使用Java Web框架:Spring MVC的全面指南
【4月更文挑战第3天】Spring MVC是Spring框架的一部分,用于构建高效、模块化的Web应用。它基于MVC模式,支持多种视图技术。核心概念包括DispatcherServlet(前端控制器)、HandlerMapping(请求映射)、Controller(处理请求)、ViewResolver(视图解析)和ModelAndView(模型和视图容器)。开发流程涉及配置DispatcherServlet、定义Controller、创建View、处理数据、绑定模型和异常处理。
使用Java Web框架:Spring MVC的全面指南
|
1月前
|
数据库
最全三大框架整合(使用映射)——struts.xml和web.xml配置
最全三大框架整合(使用映射)——数据库资源文件jdbc.properties
10 0
|
1月前
最全三大框架整合(使用映射)——applicationContext.xml里面的配置
最全三大框架整合(使用映射)——applicationContext.xml里面的配置
7 0
|
1月前
|
存储 设计模式 前端开发
请解释 Web 应用程序的 MVC(模型-视图-控制器)架构。
【2月更文挑战第26天】【2月更文挑战第89篇】请解释 Web 应用程序的 MVC(模型-视图-控制器)架构。
|
3天前
|
XML 数据格式
小米备份descript.xml文件
小米备份descript.xml文件
11 0