Pregunta

Si desarrollamos REST utilizando Spring MVC, se apoyará datos XML y JSON. He escribió ContentNegotiationViewResorver en mi primavera app-servlet.xml frijol config

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

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

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

¿Hay algo mal?

¿Fue útil?

Solución

Creo que el tipo de contenido "xml" deben ser mapeados a "text / xml" no "application / xml". Además, para forzar al sistema DNS de tipo de contenido basado en la extensión, se puede tratar de establecer la propiedad "favorPathExtension" de "ContentNegotiatingViewResolver" true (aunque debería haber sido cierto por defecto!)

EDIT: He añadido una muestra de trabajo en este lugar GIT - git://github.com/bijukunjummen/mvc-samples.git, si lleva hasta el punto final, utilizando mvn Tomcat: ejecución, 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. Este usos no JAXB2 xstream, ya que estoy familiarizado con JAXB. Una cosa que me llamó la atención fue que cuando mis anotaciones JAXB no eran correctas en la clase de atención al cliente, la primavera estaba cumpliendo JSON y no XML la forma en que lo encontró (Es posible replicar mediante la eliminación de la anotación XMLRootElement de la clase Cliente), una vez que me fijo mi anotaciones, yo volvimos XML como se esperaba. Por lo tanto, podría ser que hay algo mal con su configuración xstream.

EDIT 2: Tienes razón !! No me di cuenta, una vez que llegué xml espalda, supuse que JSON está trabajando ahora. Veo el problema, en AnnotationMethodHandlerAdapter, el manejo de @ResponseBody es un poco extraño, ignora por completo las ViewResolvers, y utiliza los MessageConverters registrados en lugar evitando completamente el ContentNegotiatingViewResolver, una solución por ahora es utilizar la anotación @ModelAttribute para la respuesta, en lugar de @ResponseBody , de esta manera view son los dispositivos de resolución recibiendo llamadas. Pruebe usando ahora el proyecto en git@github.com:bijukunjummen/mvc-samples.git y ver si funciona para usted. Esto podría ser un error de primavera, es posible tratar de sacar el tema en el foro de primavera y ver lo que recomiendan.

Otros consejos

Lo Aceptar encabezados se envían al servidor? Asegúrese de que el tipo de contenido que desea solicitud se encuentra en esta lista.

Spring 3.1 resuelve el problema que mencionas usando el nuevo elemento produces en la anotación @RequestMapping. Esto le permite controlar el HttpMessageConverter que la primavera se aplica a su objeto.

Me escribió una entrada de blog sobre él:

http://springinpractice.com/2012/02/22/supporting-xml-and-json-web-service-endpoints-in-spring-3-1-using-responsebody/

Yo tenía el mismo problema. Asumo que estás utilizando Spring 3 y que he utilizado <mvc:annotation-driven/>. No estoy del todo seguro, pero creo que esto crea un conflicto basado en los convertidores de mensajes que el espacio de nombres MVC configura.

Uso del espacio de nombres OXM trabajado 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;
   }
}

Contenido de configuración (MVC y vista interna de resolución son 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>

En este ejemplo se utiliza JAXB, por lo que se necesitaría jaxb-api y jaxb-impl en la ruta de clase.

Además, sólo un consejo, no se necesita la aplicación-servlet.xml. En su web.xml, establecer la configuración para nula y dejar que la carga Contexto Listener 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>

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 debemos estar devolver un punto de vista, por lo que me quita el @ResponseBody anotación y devolver un String con el nombre de la vista porque en nuestro XML añadimos un ContentNegotiatingViewResolver y cuando tenemos ResponseBody la contentnegociationviewresolver se ignora porque está a la espera de una vista, pero que devuelve el objeto por lo que el método debe 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 se pueden 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>

Tengo las respuestas de mkyong.com

Acceso al controlador mediante un browswer enviará un navegador típico Aceptar cabecera. No va a coincidir con cualquier vista resolver y por defecto a la primera (application / xml) o partidos porque application / xml se encuentra en la lista Aceptar.

Puedo recomendar el uso de RESTClient http://code.google.com/p/rest- cliente / tenga control completo sobre lo Aceptar cabecera (si en absoluto) que desea enviar.

No recomiendo el uso de texto / xml como el conjunto de caracteres por defecto es de US-ASCII y no UTF-8. Esto podría crear problemas de codificación cobardes en el camino. Siempre se puede especificar la codificación, pero appliation / xml tiene un defecto de codificación UTF-8.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top