2011-01-16 119 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