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 HttpServletRequestinto an implementation of HttpServletRequestWrapperand returns the Content-Typevalue for Acceptheader. For example, you can register a filter named SameInSameOutFilterlike 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 HttpMessageConverterbased on request's Content-Typevalue. If request body's Content-Typeis 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 Acceptheader along with Content-Typein 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 consumesand produceshere. 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 consumesand produceswill 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
ContentNegotiatingViewResolverinstead 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
AcceptsandContent-TypeHTTP headers
第 3 步:使用
Accepts和Content-TypeHTTP 标头
Hitting your controller with the correct HTTP header values will force ContentNegotiatingViewResolverto 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 .jsonor .xmlto the URL and ContentNegotiatingViewResolverwill 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/xmlis 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;
}
}

