分享

Spring3:如何配置ContentNegotiatingViewResolver返回JSON或者XML格式数据? | 学步园

 瑶疏影 2015-10-08

首先,我们回顾下,在基于Spring的RESTful的项目中如果你使用这种形式的URL:

http://localhost:8888/myapp/service/xxx/{id}

那么一般情况下,你会被导向到一个HTML页面。如果你想让它返回一个JSON格式或者XML格式的数据,那么你不得不在前台做一番格式转换的处理。

现在,你只需要在你的spring-servlet.xml文件里面配置一下就可以了。

先看配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www./schema/beans" xmlns:xsi="http://www./2001/XMLSchema-instance"
    xmlns:p="http://www./schema/p" xmlns:mvc="http://www./schema/mvc"
    xmlns:context="http://www./schema/context"
    xsi:schemaLocation="

http://www./schema/beans


http://www./schema/beans/spring-beans-3.0.xsd


http://www./schema/context


http://www./schema/context/spring-context-3.0.xsd


http://www./schema/mvc

        http://www./schema/mvc/spring-mvc-3.0.xsd">

    <context:component-scan base-package="com.homeland.myapp.controller" />
    <mvc:annotation-driven />

    <mvc:resources location="/images/" mapping="/images/**" />
    <mvc:resources location="/js/" mapping="/js/**" />
    <mvc:resources location="/css/" mapping="/css/**" />

    <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="order" value="1" />
        <property name="favorParameter" value="false" />
        <property name="ignoreAcceptHeader" value="true" />

        <property name="defaultContentType" value="text/html" />
        <property name="mediaTypes">
            <map>
                <entry key="json" value="application/json" />
                <entry key="xml" value="application/xml" />
            </map>
        </property>
        <property name="viewResolvers">
            <list>
                <bean
                    class="org.springframework.web.servlet.view.BeanNameViewResolver" />
                <bean
                    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                    <property name="prefix" value="/page/" />
                    <property name="suffix" value=".jsp" />
                </bean>
            </list>
        </property>
        <property name="defaultViews">
            <list>
                <bean id="jsonView"
                    class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
                <bean id="xmlView"
                    class="org.springframework.web.servlet.view.xml.MarshallingView">
                    <constructor-arg>
                        <bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
                            <property name="classesToBeBound">
                                <list>
                                    <value>com.homeland.myapp.entity.Employee</value>
                                </list>
                            </property>
                        </bean>
                    </constructor-arg>
                </bean>
            </list>
        </property>
    </bean>

</beans>

21行:viewResolver的顺序

22行:是一个格式化的开关,类似http://localhost:8888/myapp/service/{id}?format=json这种

23行:忽略请求头中的Accept

25行:默认的数据返回格式

26行~31行:配置媒体类型与扩展名的映射关系,也即将Content-Type=application/json的内容映射到http://localhost:8888/myapp/service/{id}.json这种格式

32行~42行:配置你的ViewResolver

42行~60行:配置数据格式的转换器

数据格式的转换器部分,需要说的是,在spring的包里面有2个不同的类:

  1. org.springframework.web.servlet.view.json.MappingJacksonJsonView
  2. org.springframework.web.servlet.view.json.MappingJackson2JsonView

这两个类对应到pom.xml文件是不同的包,先说第一个:

用第一个类你的JSON解析器是这样的:

<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-core-asl</artifactId>
    <version>1.9.13</version>
</dependency>
<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-mapper-asl</artifactId>
    <version>1.9.13</version>
</dependency>
<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-jaxrs</artifactId>
    <version>1.9.13</version>
</dependency>

用第二个类你的JSON解析器是这样的:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.2.2</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.2.2</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.2.2</version>
</dependency>

此外,我配置的XML解析器是:

org.springframework.oxm.jaxb.Jaxb2Marshaller

如果你使用JAXB来绑定,那么你的entity类的annotation是这样的:

package com.homeland.myapp.entity;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@Entity
@Table(name = "employee")
@XmlRootElement(name = "employee")
public class Employee implements Serializable {

	private static final long serialVersionUID = -8869011840496785130L;

