2011-01-16 23 views
5

Si desarrollamos REST utilizando Spring MVC, admitirá datos XML y JSON. He escribió ContentNegotiationViewResorver en mi primavera config frijol app-servlet.xmlSpring REST 3 para admitir XML y JSON

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

Y mi primavera RESTO controlador es:

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

puse @XStreamAlias("customer") anotación en mi clase de dominio del cliente. Pero cuando intento acceder a http://localhost:8080/rest/customers/teddy.xml siempre responden datos JSON.

Anoté @XmlRootElement(name="customer") anotación en mi clase de dominio de cliente. Pero cuando intento acceder http://localhost:8080/rest/customers/teddy.json siempre responden datos XML.

¿Hay algo raro?

+0

Dónde está app/clientes/teddy.xml asignada en el controlador? – chris

+0

lo siento ..., la url es: /rest/customers/teddy.xml, esta url supone invocar el método ShowCustomer. y teddy es el parámetro {id}. –

+0

¿Cómo está intentando acceder a esa URL? Un navegador web? ¿Está enviando el encabezado de codificación de tipo de contenido apropiado en la solicitud? – skaffman

Respuesta

2

Creo que el tipo de contenido "xml" debe asignarse a "text/xml" no a "application/xml". Además, para forzar los resolvedores de tipo de contenido basados ​​en la extensión, puede intentar establecer la propiedad "favorPathExtension" de "ContentNegotiatingViewResolver" en verdadero (aunque debería haber sido cierto de manera predeterminada)

EDITAR: He añadido un trabajo muestra en esta ubicación de GIT - git://github.com/bijukunjummen/mvc-samples.git, si abre el punto final, usando mvn tomcat: ejecutar, el json se sirve en http://localhost:8080/mvc-samples/rest/customers/teddy.json y xml en http://localhost:8080/mvc-samples/rest/customers/teddy.xml. Esto utiliza JAXB2 no XStream, ya que estoy familiarizado con JAXB. Una cosa que noté fue que cuando mis anotaciones JAXB no eran correctas en la clase Cliente, Spring estaba publicando JSON y no XML de la manera en que lo veías (puedes replicar eliminando la anotación XMLRootElement de la clase Cliente), una vez que arreglé mi anotaciones, recibí XML como se esperaba. Podría ser que haya algún problema con la configuración de XStream.

EDIT 2: ¡¡Tienes razón !! No me di cuenta, una vez que recuperé xml, asumí que json está trabajando ahora. Veo el problema, en AnnotationMethodHandlerAdapter, el manejo de @ResponseBody es un poco extraño, ignora por completo los ViewResolvers, y usa los MessageConverters registrados que pasan por alto el ContentNegotiatingViewResolver, una solución por ahora es usar la anotación @ModelAttribute para la respuesta, en lugar de @ResponseBody , de esta manera, se llama a los Resolvers view. Pruebe ahora usar el proyecto en [email protected]:bijukunjummen/mvc-samples.git y vea si le funciona. Esto podría ser un error de Spring, puedes intentarlo en el foro de Spring y ver qué recomiendan.

+0

Tengo el tipo de contenido de cambio a text/xml y text/json. y establecer faforPathExtension convertido en verdadero. Pero puedo enviar un mensaje de texto mientras accedo a la aplicación/rest/customers/teddy.xml –

+0

No estoy seguro @adisembiring, traté de usar JAXB2 y funciona sin problemas - He puesto una muestra en esta ubicación - git: //github.com/ bijukunjummen/mvc-samples.git, sirve json correctamente en /rest/customers/teddy.json y xml at rest/customers/teddy.xml. –

+0

He ejecutado su proyecto, intente acceder a la aplicación usando 'firefox',' chrome' y 'poster firefox plugin'. pero obtengo el valor 'xml' mientras acceso' rest/customers/teddy.json'. Puedes consultar el resultado de mi navegador en http://i52.tinypic.com/29hb4j.jpg –

1

Tuve el mismo problema. Supongo que estás usando Spring 3 y que has usado <mvc:annotation-driven/>. No estoy del todo seguro, pero creo que esto crea un conflicto basado en los convertidores de mensajes que configura el espacio de nombres de mvc.

Usando el espacio de nombres OXM trabajó para mí:

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

Configuración de contenido (MVC e interno vista de resolución se encuentran en otro contexto):

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

este ejemplo se utiliza JAXB, por lo que se necesitaría jaxb-api y jaxb-impl en classpath.

Además, solo un consejo, no necesita la aplicación-servlet.xml. En tu webxml, establecer la configuración para anular y dejar que el oyente Contexto les carga para usted:

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

Qué Aceptar encabezados se envían a su servidor? Asegúrese de que el tipo de contenido que desea solicitar se encuentre en esta lista.

+0

cuando agrego la anotación @XmlRootElement en la clase de dominio, el servidor devuelve el formato xml. cuando agrego la anotación @XStreamAlias, el servidor devuelve el formato JSON. Creo que el servidor acepta tanto xml como json. –

0

Al acceder al controlador con una nave de navegación, se enviará un encabezado Accept típico del navegador. No coincidirá con ninguna resolución de vista y por defecto con la primera (aplicación/xml) o concuerda porque la aplicación/xml está en la lista Aceptar.

Puedo recomendar el uso de RestClient http://code.google.com/p/rest-client/ para tener control completo sobre qué cabecera de aceptación (si es que hay alguna) que desea enviar.

No recomiendo usar text/xml ya que el juego de caracteres predeterminado es US-ASCII y no UTF-8. Esto podría crear problemas de codificación originales en el futuro. Siempre puede especificar la codificación pero appliation/xml tiene una codificación por defecto UTF-8.

1

Bueno, tengo una solución, pero no sé si es la forma correcta en su demostración del método de los usuarios:

@RequestMapping(value = "/{id}", method = GET) 
@ResponseBody 
public Customer showCustomer(@PathVariable String id) { 
    Customer c = new Customer("0001", "teddy", "bean"); 
    return c; 
} 

En esta parte, estamos utilizando MVC de la primavera y en el controlador que debe haber devolver una vista, por lo que eliminé la anotación @ResponseBody y devolvió un String con el nombre de la vista porque en nuestro XML agregamos un ContentNegotiatingViewResolver y cuando tenemos ResponseBody el contenidonegociationviewresolver se ignora porque está esperando una vista pero devolvimos el objeto el método debería ser así:

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

bien que funciona para mí, si tiene problemas que puede agregar a su app-servlet.xml

este bean, pero no creo que usted tiene que añadir este.

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

I got the answers from mkyong.com

Cuestiones relacionadas