2016-02-08 28 views
6

Ho bisogno di scrivere un servizio di riposo che accetta XML/JSON come input (metodo POST) e XML/JSON come output (basato sul formato di input). Ho provato un approccio qui sotto per ottenere questo risultato, ma non mi ha aiutato. Il metodo Endpoint accetta sia XML/JSON, ma mentre risponde fornisce sempre JSON o XML in base all'ordine specificato in @RequestMapping -produces. Qualsiasi aiuto sarà molto apprezzato .Accettazione/restituzione di XML/JSON richiesta e risposta - Spring MVC

mio metodo endpoint:

@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 Classe: 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 Classe: 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; 
    } 
} 

primavera-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 ingresso:

{ 
"id":2014, 
"name":"test", 
"graduationtime":"09/05/2014", 
"courses":[ 
{ 
"courseName":"Math", 
"score":150 
}, 
{ 
"courseName":"Che", 
"score":150 
} 
] 
} 

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> 
+0

Guarda questo esempio. http://howtodoinjava.com/spring/spring-restful/spring-rest-hello-world-xml-example/ –

risposta

0

Registrare un filtro che intercetta ogni richiesta, ordito il HttpServletRequest in un'implementazione di HttpServletRequestWrapper e restituisce il valore Content-Type per Accept intestazione. Ad esempio, è possibile registrare un filtro denominato SameInSameOutFilter come segue:

@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); 
    } 
} 

Avvolge richiesta corrente in un 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); 
    } 
} 

Questo wrapper dice Spring MVC per selezionare un HttpMessageConverter in base al valore di richiesta Content-Type. Se il corpo della richiesta Content-Type è application/xml, la risposta sarà XML. In caso contrario, la risposta sarebbe JSON.

L'altra soluzione è quella di impostare manualmente l'intestazione insieme a Content-Type in ogni richiesta ed evitare tutti questi hack.

13

La migliore pratica per gestire formati di dati diversi con lo stesso controller è lasciare che il framework faccia tutto il lavoro necessario per capire i meccanismi di marshalling e unmarshalling.

Fase 1: Usa configurazione del controller minima

@RequestMapping(value = "/getxmljson", method = RequestMethod.POST) 
@ResponseBody 
public Student processXMLJsonRequest(@RequestBody Student student) { 
    return student; 
} 

Non è necessario specificare consumes e produces qui. Ad esempio, considera che potresti utilizzare questo stesso metodo per gestire altri formati in futuro, come i buffer dei protocolli di Google, l'EDI, ecc. Mantenere i controller liberi da consumes e produces ti consente di aggiungere formati di dati tramite la configurazione globale invece di dover modificare il codice del controller.

Fase 2: Uso ContentNegotiatingViewResolver invece di 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> 

Lasciate che il risolutore vista decidere come leggere dati in ingresso e come scrivere indietro.

Fase 3: Usa Accepts e Content-Type HTTP headers

colpire il vostro controller con i valori di intestazione HTTP corretti costringerà ContentNegotiatingViewResolver al maresciallo ei dati unmarshalling automaticamente utilizzando le rappresentazioni di dati appropriati.

Se si desidera scambiare dati in formato JSON, impostare entrambe le intestazioni su application/json. Se invece preferisci XML, imposta entrambi su application/xml.

Se non si desidera utilizzare intestazioni HTTP (che idealmente si dovrebbe), è sufficiente aggiungere .json o .xml all'URL e ContentNegotiatingViewResolver farà il resto.


È possibile controllare my sample app che ho creato utilizzando i frammenti di codice che funziona bene per JSON e XML.

+0

Sarebbe inoltre necessario org.springframework.web.servlet.view.xml.MappingJackson2XmlView per gestire XML. – anre

4

aggiunta alla risposta di Manish sopra, se non vuoi utilizzare la configurazione basata utilizzo xml questa configurazione basato su Java instead-

@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; 
} 
0

ho di fronte lo stesso problema come la tua. Di seguito è la mia soluzione e campione.

Qui di seguito è la dipendenza che è necessario includere:

 <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> 

dispatcher-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> 

e la mia @RequestMapping (è possibile utilizzare il proprio mappatura richiesta)

@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 ; 
    }