	@Id
	@SequenceGenerator(name = "seq_employee_id", 
		allocationSize = 1, initialValue = 1, 
		sequenceName = "seq_employee_id")
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_employee_id")
	private int id;
	@Column(name = "first_name", length = 60, nullable = false)
	private String firstname;
	@Column(name = "last_name", length = 60, nullable = false)
	private String lastname;
	@Column(name = "full_name", length = 120, nullable = false)
	private String fullname;
	@Column(name = "age", length = 3, nullable = false)
	private int age;
	@Column(name = "sex", length = 1, nullable = false)
	private int sex;
	@Column(name = "email", length = 255, nullable = false)
	private String email;
	@Column(name = "cell_phone", length = 15, nullable = false)
	private String cellphone;
	@Column(name = "department_id", nullable = false)
	private int  departmentId;
	@Column(name = "role_id", nullable = false)
	private int roleId;
	
	public Employee() {}

	public int getId() {
		return id;
	}

	@XmlElement
	public void setId(int id) {
		this.id = id;
	}

	public String getFirstname() {
		return firstname;
	}

	@XmlElement
	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}

	public String getLastname() {
		return lastname;
	}

	@XmlElement
	public void setLastname(String lastname) {
		this.lastname = lastname;
	}

	public String getFullname() {
		return fullname;
	}

	@XmlElement
	public void setFullname(String fullname) {
		this.fullname = fullname;
	}

	public int getAge() {
		return age;
	}

	@XmlElement
	public void setAge(int age) {
		this.age = age;
	}

	public int isSex() {
		return sex;
	}

	@XmlElement
	public void setSex(int sex) {
		this.sex = sex;
	}
	
	public int getSex() {
		return sex;
	}

	public String getEmail() {
		return email;
	}

	@XmlElement
	public void setEmail(String email) {
		this.email = email;
	}

	public String getCellphone() {
		return cellphone;
	}

	@XmlElement
	public void setCellphone(String cellphone) {
		this.cellphone = cellphone;
	}

	public int getDepartmentId() {
		return departmentId;
	}

	@XmlElement
	public void setDepartmentId(int departmentId) {
		this.departmentId = departmentId;
	}

	public int getRoleId() {
		return roleId;
	}

	@XmlElement
	public void setRoleId(int roleId) {
		this.roleId = roleId;
	}

}

这里必须要说一下,如果你把@XmlElement放在property上面,会报错。这个很莫名其妙。根据错误信息,它判定有两个同名的属性,我猜测是因为在扫描文件的时候把方法也扫了。不知道为啥。所以,就把@XmlElement放在了setter()方法上。

但是,我们知道还有另外一个很好用的就是XStream解析器。

那么,如何使用XStream的话,配置文件要如何改呢?

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www./schema/beans" xmlns:xsi="http://www./2001/XMLSchema-instance"
    xmlns:p="http://www./schema/p" xmlns:mvc="http://www./schema/mvc"
    xmlns:context="http://www./schema/context"
    xsi:schemaLocation="

http://www./schema/beans


http://www./schema/beans/spring-beans-3.0.xsd


http://www./schema/context


http://www./schema/context/spring-context-3.0.xsd


http://www./schema/mvc

        http://www./schema/mvc/spring-mvc-3.0.xsd">

    <context:component-scan base-package="com.homeland.myapp.controller" />
    <mvc:annotation-driven />

    <mvc:resources location="/images/" mapping="/images/**" />
    <mvc:resources location="/js/" mapping="/js/**" />
    <mvc:resources location="/css/" mapping="/css/**" />

    <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="order" value="1" />
        <property name="favorParameter" value="false" />
        <property name="ignoreAcceptHeader" value="true" />

        <property name="defaultContentType" value="text/html" />
        <property name="mediaTypes">
            <map>
                <entry key="json" value="application/json" />
                <entry key="xml" value="application/xml" />
            </map>
        </property>
        <property name="viewResolvers">
            <list>
                <bean
                    class="org.springframework.web.servlet.view.BeanNameViewResolver" />
                <bean
                    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                    <property name="prefix" value="/page/" />
                    <property name="suffix" value=".jsp" />
                </bean>
            </list>
        </property>
        <property name="defaultViews">
            <list>
                <bean id="jsonView" class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
                <bean id="xmlView" class="org.springframework.web.servlet.view.xml.MarshallingView">
                    <property name="marshaller">
                        <bean class="org.springframework.oxm.xstream.XStreamMarshaller"/>
                    </property>
                </bean>
            </list>
        </property>
    </bean>

</beans>

相对应的entity类的annotation也要改:

package com.homeland.myapp.entity;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;

@Entity
@Table(name = "employee")
@XStreamAlias("employee")
public class Employee implements Serializable {

	private static final long serialVersionUID = -8869011840496785130L;

