春季休息3支持XML和JSON
-
11-10-2019 - |
题
如果我们使用Spring MVC开发休息,它将支持XML和JSON数据。我在春季config bean中写了contentnogotiationViewResorver 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”内容类型应映射到“ text/xml”,而不是“ application/xml”。另外,要根据扩展名强制内容类型解析器,您可以尝试将“ contentNegotiatingViewResolver”的“ forpathextension”属性设置为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的JAXB2而不是Xstream。我注意到的一件事是,当我的JAXB注释在客户课程中不正确时,Spring会提供JSON而不是您看到的XML(您可以通过从客户类中删除XMLrootelement注释来复制它)注释,我按预期获得了XML。 因此,您的Xstream配置可能有问题。
编辑2:你是对的!我没有注意到,一旦我回来了XML,我以为JSON现在正在工作。我看到问题,在 AnnotationMethodHandlerAdapter
, ,处理 @ResponseBody
有点奇怪,它完全忽略了View Relsolvers,并使用注册的MessageConverter,而是完全绕过 ContentNegotiatingViewResolver
, ,现在有一个解决方法是使用 @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;
}
在这一部分中,我们使用的是弹簧的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访问控制器将发送典型的浏览器接受标头。它将不匹配任何视图解析器,默认值与第一个(Application/XML)或它匹配,因为Application/XML在ACCEPT列表中。
我可以建议使用restclient http://code.google.com/p/rest-client/ 要完全控制您要发送的接受标头(如果有的话)。
我不建议将文本/XML用作默认字符集为us-ascii,而不是UTF-8。这可能会引起时髦的编码问题。您始终可以指定编码,但是Appliation/XML具有UTF-8默认编码。