接受/返回 XML/JSON 请求和响应 - Spring MVC
Posted
技术标签:
【中文标题】接受/返回 XML/JSON 请求和响应 - Spring MVC【英文标题】:Accepting / returning XML/JSON request and response - Spring MVC 【发布时间】:2016-05-18 04:12:54 【问题描述】:我需要编写一个接受 XML/JSON 作为输入(POST 方法)和 XML/JSON 作为输出(基于输入格式)的休息服务。我尝试了以下方法来实现这一点,但没有帮助。Endpoint 方法同时接受 XML/JSON,但在响应时它总是根据 @RequestMapping -produces 中指定的顺序给出 JSON 或 XML。任何帮助将不胜感激.
我的端点方法:
@RequestMapping(value = "/getxmljson", method = RequestMethod.POST,produces="application/json","application/xml",
consumes="application/json", "application/xml")
public @ResponseBody Student processXMLJsonRequest(@RequestBody Student student)
throws Exception
System.out.println("*************Inside Controller");
return student;
POJO 类:Student.java
import java.io.Serializable;
import java.util.ArrayList;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
@XmlRootElement(name = "student")
@XmlType(propOrder = "id", "name", "graduationTime", "courses")
@JsonPropertyOrder("id", "name", "graduationTime", "courses")
public class Student implements Serializable
private static final long serialVersionUID = 1L;
private int id;
private String name;
private String graduationTime;
private ArrayList<Course> courses = new ArrayList<Course>();
@XmlElement
public int getId() return id;
@XmlElement
public String getName() return name;
@XmlElement
public String getGraduationTime() return graduationTime;
@XmlElement
public ArrayList<Course> getCourses() return courses;
public void setId(int value) this.id = value;
public void setName(String value) this.name = value;
public void setGraduationTime(String value) this.graduationTime = value;
public void setCourses(ArrayList<Course> value) this.courses = value;
@JsonIgnore
public String toString()
return this.name + " - "
+ graduationTime == null? "Unknown" : graduationTime.toString();
public Student()
public Student(int id, String name, String graduationTime)
this.id = id;
this.name = name;
this.graduationTime = graduationTime;
POJO 类:Course.java
import java.io.Serializable;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
@XmlRootElement(name = "course")
@XmlType(propOrder = "courseName", "score")
@JsonPropertyOrder("courseName", "score")
public class Course implements Serializable
private static final long serialVersionUID = 1L;
private String courseName;
private Integer score;
public @XmlElement String getCourseName() return courseName;
public @XmlElement Integer getScore() return score;
public void setCourseName(String value) courseName = value;
public void setScore(Integer value) score = value;
public Course()
public Course(String courseName, Integer score)
this.courseName = courseName;
this.score = score;
spring-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:sws="http://www.springframework.org/schema/web-services"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:oxm="http://www.springframework.org/schema/oxm"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/web-services
http://www.springframework.org/schema/web-services/web-services-2.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-4.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.5.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing
infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving
up static resources in the $webappRoot/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Configure to plugin JSON as request and response in method handler -->
<beans:bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<beans:property name="messageConverters">
<beans:list>
<beans:ref bean="jsonMessageConverter" />
<beans:ref bean="xmlMessageConverter" />
</beans:list>
</beans:property>
</beans:bean>
<!-- Configure bean to convert JSON to POJO and vice versa -->
<beans:bean id="jsonMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
</beans:bean>
<beans:bean id="xmlMessageConverter"
class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter">
</beans:bean>
<beans:bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
</beans:bean>
<beans:bean id="objectMapper" class="com.fasterxml.jackson.databind.ObjectMapper" />
<context:component-scan base-package="com.test" />
</beans:beans>
Json 输入:
"id":2014,
"name":"test",
"graduationtime":"09/05/2014",
"courses":[
"courseName":"Math",
"score":150
,
"courseName":"Che",
"score":150
]
XML 输入:
<?xml version="1.0" encoding="UTF-8" ?>
<student>
<id>2014</id>
<name>test</name>
<graduationTime>09/05/2014</graduationTime>
<courses>
<courseName>Math</courseName>
<score>150</score>
</courses>
<courses>
<courseName>Che</courseName>
<score>150</score>
</courses>
</student>
【问题讨论】:
看看这个样本。 howtodoinjava.com/spring/spring-restful/… 【参考方案1】:注册一个拦截每个请求的过滤器,将HttpServletRequest
变形为HttpServletRequestWrapper
的实现,并为Accept
标头返回Content-Type
值。例如,您可以注册一个名为SameInSameOutFilter
的过滤器,如下所示:
@Component
public class SameInSameOutFilter extends GenericFilterBean
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
SameInSameOutRequest wrappedRequest = new SameInSameOutRequest((HttpServletRequest) request);
chain.doFilter(wrappedRequest, response);
它将当前请求包装在SameInSameOutRequest
:
public class SameInSameOutRequest extends HttpServletRequestWrapper
public SameInSameOutRequest(HttpServletRequest request)
super(request);
@Override
public String getHeader(String name)
if (name.equalsIgnoreCase("accept"))
return getContentType();
return super.getHeader(name);
这个包装器告诉 spring mvc 根据请求的 Content-Type
值选择一个 HttpMessageConverter
。如果请求正文的Content-Type
是application/xml
,那么响应将是XML
。否则,响应将是JSON
。
另一种解决方案是在每个请求中手动设置 Accept
标头和 Content-Type
并避免所有这些黑客攻击。
【讨论】:
【参考方案2】:使用同一个控制器处理不同数据格式的最佳实践是让框架完成所有工作,找出编组和解组机制。
第 1 步:使用最少的控制器配置
@RequestMapping(value = "/getxmljson", method = RequestMethod.POST)
@ResponseBody
public Student processXMLJsonRequest(@RequestBody Student student)
return student;
此处无需指定consumes
和produces
。例如,考虑到您将来可能希望使用相同的方法来处理其他格式,例如 Google Protocol Buffers、EDI 等。保持控制器不受 consumes
和 produces
的影响,您可以通过全局配置添加数据格式而不必修改控制器代码。
第 2 步:使用
ContentNegotiatingViewResolver
而不是RequestMappingHandlerAdapter
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
</list>
</property>
</bean>
让视图解析器决定如何读取传入的数据以及如何将其写回。
第 3 步:使用
Accepts
和Content-Type
HTTP 标头
使用正确的 HTTP 标头值访问您的控制器将强制 ContentNegotiatingViewResolver
使用适当的数据表示自动编组和解组数据。
如果要交换 JSON 格式的数据,请将两个标头都设置为 application/json
。如果您想要 XML,请将两者都设置为 application/xml
。
如果您不想使用 HTTP 标头(理想情况下应该这样做),您只需将 .json
或 .xml
添加到 URL,然后 ContentNegotiatingViewResolver
将完成剩下的工作。
您可以查看我使用您的代码 sn-ps 创建的my sample app,该代码适用于 JSON 和 XML。
【讨论】:
还需要 org.springframework.web.servlet.view.xml.MappingJackson2XmlView 来处理 XML。【参考方案3】:添加到上面 Manish 的答案,如果您不想使用基于 xml 的配置,请改用这个基于 java 的配置-
@Bean
public ViewResolver contentNegotiatingViewResolver()
ContentNegotiatingViewResolver resolver =
new ContentNegotiatingViewResolver();
List<View> views = new ArrayList<>();
views.add(new MappingJackson2XmlView());
views.add(new MappingJackson2JsonView());
resolver.setDefaultViews(views);
return resolver;
【讨论】:
【参考方案4】:我遇到了和你一样的问题。以下是我的解决方案和示例。
以下是您需要包含的 maven 依赖项:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.4.3</version>
</dependency>
调度程序-servlet.xml
<mvc:annotation-driven
content-negotiation-manager="contentManager" />
<bean id="contentManager"
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false" />
<property name="ignoreAcceptHeader" value="false" />
<property name="defaultContentType" value="application/json" />
<property name="useJaf" value="false" />
</bean>
还有我的@RequestMapping(你可以使用自己的请求映射)
@RequestMapping(value = "/testXMLJSON",
method = RequestMethod.GET, produces =
MediaType.APPLICATION_XML_VALUE,
MediaType.APPLICATION_JSON_VALUE )
@ResponseBody
public ArtworkContentMessageType testXMLJSON()
//this is GS1 xml standard mapping.
ArtworkContentMessageType resp = new ArtworkContentMessageType();
StandardBusinessDocumentHeader standarBusinessDocumentHeader = new StandardBusinessDocumentHeader();
resp.setStandardBusinessDocumentHeader(standarBusinessDocumentHeader );
ArtworkContentType artWorkContent = new ArtworkContentType();
resp.getArtworkContent().add(artWorkContent);
return resp ;
如果需要application/xml
,则必须存在以下标题
Content-Type:application/xml
Accept:application/xml
【讨论】:
【参考方案5】:如果资源定义如下
@GET
@Path("/id")
@Produces(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)
public Student getStudent(@PathParam("id") String id)
return student(); // logic to retunrs student object
那么请求应该包含'accept'标头('application/json'或application/xml'), 然后它以 json 或 xml 格式返回响应。
样品请求:
curl -k -X GET -H "accept: application/json" "https://172.17.0.5:8243/service/1.0/222"
学生班级示例
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "student")
public class Student
private int id;
private String name;
private String collegeName;
private int age;
@XmlAttribute
public int getId()
return id;
public void setId(int id)
this.id = id;
@XmlElement
public String getName()
return name;
public void setName(String name)
this.name = name;
@XmlElement
public String getCollegeName()
return collegeName;
public void setCollegeName(String collegeName)
this.collegeName = collegeName;
public int getAge()
return age;
@XmlElement
public void setAge(int age)
this.age = age;
【讨论】:
以上是关于接受/返回 XML/JSON 请求和响应 - Spring MVC的主要内容,如果未能解决你的问题,请参考以下文章