Frage

Wenn wir REST mit Spring MVC entwickeln, wird es XML und JSON-Daten unterstützen. Ich habe geschrieben ContentNegotiationViewResorver in meiner Feder Config bean app-servlet.xml

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

Und meine Feder REST-Controller ist:

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

setze ich @XStreamAlias("customer") Anmerkung in meiner Kunden-Domain-Klasse. Aber wenn ich versuche, den Zugang http://localhost:8080/rest/customers/teddy.xml es immer Antwort JSON-Daten.

setze ich @XmlRootElement(name="customer") Anmerkung in meiner Kunden-Domain-Klasse. Aber wenn ich versuche den Zugriff http://localhost:8080/rest/customers/teddy.json es immer Antwort XML-Daten.

Gibt es etwas, was nicht in Ordnung?

War es hilfreich?

Lösung

Ich denke, "xml" Inhaltstyp sollte auf "text / xml" abgebildet werden nicht zu "application / xml". Auch auf Inhaltstyp Resolver auf Erweiterung basiert zu erzwingen, können Sie versuchen, die „favorPathExtension“ Eigenschaft „ContentNegotiatingViewResolver“ auf true gesetzt (obwohl es standardmäßig wahr sein sollte!)

EDIT: Ich habe jetzt eine Arbeitsprobe an diesem GIT Standort hinzugefügt - git://github.com/bijukunjummen/mvc-samples.git, wenn Sie den Endpunkt bringen, mit mvn tomcat: laufen, die json bei http://localhost:8080/mvc-samples/rest/customers/teddy.json und xml bei http://localhost:8080/mvc-samples/rest/customers/teddy.xml serviert werden. Diese nutzt JAXB2 nicht XStream, wie ich mit JAXB vertraut bin. Eine Sache, die ich bemerkte, war, dass, wenn meine JAXB Annotationen nicht in Customer-Klasse korrekt waren, Frühling bediente aus JSON und XML nicht so, wie Sie es sah (Sie können es replizieren, indem Sie die XMLRootElement Annotation von Customer-Klasse entfernen), sobald ich fixiert auf meine Anmerkungen habe ich XML zurück, wie erwartet. So könnte es sein, dass es etwas falsch mit Ihrer XStream Konfiguration ist.

EDIT 2: Sie sind recht !! Ich habe nicht bemerkt, wenn ich zurück xml bekam, nahm ich an, dass json arbeitet jetzt. Ich sehe das Problem, in AnnotationMethodHandlerAdapter, die Handhabung für @ResponseBody ein wenig seltsam ist, ignoriert vollständig die ViewResolvers und nutzt die registrierten MessageConverters stattdessen vollständig ContentNegotiatingViewResolver Umgehung, eine Abhilfe für jetzt ist @ModelAttribute Anmerkung für die Antwort zu verwenden, statt @ResponseBody , auf diese Weise die Ansicht Auflöser werden immer genannt. Versuchen Sie jetzt das Projekt bei git@github.com:bijukunjummen/mvc-samples.git und sehen, ob es für Sie arbeitet. Dies könnte einen Frühling Bug sein, können Sie versuchen, und bringen es im Frühjahr Forum und sehen, was sie empfehlen.

Andere Tipps

Was sind Accept-Header an den Server gesendet? Stellen Sie sicher, dass der Inhaltstyp Sie auf Anfrage gerne würde, ist in dieser Liste.

Frühling 3.1 löst das Problem, das Sie das neue produces Element auf der @RequestMapping Anmerkung mit erwähnen. Dadurch können Sie die HttpMessageConverter steuern, dass Frühling zu Ihrem Objekt gilt.

Ich schrieb einen Blog-Post über sie:

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

Ich hatte das gleiche Problem. Ich nehme an, Sie mit Spring 3 und Sie haben verwendet <mvc:annotation-driven/>. Ich bin nicht ganz sicher, aber ich denke, das einige Konflikte auf dem Nachrichtenwandler basierend erstellt, dass die mvc Namespace konfiguriert.

Mit dem OXM Namespace für mich gearbeitet:

@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-Konfiguration (mvc und Innenansicht Resolver in einem anderen Kontext ist):

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

In diesem Beispiel wird JAXB, so dass Sie jaxb-api und jaxb-impl auf dem Classpath bräuchten.

Auch nur ein Tipp, Sie brauchen nicht auf die App-servlet.xml. In Ihrem web.xml, stellen Sie die Config auf null und lassen Sie die Context Listener Last sie für Sie:

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

got Nun ich eine Lösung, aber ich weiß nicht, ob es der richtige Weg ist in Ihrer Methode Show Kunde:

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

In diesem Teil verwenden wir MVC des Frühlings und in der Steuerung sollten wir eine Ansicht zurückkehren, so dass ich die Anmerkung @ResponseBody entfernt und ich wieder ein String mit dem Namen der Ansicht, weil in unserer XML wir eine ContentNegotiatingViewResolver hinzugefügt und wenn wir ResponseBody haben die contentnegociationviewresolver ignoriert, da für eine waiting aber wir wieder das Objekt so das Verfahren so sein sollte:

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

gut das funktioniert für mich, wenn Sie Probleme haben Sie zu Ihrem app-servlet.xml hinzufügen

diese Bohne, aber ich glaube nicht, dass Sie diese hinzufügen müssen.

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

Ich habe die Antworten von mkyong.com

Zugriff auf den Controller eine browswer verwendet, wird ein typischer Browser Accept-Header senden. Es wird nicht auf den ersten (application / xml) oder sie paßt zu jeder Ansicht Resolver und Standard überein, da application / xml in der Liste übernehmen ist.

Ich kann mit empfehlen RestClient http://code.google.com/p/rest- Client / vollständige Kontrolle darüber haben, was Accept-Header (wenn man überhaupt) Sie senden möchten.

Ich empfehle, nicht text / xml als Standardzeichensatz ist US-ASCII und nicht UTF-8. Dies könnte flippige Codierung Probleme auf dem Weg schaffen. Sie können jederzeit die Codierung angeben, aber appliation / xml hat eine UTF-8-Standard-Kodierung.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top