spring mvc rest response json and xml
I have the requirement to return the result from the database either as a string in xml-structure or as json-structure. I've got a solution, but I don't know, if this one is the best way to solve this. I have two methods here:
@RequestMapping(value = "/content/json/{ids}", method = RequestMethod.GET)
public ResponseEntity<String> getContentByIdsAsJSON(@PathVariable("ids") String ids)
{
String content = null;
StringBuilder builder = new StringBuilder();
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add("Content-Type", "text/html; charset=utf-8");
// responseHeaders.add("Content-Type", "application/json; charset=utf-8");
List<String> list = this.contentService.findContentByListingIdAsJSON(ids);
if (list.isEmpty())
{
content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><error>no data found</error>";
return new ResponseEntity<String>(content, responseHeaders, HttpStatus.CREATED);
}
for (String json : list)
{
builder.append(json + "\n");
}
content = builder.toString();
return new ResponseEntity<String>(content, responseHeaders, HttpStatus.CREATED);
}
@RequestMapping(value = "/content/{ids}", method = RequestMethod.GET)
public ResponseEntity<String> getContentByIdsAsXML(@PathVariable("ids") String ids)
{
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add("Conten开发者_Python百科t-Type", "application/xml; charset=utf-8");
String content = this.contentService.findContentByListingIdAsXML(ids);
if (content == null)
{
content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><error>no data found</error>";
return new ResponseEntity<String>(content, responseHeaders, HttpStatus.CREATED);
}
return new ResponseEntity<String>(content, responseHeaders, HttpStatus.CREATED);
}
for the first method I need a better solution, which I already asked here: spring mvc rest mongo dbobject response
The next thing is, that I inserted in the configuration a json converter:
<bean id="jsonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json"/>
</bean>
when I change the content-type at the first method to "application/json", it works, but then the xml response doesn't work anymore, because the json converter wants to convert the xml string to json-structure I think.
what can I do, that spring identifies the difference that the one method should return a json type and the other one a normal xml as string? I tried it with the accept flag:
@RequestMapping(value = "/content/json/{ids}", method = RequestMethod.GET, headers = "Accept=application/json")
but this doesn't work. I get the following error:
org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.StackOverflowError
I hope that somebody can help me out.
If you are using Spring 3.1, you can take advantage of the new produces
element on the @RequestMapping
annotation to ensure that you produce XML or JSON as you wish, even within the same app.
I wrote a post about this here:
http://springinpractice.com/2012/02/22/supporting-xml-and-json-web-service-endpoints-in-spring-3-1-using-responsebody/
Whoa...when you're working with Spring, assume someone else has come up against the same issue. You can dump all the server-side JSON generation, because all you need to do is:
- Include the Jackson JSON JARs in your app
- Set the
RequestMapping
return type to@ResponseBody(yourObjectType)
Spring will auto-magically convert your object to JSON. Really. Works like magic.
Doc for @ResponseBody
: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-ann-responsebody
You can use ContentNegotiatingViewResolver as below:
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="defaultContentType" value="application/json" />
<property name="ignoreAcceptHeader" value="true" />
<property name="favorPathExtension" value="true" />
<property name="order" value="1" />
<property name="mediaTypes">
<map>
<entry key="xml" value="application/xml" />
<entry key="json" value="application/json" />
</map>
</property>
<property name="defaultViews">
<list>
<ref bean="xmlView"/>
<ref bean="jsonView"/>
</list>
</property>
</bean>
<bean id="jsonView"
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<property name="contentType" value="application/json;charset=UTF-8"/>
<property name="disableCaching" value="false"/>
</bean>
<bean id="xmlView"
class="org.springframework.web.servlet.view.xml.MarshallingView">
<property name="contentType" value="application/xml;charset=UTF-8"/>
<constructor-arg>
<ref bean="xstreamMarshaller"/>
</constructor-arg>
</bean>
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="autodetectAnnotations" value="true" />
<property name="annotatedClass" value="demo.domain.xml.XMLResponse"/>
<property name="supportedClasses" value="demo.domain.xml.XMLResponse"/>
</bean>
In your controller:
@RequestMapping(value = "/get/response.json", method = RequestMethod.GET)
public JSONResponse getJsonResponse(){
return responseService.getJsonResponse();
}
@RequestMapping(value = "/get/response.xml", method = RequestMethod.GET)
public XMLResponse getXmlResponse(){
return responseService.getXmlResponse();
}
If someone using Spring Boot for XML response then add the following dependency,
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
And in the model class you are returning add the @XmlRootElement
.
@Entity
@Table(name = "customer")
@XmlRootElement
public class Customer {
//... fields and getters, setters
}
and in your controller add produces="application/xml"
. This will produce the response in xml format.
Here I wrote method which take XML as request parameter from your request mapping URL
Here I am posting XML to my URL "baseurl/user/createuser/"
public class UserController {
@RequestMapping(value = "createuser/" ,
method=RequestMethod.POST, consumes= "application/xml")
@ResponseBody
ResponseEntity<String> createUser(@RequestBody String requestBody ) {
String r = "<ID>10</ID>"; // Put whatever response u want to return to requester
return new ResponseEntity<String>(
"Handled application/xml request. Request body was: "
+ r,
new HttpHeaders(),
HttpStatus.OK);
}
}
I tested it using chrome poster where you can send any xml in content body like:
"<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <userEntity><id>3</id><firstName>saurabh</firstName><lastName>shri</lastName><password>pass</password><userName>test@test.com</userName></userEntity>"
This XML will capture by my createUser method and stored in String requestBody which i can use further
Easiest way to do this to get JSON response would be: Using Spring 3.1, you could do as follows
In your pom.xml file (hoping you are using a maven project), add maven dependency for jackson-mapper (http://mvnrepository.com/artifact/org.codehaus.jackson/jackson-mapper-asl/1.9.13)
Modify your code as follows and test the endpoint on postman:
@RequestMapping(value = "/content/json/{ids}", method = RequestMethod.GET) public @ResponseBody String getContentByIdsAsJSON(@PathVariable("ids") String ids){ String content = ""; StringBuilder builder = new StringBuilder(); List<String> list = this.contentService.findContentByListingIdAsJSON(ids); if (list.isEmpty()){ content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><error>no data found</error>"; return content; } for (String json : list){ builder.append(json + "\n"); } content = builder.toString(); return content; }
After a lot research i think i have a good solution for this: very simple, spring by default, uses Jackson to working with Json, that library comes in the spring-boot-starter-web, but the Xml extention of Jackson doesn't come by default, all you need to do is import in your build.gradle or in your pom.xml the jackson-dataformat-xml dependency and now you can alternate between json or xml for example with a code like this:
@PostMapping(value = "/personjson")
public ResponseEntity<?> getJsonPerson (@RequestBody Person person) {
return ResponseEntity.accepted().contentType(MediaType.APPLICATION_JSON)
.body(person);
}
@PostMapping(value = "/personxml")
public ResponseEntity<?> getXmlPerson (@RequestBody Person person) {
return ResponseEntity.accepted().contentType(MediaType.APPLICATION_XML)
.body(person);
}
Where person is a bean (only have the @Component tag), Lock at that both codes are equal only the MediaType is different and it works!!, isn't nesesary too add the "produces" and "consumes" atributes to the Mapping tag, because Spring, by default, can consume both Json and Xml, i did an example sending a Json and getting. xml, and sending xml getting a Json, only you need to specify in your postman or in curl when you do the request, the correct header of the body that you are sending either application/json or application/xml.
Note: this is only a way a todo this, JAXB and XmlRootElement, is other way to do it.
精彩评论