Primavera REST 3 al supporto XML e JSON
-
11-10-2019 - |
Domanda
Se sviluppiamo REST utilizzando Spring MVC, sosterrà i dati XML e JSON. Ho scritto nel mio ContentNegotiationViewResorver primavera app-servlet.xml
config fagiolo
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"
p:order="1">
<property name="mediaTypes">
<map>
<entry key="xml" value="application/xml" />
<entry key="json" value="application/json" />
</map>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<property name="marshaller">
<bean class="org.springframework.oxm.xstream.XStreamMarshaller"
p:autodetectAnnotations="true" />
</property>
</bean>
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
</list>
</property>
</bean>
E RESTO controller mia primavera è:
@Controller
@RequestMapping("/rest/customers")
class CustomerRestController {
protected Log log = LogFactory.getLog(CustomerRestController.class);
@RequestMapping(method = POST)
@ResponseStatus(CREATED)
public void createCustomer(@RequestBody Customer customer,
HttpServletResponse response) {
log.info(">>>" + customer.getName());
response.setHeader("Location", String.format("/rest/customers/%s",
customer.getNumber()));
}
@RequestMapping(value = "/{id}", method = GET)
@ResponseBody
public Customer showCustomer(@PathVariable String id) {
Customer c = new Customer("0001", "teddy", "bean");
return c;
}
@RequestMapping(value = "/{id}", method = PUT)
@ResponseStatus(OK)
public void updateCustomer(@RequestBody Customer customer) {
log.info("customer: " + customer.getName());
}
I set @XStreamAlias("customer")
annotazione nella mia classe di dominio del cliente.
Ma quando provo accesso http://localhost:8080/rest/customers/teddy.xml
sempre dati di risposta JSON.
I set @XmlRootElement(name="customer")
annotazione nella mia classe di dominio del cliente.
Ma quando provo accesso http://localhost:8080/rest/customers/teddy.json
sempre dati di risposta XML.
C'è qualche cosa che non va?
Soluzione
Credo che il tipo di contenuto "xml" dovrebbero essere mappati a "text / xml" non "application / xml". Inoltre, per forzare resolver tipo di contenuti in base all'estensione, si può provare a impostare il "favorPathExtension" di proprietà di "ContentNegotiatingViewResolver" true (anche se dovrebbe essere vero per difetto!)
EDIT: ora ho aggiunto un campione di lavoro in questa posizione GIT - git://github.com/bijukunjummen/mvc-samples.git
, se si mettono il punto finale, utilizzando mvn Tomcat: corsa, il JSON è servito a http://localhost:8080/mvc-samples/rest/customers/teddy.json
e XML a http://localhost:8080/mvc-samples/rest/customers/teddy.xml
. Questo utilizza non JAXB2 Xstream, come mi è familiare con JAXB. Una cosa che ho notato è che quando le mie annotazioni JAXB non erano corretti in classe Customer, Primavera stava servendo fuori JSON e non XML il modo in cui l'avete visto (È possibile replicare rimuovendo l'annotazione XMLRootElement dalla classe Cliente), una volta che ho fissato il mio annotazioni, sono tornato XML come previsto. Quindi potrebbe essere che ci sia qualcosa di sbagliato con la configurazione XStream.
EDIT 2: Hai ragione !! Non ho notato, una volta ho avuto xml indietro, ho supposto che JSON sta lavorando ora. Io vedo il problema, nel AnnotationMethodHandlerAdapter
, la gestione per @ResponseBody
è un po 'strano, ignora completamente le ViewResolvers, e utilizza i MessageConverters registrati invece bypassando completamente il ContentNegotiatingViewResolver
, una soluzione per ora è quello di utilizzare @ModelAttribute
annotazioni per la risposta, invece di @ResponseBody , in questo modo i resolver vista sono sempre chiamato. Provate ora con il progetto a git@github.com:bijukunjummen/mvc-samples.git
e vedere se funziona per voi. Questo potrebbe essere un bug primavera, si può provare e portarla fino nel forum primavera e vedere che cosa suggeriscono.
Altri suggerimenti
intestazioni Cosa Accetta vengono inviati al server? Assicurarsi che il tipo di contenuto che si desidera richiesta non è in questa lista.
Primavera 3.1 risolve il problema si parla utilizzando il nuovo elemento produces
sul annotazioni @RequestMapping
. Questo consente di controllare la HttpMessageConverter
che la primavera si applica al vostro oggetto.
ho scritto un post su di esso:
Ho avuto lo stesso problema. Presumo che si sta utilizzando Spring 3 e ho usato <mvc:annotation-driven/>
. Io non sono del tutto sicuro, ma penso che questo crea qualche conflitto sulla base dei convertitori messaggio che il MVC namespace configura.
utilizzando lo spazio OXM funzionato per me:
@XmlRootElement(name="person")
class Person {
private String firstName;
private String lastName;
}
@Controller
@RequestMapping("person")
class PersonController {
@RequestMapping("list")
public @ResponseBody Person getPerson() {
Person p = new Person();
p.setFirstName("hello");
p.setLastName("world");
return p;
}
}
Content Configuration (MVC e vista interna resolver sono in un altro contesto):
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:oxm="http://www.springframework.org/schema/oxm"
xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<oxm:jaxb2-marshaller id="jaxbMarshaller">
<oxm:class-to-be-bound name="package.Person" />
</oxm:jaxb2-marshaller>
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="defaultContentType" value="text/html" />
<property name="ignoreAcceptHeader" value="true" />
<property name="favorPathExtension" value="true" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<property name="marshaller" ref="jaxbMarshaller" />
</bean>
</list>
</property>
</bean>
</beans>
Questo esempio utilizza JAXB, in modo da avreste bisogno di JAXB-api e JAXB-impl nel classpath.
Inoltre, solo un suggerimento, non è necessario l'app-servlet.xml. Nel vostro web.xml, impostare la configurazione per nulla e lasciare che il carico contesto Listener loro per voi:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/mvc-context.xml, /WEB-INF/spring/content-negotiation-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value/>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Beh ho avuto una soluzione, ma non so se è il modo giusto nel vostro metodo show cliente:
@RequestMapping(value = "/{id}", method = GET)
@ResponseBody
public Customer showCustomer(@PathVariable String id) {
Customer c = new Customer("0001", "teddy", "bean");
return c;
}
In questa parte, stiamo usando MVC della primavera e nel controller dovremmo essere restituire una vista, quindi ho rimosso il @ResponseBody
annotazione e ho restituire un String
con il nome della vista perché nel nostro XML abbiamo aggiunto un ContentNegotiatingViewResolver
e quando abbiamo ResponseBody
il contentnegociationviewresolver viene ignorata perché è in attesa di una vista ma siamo tornati l'oggetto in modo che il metodo dovrebbe essere così:
@RequestMapping(value = "/{id}", method = GET)
public String showCustomer(@PathVariable String id, ModelMap model) {
Customer c = new Customer("0001", "teddy", "bean");
model.addAttribute("customer",c);
return "myView";
}
così che funziona per me, se avete problemi che si possono aggiungere al vostro app-servlet.xml
questo fagiolo, ma non credo che si deve aggiungere questo.
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
Accesso al controller utilizzando un browswer invierà un browser tipico Accetta intestazione. Essa non corrisponderà alcun resolver vista e di default al primo (application / xml) o partite a causa application / xml è nella lista Accetta.
posso consiglia di utilizzare RestClient http://code.google.com/p/rest- client / di avere il controllo completo su ciò che Accept intestazione (se uno a tutti) che si desidera inviare.
Non consiglio usando text / xml, come il set di caratteri predefinito è US-ASCII e non UTF-8. Questo potrebbe creare problemi di codifica funky lungo la strada. È sempre possibile specificare la codifica ma appliation / XML ha una codifica predefinita UTF-8.