	@Id
	@SequenceGenerator(name = "seq_employee_id", 
		allocationSize = 1, initialValue = 1, 
		sequenceName = "seq_employee_id")
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_employee_id")
	@XStreamAsAttribute
	@XStreamAlias("id")
	private int id;
	@Column(name = "first_name", length = 60, nullable = false)
	@XStreamAsAttribute
	@XStreamAlias("first_name")
	private String firstname;
	@Column(name = "last_name", length = 60, nullable = false)
	@XStreamAsAttribute
	@XStreamAlias("last_name")
	private String lastname;
	@Column(name = "full_name", length = 120, nullable = false)
	@XStreamAsAttribute
	@XStreamAlias("full_name")
	private String fullname;
	@Column(name = "age", length = 3, nullable = false)
	@XStreamAsAttribute
	@XStreamAlias("age")
	private int age;
	@Column(name = "sex", length = 1, nullable = false)
	@XStreamAsAttribute
	@XStreamAlias("sex")
	private int sex;
	@Column(name = "email", length = 255, nullable = false)
	@XStreamAsAttribute
	@XStreamAlias("email")
	private String email;
	@Column(name = "cell_phone", length = 15, nullable = false)
	@XStreamAsAttribute
	@XStreamAlias("cell_phone")
	private String cellphone;
	@Column(name = "department_id", nullable = false)
	@XStreamAsAttribute
	@XStreamAlias("department_id")
	private int  departmentId;
	@Column(name = "role_id", nullable = false)
	@XStreamAsAttribute
	@XStreamAlias("role_id")
	private int roleId;
	
