2011-01-16 82 views
5

如果我们使用Spring MVC开发REST,它将支持XML和JSON数据。我在Spring配置豆app-servlet.xmlSpring REST 3支持XML和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> 

我的春天REST控制器写道ContentNegotiationViewResorver是:

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

我设置@XStreamAlias("customer")标注在我的客户领域类。 但是,当我尝试访问http://localhost:8080/rest/customers/teddy.xml它总是响应JSON数据。

我在我的客户域类中设置了@XmlRootElement(name="customer")注释。 但是,当我尝试访问http://localhost:8080/rest/customers/teddy.json它总是响应XML数据。

有什么不对吗?

+0

凡在控制器应用程序/客户/ teddy.xml映射? – chris

+0

对不起..网址是:/rest/customers/teddy.xml,这个网址应该调用showCustomer方法。而泰迪是{id}参数。 –

+0

你如何访问该URL?网页浏览器?您是否在请求中发送适当的内容类型编码标头? – skaffman

回答

2

我认为“xml”内容类型应该映射到“text/xml”而不是“application/xml”。此外,要强制基于扩展名的内容类型解析器,可以尝试将“ContentNegotiatingViewResolver”的“favorPathExtension”属性设置为true(尽管默认情况下它应该是true)。

编辑:我现在已经添加了一个工作在此GIT位置采样 - git://github.com/bijukunjummen/mvc-samples.git,如果调出端点,使用mvn tomcat:run,则json将在http://localhost:8080/mvc-samples/rest/customers/teddy.json处提供,xml位于http://localhost:8080/mvc-samples/rest/customers/teddy.xml处。这使用JAXB2而不是XStream,因为我熟悉JAXB。我注意到的一件事是,当我的JAXB注释在Customer类中不正确时,Spring按照您看到的方式提供JSON而不是XML(您可以通过从Customer类删除XMLRootElement注释来复制它),一旦我修复了我的注释,我按预期收回了XML。 所以可能是因为你的XStream配置有问题。

编辑2:你是对的!我没有注意到,一旦我回到xml,我认为json现在在工作。我看到这个问题,在AnnotationMethodHandlerAdapter中,对@ResponseBody的处理有点奇怪,它完全忽略了ViewResolvers,并且使用注册的MessageConverters而不是完全绕过ContentNegotiatingViewResolver,现在的一种解决方法是使用@ModelAttribute注释作为响应,而不是@ResponseBody ,这就是Resolvers正在调用的视图。现在尝试使用[email protected]:bijukunjummen/mvc-samples.git的项目,看看它是否适合你。这可能是Spring的一个bug,你可以尝试在Spring论坛中提出来,看看他们推荐什么。

+0

我已经将内容类型更改为text/xml和text/json。并将faforPathExtension设置为true。但我json的文本,而我访问应用程序/休息/客户/ teddy.xml –

+0

不确定@adisembiring,我试着用JAXB2和它的工作没有问题 - 我已经在这个位置的示例 - git://github.com/ bijukunjummen/mvc-samples.git,它在 /rest/customers/teddy.json和xml在rest/customers/teddy.xml处正确地提供json。 –

+0

我已经运行你的项目,试着使用'firefox','chrome'和'poster firefox plugin'来访问应用程序。但是在访问'rest/customers/teddy.json'的时候我得到'xml'的值。您可以在http://i52.tinypic.com/29hb4j.jpg –

1

我有同样的问题。我假设你使用的是Spring 3,并且已经使用了<mvc:annotation-driven/>。我不完全确定,但我认为这会根据mvc命名空间配置的消息转换器产生一些冲突。

使用OXM命名为我工作:

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

内容配置(MVC和内部视图解析器是在另一种情况下):

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

此示例使用JAXB,所以你需要jaxb-api和jaxb-impl在classpath上。

此外,只是一个提示,你不需要app-servlet.xml。在你的网上。xml,将配置设置为空,并让上下文侦听器为您加载它们:

<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

什么Accept标头发送到您的服务器? 确保您想要请求的内容类型在此列表中。

+0

当我在域类中添加@XmlRootElement注释时,服务器返回xml格式。当我添加@XStreamAlias注释时,服务器返回JSON格式。我认为服务器接受xml和json。 –

0

使用浏览器访问控制器将发送一个典型的浏览器Accept头。它不会匹配任何视图解析器并且默认第一个(application/xml),或者它匹配,因为application/xml位于Accept列表中。

我可以推荐使用RestClient http://code.google.com/p/rest-client/来完全控制要发送的Accept头(如果有的话)。

我不推荐使用text/xml作为默认字符集是US-ASCII而不是UTF-8。这可能会在路上产生时髦的编码问题。您始终可以指定编码,但appliation/xml具有UTF-8默认编码。

1

嗯,我得到了一个解决方案,但我不知道,如果它在你的方法显示客户的正确方法:

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

在这一部分,我们使用Spring的MVC和控制器,我们应该是返回一个视图,所以我删除了注释@ResponseBody,并返回了一个String的视图名称,因为在我们的XML中我们添加了ContentNegotiatingViewResolver,并且当我们有ResponseBody时,contentnegociationviewresolver被忽略,因为正在等待视图,但我们返回了该对象该方法应该是这样的:

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

也为我的作品,如果你有问题,你可以添加到您的app-servlet.xml

这个bean,但我不认为你必须添加此。

<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