Java 接受/返回 XML/JSON 请求和响应 - Spring MVC
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35270660/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Accepting / returning XML/JSON request and response - Spring MVC
提问by Mohan
I need to write a rest service which accepts XML/JSON as a input (POST method) and XML/JSON as a output (based on the input format). I have tried a below approach to achieve this but doesn't helped out.Endpoint method accepts both XML/JSON but while responding it always gives either JSON or XML based on the order specified in @RequestMapping -produces.Any help will be really appreciated.
我需要编写一个 rest 服务,它接受 XML/JSON 作为输入(POST 方法)和 XML/JSON 作为输出(基于输入格式)。我尝试了以下方法来实现这一点,但没有帮助。端点方法接受 XML/JSON,但在响应时,它总是根据 @RequestMapping -produces 中指定的顺序提供 JSON 或 XML。任何帮助将不胜感激.
My endpoint method:
我的端点方法:
@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 Class: Student.java
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.Hymanson.annotation.JsonIgnore;
import com.fasterxml.Hymanson.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 Class: Course.java
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.Hymanson.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
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.MappingHymanson2HttpMessageConverter">
</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.Hymanson.databind.ObjectMapper" />
<context:component-scan base-package="com.test" />
</beans:beans>
Json Input:
JSON 输入:
{
"id":2014,
"name":"test",
"graduationtime":"09/05/2014",
"courses":[
{
"courseName":"Math",
"score":150
},
{
"courseName":"Che",
"score":150
}
]
}
XML Input:
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>
回答by Ali Dehghani
Register a filter that intercepts each request, warp the HttpServletRequest
into an implementation of HttpServletRequestWrapper
and returns the Content-Type
value for Accept
header. For example, you can register a filter named SameInSameOutFilter
like following:
注册一个拦截每个请求的过滤器,将其HttpServletRequest
转换为 的实现HttpServletRequestWrapper
并返回标头的Content-Type
值Accept
。例如,您可以注册一个名称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);
}
}
It wraps current request in a SameInSameOutRequest
:
它将当前请求包装在一个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);
}
}
This wrapper tells spring mvc to select a HttpMessageConverter
based on request's Content-Type
value. If request body's Content-Type
is application/xml
, then the response would be an XML
. Otherwise, the response would be JSON
.
这个包装器告诉 spring mvcHttpMessageConverter
根据请求的Content-Type
值选择一个。如果请求正文Content-Type
是application/xml
,则响应将是XML
。否则,响应将是JSON
。
The other solution is to manually set the Accept
header along with Content-Type
in each request and avoid all these hacks.
另一种解决方案是在每个请求中手动设置Accept
标头Content-Type
并避免所有这些黑客攻击。
回答by manish
The best practice for handling different data formats with the same controller is to let the framework do all the work of figuring out the marshalling and unmarshalling mechanisms.
使用同一个控制器处理不同数据格式的最佳实践是让框架完成所有的工作,以确定编组和解组机制。
Step 1: Use minimal controller configuration
第 1 步:使用最少的控制器配置
@RequestMapping(value = "/getxmljson", method = RequestMethod.POST)
@ResponseBody
public Student processXMLJsonRequest(@RequestBody Student student) {
return student;
}
There is no need to specify consumes
and produces
here. As an example, consider that you may want this same method to handle other formats in the future such as Google Protocol Buffers, EDI, etc. Keeping the controllers free of consumes
and produces
will let you add data formats through global configuration instead of having to modify the controller code.
没有必要在这里指定consumes
和produces
。例如,考虑到您将来可能希望使用相同的方法来处理其他格式,例如 Google Protocol Buffers、EDI 等。保持控制器免费,consumes
并produces
允许您通过全局配置添加数据格式,而不必修改控制器代码。
Step 2: Use
ContentNegotiatingViewResolver
instead ofRequestMappingHandlerAdapter
第 2 步:使用
ContentNegotiatingViewResolver
代替RequestMappingHandlerAdapter
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingHymanson2JsonView"/>
</list>
</property>
</bean>
Let the view resolver decide how to read incoming data and how to write it back.
让视图解析器决定如何读取传入数据以及如何将其写回。
Step 3: Use
Accepts
andContent-Type
HTTP headers
第 3 步:使用
Accepts
和Content-Type
HTTP 标头
Hitting your controller with the correct HTTP header values will force ContentNegotiatingViewResolver
to marshal and unmarshal data automatically using the appropriate data representations.
使用正确的 HTTP 标头值命中您的控制器将强制ContentNegotiatingViewResolver
使用适当的数据表示自动编组和解组数据。
If you want to exchange data in JSON format, set both headers to application/json
. If you want XML instead, set both to application/xml
.
如果要以 JSON 格式交换数据,请将两个标头都设置为application/json
. 如果您想要 XML,请将两者都设置为application/xml
.
If you do not want to use HTTP headers (which ideally you should), you can simply add .json
or .xml
to the URL and ContentNegotiatingViewResolver
will do the rest.
如果您不想使用 HTTP 标头(理想情况下您应该这样做),您可以简单地将.json
或添加.xml
到 URL 并ContentNegotiatingViewResolver
完成其余的工作。
You can check out my sample appthat I created using your code snippets that works fine for JSON and XML.
回答by Gagandeep Kalra
Adding to Manish's answer above, if you don't wanna use xml based configuration use this java based configuration instead-
添加到上面 Manish 的答案,如果您不想使用基于 xml 的配置,请改用这个基于 java 的配置 -
@Bean
public ViewResolver contentNegotiatingViewResolver() {
ContentNegotiatingViewResolver resolver =
new ContentNegotiatingViewResolver();
List<View> views = new ArrayList<>();
views.add(new MappingHymanson2XmlView());
views.add(new MappingHymanson2JsonView());
resolver.setDefaultViews(views);
return resolver;
}
回答by Sh4m
i was facing the same problem like yours. Below is my solution and sample.
我面临着和你一样的问题。以下是我的解决方案和示例。
Below is maven dependency that you need to include:
以下是您需要包含的 maven 依赖项:
<dependency>
<groupId>com.fasterxml.Hymanson.core</groupId>
<artifactId>Hymanson-core</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.Hymanson.core</groupId>
<artifactId>Hymanson-databind</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.Hymanson.core</groupId>
<artifactId>Hymanson-annotations</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.Hymanson.dataformat</groupId>
<artifactId>Hymanson-dataformat-xml</artifactId>
<version>2.4.3</version>
</dependency>
dispatcher-servlet.xml
调度程序-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>
and my @RequestMapping ( you can use your own request mapping )
和我的@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 ;
}
If application/xml
is required then, below headers must be present
如果application/xml
需要,则必须存在以下标题
Content-Type:application/xml
Accept:application/xml
回答by Anusha Ruwanpathirana
If the resource define as below
如果资源定义如下
@GET
@Path("/{id}")
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Student getStudent(@PathParam("id") String id) {
return student(); // logic to retunrs student object
}
Then the request should contains 'accept' header ('application/json' or application/xml'),
then it returns response in json or xml format.
然后请求应该包含'accept' 头('application/json' 或 application/xml'),
然后它以 json 或 xml 格式返回响应。
Sample request :
样品请求:
curl -k -X GET -H "accept: application/json" "https://172.17.0.5:8243/service/1.0/222"
Sample Student class
示例学生类
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;
}
}