	public Employee() {}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getFirstname() {
		return firstname;
	}

	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}

	public String getLastname() {
		return lastname;
	}

	public void setLastname(String lastname) {
		this.lastname = lastname;
	}

	public String getFullname() {
		return fullname;
	}

	public void setFullname(String fullname) {
		this.fullname = fullname;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public int isSex() {
		return sex;
	}

	public void setSex(int sex) {
		this.sex = sex;
	}
	
	public int getSex() {
		return sex;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getCellphone() {
		return cellphone;
	}

	public void setCellphone(String cellphone) {
		this.cellphone = cellphone;
	}

	public int getDepartmentId() {
		return departmentId;
	}

	public void setDepartmentId(int departmentId) {
		this.departmentId = departmentId;
	}

	public int getRoleId() {
		return roleId;
	}

	public void setRoleId(int roleId) {
		this.roleId = roleId;
	}

}

不过,用JAXB以及XStream其返回的数据样式也不完全一样。大家可以比较一下。

在使用Spring3自带的XStreamMarshaller的时候,你会发现如果你用了下划线("_")来链接属性名中的两个或多个单词的话,在最终的xml返回值中出现了双下划线("__")。

目前还不知道怎么解决。网上搜索了下,貌似要换marshaller了。当然,你也可以不用。以下代码告诉你,用好@XStreamAliases会让返回的XML好看一些:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www./schema/beans" xmlns:xsi="http://www./2001/XMLSchema-instance"
    xmlns:p="http://www./schema/p" xmlns:mvc="http://www./schema/mvc"
    xmlns:context="http://www./schema/context"
    xsi:schemaLocation="

http://www./schema/beans


http://www./schema/beans/spring-beans-3.0.xsd


http://www./schema/context


http://www./schema/context/spring-context-3.0.xsd


http://www./schema/mvc

        http://www./schema/mvc/spring-mvc-3.0.xsd">

    <context:component-scan base-package="com.homeland.myapp.controller" />
    <mvc:annotation-driven />

    <mvc:resources location="/images/" mapping="/images/**" />
    <mvc:resources location="/js/" mapping="/js/**" />
    <mvc:resources location="/css/" mapping="/css/**" />

    <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="order" value="1" />
        <property name="favorParameter" value="false" />
        <property name="ignoreAcceptHeader" value="true" />

        <property name="defaultContentType" value="text/html" />
        <property name="mediaTypes">
            <map>
                <entry key="json" value="application/json" />
                <entry key="xml" value="application/xml" />
            </map>
        </property>
        <property name="viewResolvers">
            <list>
                <bean
                    class="org.springframework.web.servlet.view.BeanNameViewResolver" />
                <bean
                    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                    <property name="prefix" value="/page/" />
                    <property name="suffix" value=".jsp" />
                </bean>
            </list>
        </property>
        <property name="defaultViews">
            <list>
                <bean id="jsonView" class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
                <bean id="xmlView" class="org.springframework.web.servlet.view.xml.MarshallingView">
                    <property name="marshaller">
                        <bean class="org.springframework.oxm.xstream.XStreamMarshaller">
                            <property name="autodetectAnnotations" value="true" />
                            <!-- <property name="aliases">
                                <map>
                                    <entry key="employee" value="com.homeland.myapp.entity.Employee" />
                                </map>
                            </property>
                            <property name="fieldAliases">
                                <map>
                                    <entry key="com.homeland.myapp.entity.Employee.firstname" value="first_name" />
                                </map>
                            </property> -->
                        </bean>
                    </property>
                </bean>
            </list>
        </property>
    </bean>

</beans>

在上面代码中注释部分相当于加了annotation的entity类:

package com.homeland.myapp.entity;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

import com.thoughtworks.xstream.annotations.XStreamAlias;

@Entity
@Table(name = "employee")
@XStreamAlias("employee")
public class Employee implements Serializable {

	private static final long serialVersionUID = -8869011840496785130L;

	@Id
	@SequenceGenerator(name = "seq_employee_id", 
		allocationSize = 1, initialValue = 1, 
		sequenceName = "seq_employee_id")
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_employee_id")
	@XStreamAlias("id")
	private int id;
	@Column(name = "first_name", length = 60, nullable = false)
	@XStreamAlias("first-name")
	private String firstname;
	@Column(name = "last_name", length = 60, nullable = false)
	@XStreamAlias("last-name")
	private String lastname;
	@Column(name = "full_name", length = 120, nullable = false)
	@XStreamAlias("full-name")
	private String fullname;
	@Column(name = "age", length = 3, nullable = false)
	@XStreamAlias("age")
	private int age;
	@Column(name = "sex", length = 1, nullable = false)
	@XStreamAlias("sex")
	private int sex;
	@Column(name = "email", length = 255, nullable = false)
	@XStreamAlias("email")
	private String email;
	@Column(name = "cell_phone", length = 15, nullable = false)
	@XStreamAlias("cell-phone")
	private String cellphone;
	@Column(name = "department_id", nullable = false)
	@XStreamAlias("department-id")
	private int  departmentId;
	@Column(name = "role_id", nullable = false)
	@XStreamAlias("role-id")
	private int roleId;
	
	public Employee() {}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getFirstname() {
		return firstname;
	}

	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}

	public String getLastname() {
		return lastname;
	}

	public void setLastname(String lastname) {
		this.lastname = lastname;
	}

	public String getFullname() {
		return fullname;
	}

	public void setFullname(String fullname) {
		this.fullname = fullname;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public int isSex() {
		return sex;
	}

	public void setSex(int sex) {
		this.sex = sex;
	}
	
	public int getSex() {
		return sex;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getCellphone() {
		return cellphone;
	}

	public void setCellphone(String cellphone) {
		this.cellphone = cellphone;
	}

	public int getDepartmentId() {
		return departmentId;
	}

	public void setDepartmentId(int departmentId) {
		this.departmentId = departmentId;
	}

	public int getRoleId() {
		return roleId;
	}

	public void setRoleId(int roleId) {
		this.roleId = roleId;
	}

}

双下划线神马的,换成短线(“-")吧!偷笑

P.S:

JSON格式的返回结果:

{"employee":{
             "id":14,
             "firstname":"Jackson",
             "lastname":"Tom",
             "fullname":"tom.jackson",
             "age":33,
             "sex":1,
             "email":"tom.jackson@xxx.com",
             "cellphone":"86186xxxxxxx8",
             "departmentId":11,
             "roleId":11
            }
}

XML格式的返回结果:

相应的controller代码:

package com.homeland.myapp.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.homeland.myapp.entity.Employee;
import com.homeland.myapp.service.EmployeeService;
import com.thoughtworks.xstream.XStream;

@Controller
public class EmployeeController {
	
	@Autowired
	private EmployeeService employeeService;

	@RequestMapping(method = RequestMethod.GET, value = "/employee/{id}")
	public Employee getEmployee(@PathVariable String id) {
		Employee e = employeeService.findById(Integer.parseInt(id));
		return e;
	}
	
	@RequestMapping(method = RequestMethod.GET, value = "/employees")
	public List<Employee> getAllEmployee() {
		List<Employee> employees = employeeService.findAll();
		return employees;
	}
}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多