XMLとJSONをサポートするスプリングレスト3
-
11-10-2019 - |
質問
Spring MVCを使用してRESTを開発すると、XMLおよびJSONデータがサポートされます。 Spring Config BeanでContentNegotiationViewResorverを書きました 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>
そして、私のスプリングレストコントローラーは次のとおりです。
@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データに応答します。
間違ったことはありますか?
解決
「XML」コンテンツタイプは、「アプリケーション/XML」から「テキスト/XML」にマッピングする必要があると思います。また、拡張機能に基づいてコンテンツタイプのリゾルバーを強制するには、「ContentNegotiatingViewResolver」の「favepathextension」プロパティをtrueに設定することを試みることができます(デフォルトでは真であるはずです!)
編集:このgitの場所で作業サンプルを追加しました - git://github.com/bijukunjummen/mvc-samples.git
, 、MVN Tomcat:Runを使用して、エンドポイントを掲載する場合、JSONはで提供されます http://localhost:8080/mvc-samples/rest/customers/teddy.json
およびxml at http://localhost:8080/mvc-samples/rest/customers/teddy.xml
. 。 JaxBに精通しているため、これはXStreamではなくJaxB2を使用します。私が気づいたことの1つは、jaxBアノテーションが顧客クラスで正しくなかったとき、SpringはJSONを提供していなかったことであり、XMLを見た方法ではありませんでした(顧客クラスからXMLRootelementアノテーションを削除することで複製できます)。注釈、私は予想どおりXMLを取り戻しました。 したがって、Xstream構成に何か問題がある可能性があります。
編集2:あなたは正しいです!! XMLに戻ったら、JSONが今働いていると思いました。私は問題を見ます AnnotationMethodHandlerAdapter
, 、のハンドリング @ResponseBody
少し奇妙で、viewResolversを完全に無視し、登録されたMessageConvertersを使用します。 ContentNegotiatingViewResolver
, 、今のところ1つの回避策は使用することです @ModelAttribute
@responsebodyの代わりに、応答のための注釈、この方法でビューリゾルバーが呼び出されています。でプロジェクトを使用して今すぐ試してみてください git@github.com:bijukunjummen/mvc-samples.git
そして、それがあなたのために働くかどうかを確認してください。これは春のバグかもしれません。春のフォーラムでそれを持ち上げて、彼らが推奨するものを見ることができます。
他のヒント
ヘッダーがサーバーに送信されるのは何ですか?要求するコンテンツタイプがこのリストにあることを確認してください。
春3.1は、新しいものを使用して言及する問題を解決します produces
の要素 @RequestMapping
注釈。これにより、制御できます HttpMessageConverter
その春はあなたのオブジェクトに当てはまります。
私はそれについてブログ投稿を書きました:
同じ問題がありました。私はあなたが春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が必要です。
また、ヒントだけで、app-servlet.xmlは必要ありません。 web.xmlで、構成をNULLに設定し、コンテキストリスナーにそれらをロードさせます。
<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>
まあ私は解決策を手に入れましたが、それがあなたのメソッドショーの顧客の正しい方法であるかどうかはわかりません:
@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
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
Browswerを使用してコントローラーにアクセスすると、典型的なブラウザAcceptヘッダーが送信されます。ビューのリゾルバーと一致せず、デフォルトで最初のもの(アプリケーション/XML)にデフォルトまたはそれが一致します。
RestClientを使用することをお勧めします http://code.google.com/p/rest-client/ ヘッダーを受け入れるもの(まったくあれば)を送信したいものを完全に制御するため。
デフォルトの文字セットはUS-ASCIIであり、UTF-8ではなく、テキスト/XMLを使用することはお勧めしません。これにより、ファンキーなエンコードの問題が発生する可能性があります。いつでもエンコードを指定できますが、Appliation/XMLにはUTF-8デフォルトのエンコードがあります。