首先,我们回顾下,在基于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.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/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个不同的类:
- org.springframework.web.servlet.view.json.MappingJacksonJsonView
- 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.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/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.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/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;
}
}