Spring Rest 3, чтобы поддержать XML и JSON
-
11-10-2019 - |
Вопрос
Если мы разрабатываем отдых с помощью Spring MVC, он будет поддерживать данные XML и JSON. Я написал ContentNegotiationViewResorver в моей пружине Bean 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» не для «приложения/xml». Кроме того, чтобы заставить разрешения типа контента на основе расширения, вы можете попытаться установить свойство «FavorPateExtension» для «ContentNegotiationViewResolver» 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 были не правильными в классе клиентов, Spring служил JSON, а не XML, как вы его видели (вы можете повторить его, удалив аннотацию XMLROOTELEMER из класса клиента), после того, как я исправил свой Аннотации, я вернулся XML, как и ожидалось. Так что может случиться так, что с вашей конфигурацией Xstream что -то не так.
РЕДАКТИРОВАТЬ 2: Вы правы !! Я не заметил, как только я вернулся XML, я предположил, что JSON работает сейчас. Я вижу проблему, в AnnotationMethodHandlerAdapter
, обработка для @ResponseBody
немного странно, он полностью игнорирует ViewReSolvers и использует зарегистрированные MessageConverters вместо этого полностью обходные ContentNegotiatingViewResolver
, один обходной путь на данный момент - использовать @ModelAttribute
Аннотация для ответа, вместо @Responsebody, таким образом, что резолюры вида вызываются. Попробуйте сейчас использовать проект в git@github.com:bijukunjummen/mvc-samples.git
И посмотрим, работает ли это для вас. Это может быть весенняя ошибка, вы можете попытаться поднять его на весеннем форуме и посмотреть, что они рекомендуют.
Другие советы
Что заголовки принятия отправляются на ваш сервер? Убедитесь, что тип контента, который вы хотели бы запросить, находится в этом списке.
Весна 3.1 решает проблему, которую вы упоминаете, используя новую produces
элемент на @RequestMapping
аннотация. Это позволяет вам контролировать HttpMessageConverter
Эта весна относится к вашему объекту.
Я написал сообщение об этом в блоге:
У меня такая же проблема. Я полагаю, вы используете 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 на классе.
Кроме того, просто совет, вам не нужен приложение-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
Контент tegociationViewResolver игнорируется, потому что ждет представление, но мы вернули объект, чтобы метод был таким:
@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>
Доступ к контроллеру с помощью брейс -заседания отправит типичный заголовок принятия браузера. Он не будет соответствовать ни одному представлению, и по умолчанию с первым (Application/XML) или соответствует, потому что Application/XML находится в списке приема.
Я могу рекомендовать использовать RestClient http://code.google.com/p/rest-client/ Чтобы получить полный контроль над тем, что принять заголовок (если один вообще) вы хотите отправить.
Я не рекомендую использовать Text/XML в качестве набора символов по умолчанию US-ASCII, а не UTF-8. Это может создать забавные проблемы кодирования в будущем. Вы всегда можете указать кодирование, но приложение/XML имеет кодирование UTF-8 по умолчанию.