Question

Si nous développons REST en utilisant Spring MVC, il soutiendra les données XML et JSON. Je l'ai écrit dans mon ContentNegotiationViewResorver haricot config printemps 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>

Et mon ressort REST Controller est:

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

Je mis l'annotation @XStreamAlias("customer") dans ma classe de domaine du client. Mais lorsque je tente un accès http://localhost:8080/rest/customers/teddy.xml il toujours la réponse des données JSON.

Je mis l'annotation @XmlRootElement(name="customer") dans ma classe de domaine du client. Mais lorsque je tente un accès http://localhost:8080/rest/customers/teddy.json il toujours des données XML de réponse.

Y at-il une chose mal?

Était-ce utile?

La solution

Je pense que "xml" type de contenu doit être mis en correspondance avec "text / xml" ne pas "application / xml". En outre, pour forcer type de contenu résolveurs basé sur l'extension, vous pouvez essayer de définir la propriété « favorPathExtension » de « ContentNegotiatingViewResolver » true (bien qu'il aurait été vrai par défaut!)

EDIT: J'ai maintenant ajouté un échantillon de travail à cet endroit GIT - git://github.com/bijukunjummen/mvc-samples.git, si vous apportez le point final, en utilisant mvn tomcat: exécution, le JSON est servi à http://localhost:8080/mvc-samples/rest/customers/teddy.json et xml à http://localhost:8080/mvc-samples/rest/customers/teddy.xml. Cette utilisation ne jaxb2 XStream, comme je suis familier avec JAXB. Une chose que je remarqué est que lorsque mes annotations JAXB n'étaient pas correctes dans la classe client, Spring purgeait JSON et non XML comme vous l'avez vu (Vous pouvez le reproduire en supprimant l'annotation XMLRootElement de la classe client), une fois que je fixe mon annotations, je me suis de retour XML comme prévu. Il pourrait être qu'il ya quelque chose de mal avec votre configuration XStream.

EDIT 2: Vous avez raison !! Je n'ai pas remarqué, une fois que je suis de retour xml, je suppose que JSON travaille actuellement. Je vois le problème, dans AnnotationMethodHandlerAdapter, la manipulation des @ResponseBody est un peu étrange, il ignore complètement les ViewResolvers, et utilise les MessageConverters enregistrés à la place sans passer complètement le ContentNegotiatingViewResolver, une solution de contournement pour est maintenant d'utiliser l'annotation @ModelAttribute pour la réponse, au lieu de @ResponseBody , de cette façon les résolveurs vue OBTIENNENT appelé. Essayez d'utiliser maintenant le projet à git@github.com:bijukunjummen/mvc-samples.git et voir si cela fonctionne pour vous. Cela pourrait être un bug Spring, vous pouvez essayer de le mettre dans le forum printemps et voir ce qu'ils recommandent.

Autres conseils

Qu'est-ce en-têtes Accept sont envoyés à votre serveur? Assurez-vous que le type de contenu que vous souhaitez à la demande est dans cette liste.

Spring 3.1 permet de résoudre le problème que vous mentionnez en utilisant le nouvel élément produces sur l'annotation @RequestMapping. Cela vous permet de contrôler le HttpMessageConverter que le printemps s'applique à votre objet.

J'ai écrit un billet de blog à ce sujet:

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

J'ai eu le même problème. Je suppose que vous utilisez Spring 3 et vous avez utilisé <mvc:annotation-driven/>. Je ne suis pas tout à fait sûr, mais je pense que cela crée un conflit basé sur les convertisseurs de message que l'espace de noms mvc configure.

Utilisation de l'espace de noms OXM a fonctionné pour moi:

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

Configuration de contenu (mvc de vue interne et résolveur sont dans un autre contexte):

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

Cet exemple utilise JAXB, de sorte que vous auriez besoin JAXB-api et JAXB-impl sur le chemin de classe.

En outre, juste une astuce, vous ne pas besoin de l'app-servlet.xml. Dans votre web.xml, définissez la configuration null et laissez la charge Contexte Listener les pour vous:

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

Eh bien, je suis une solution mais je ne sais pas si c'est la bonne façon dans votre client show méthode:

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

Dans cette partie, nous utilisons MVC du printemps et dans le contrôleur, nous devrions être retourner une vue, alors j'ai enlevé la @ResponseBody d'annotation et je renvoie un String avec le nom de la vue parce que dans notre XML, nous avons ajouté un ContentNegotiatingViewResolver et quand nous avons ResponseBody la contentnegociationviewresolver est ignorée car est en attente d'une vue, mais nous sommes revenus l'objet de sorte que la méthode doit être comme ça:

@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 fonctionne pour moi, si vous avez des problèmes, vous pouvez ajouter à votre app-servlet.xml

ce haricot, mais je ne pense pas que vous devez ajouter ceci.

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

Je suis les réponses de mkyong.com

Accès au contrôleur à l'aide d'un browswer envoie un navigateur typique tête Accept. Il ne correspond à aucun résolveur de vue et par défaut à la première (application / xml) ou il correspond parce que l'application / xml est dans la liste Accepter.

Je recommande d'utiliser RESTClient http://code.google.com/p/rest- client / d'avoir un contrôle complet sur ce que tête Accept (si une) que vous souhaitez envoyer.

Je ne recommande pas d'utiliser text / xml comme le jeu de caractères par défaut est US-ASCII et non UTF-8. Cela peut créer des problèmes d'encodage géniaux sur la route. Vous pouvez toujours spécifier l'encodage mais appliation / xml a un encodage par défaut UTF-8.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top