Перейти к основному содержимому

Spring Согласование содержимого MVC

· 6 мин. чтения

1. Обзор

В этой статье описывается, как реализовать согласование содержимого в проекте Spring MVC.

Как правило, существует три варианта определения типа носителя запроса:

  • (Устарело) Использование суффиксов URL (расширений) в запросе (например , .xml/.json )
  • Использование параметра URL в запросе (например , ?format=json )
  • Использование заголовка Accept в запросе

По умолчанию это порядок, в котором менеджер согласования содержимого Spring попытается использовать эти три стратегии. И если ни один из них не включен, мы можем указать откат к типу контента по умолчанию.

2. Стратегии обсуждения контента

Начнем с необходимых зависимостей — мы работаем с представлениями JSON и XML, поэтому в этой статье мы будем использовать Jackson для JSON:

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.10.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.2</version>
</dependency>

Для поддержки XML мы можем использовать либо JAXB, XStream, либо более новую поддержку Jackson-XML.

Поскольку мы объяснили использование заголовка Accept в более ранней статье о HttpMessageConverters , давайте подробно сосредоточимся на первых двух стратегиях.

3. Стратегия суффиксов URL

В версии Spring Boot 2.6.x стратегия по умолчанию для сопоставления путей запросов с зарегистрированными сопоставлениями обработчиков Spring MVC изменилась с

AntPathMatcher

на

PathPatternParser

.

А поскольку сопоставление шаблонов суффиксов не поддерживается PathPatternParser, нам сначала нужно использовать устаревшее средство сопоставления путей, прежде чем использовать эту стратегию.

Мы можем добавить spring.mvc.pathmatch.matching-strategy в файл application.properties, чтобы вернуть значение по умолчанию на

AntPathMatcher

.

По умолчанию эта стратегия отключена, нам нужно включить ее, установив

spring.mvc.pathmatch.use-suffix-pattern

значение true в application.properties:

spring.mvc.pathmatch.use-suffix-pattern=true
spring.mvc.pathmatch.matching-strategy=ant-path-matcher

После включения платформа может проверять расширение пути прямо из URL-адреса, чтобы определить тип выходного контента.

Прежде чем перейти к конфигурациям, давайте быстро рассмотрим пример. У нас есть следующая простая реализация метода API в типичном контроллере Spring:

@RequestMapping(
value = "/employee/{id}",
produces = { "application/json", "application/xml" },
method = RequestMethod.GET)
public @ResponseBody Employee getEmployeeById(@PathVariable long id) {
return employeeMap.get(id);
}

Давайте вызовем его, используя расширение JSON, чтобы указать медиа-тип ресурса:

curl http://localhost:8080/spring-mvc-basics/employee/10.json

Вот что мы можем получить, если воспользуемся расширением JSON:

{
"id": 10,
"name": "Test Employee",
"contactNumber": "999-999-9999"
}

А вот как будет выглядеть запрос-ответ с XML:

curl http://localhost:8080/spring-mvc-basics/employee/10.xml

Тело ответа:

<employee>
<contactNumber>999-999-9999</contactNumber>
<id>10</id>
<name>Test Employee</name>
</employee>

Теперь, если мы не используем какое-либо расширение или используем то, которое не настроено, будет возвращен тип контента по умолчанию:

curl http://localhost:8080/spring-mvc-basics/employee/10

Давайте теперь посмотрим на настройку этой стратегии — с конфигурациями Java и XML.

3.1. Конфигурация Java

public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(true).
favorParameter(false).
ignoreAcceptHeader(true).
useJaf(false).
defaultContentType(MediaType.APPLICATION_JSON);
}

Давайте рассмотрим детали.

Во-первых, мы включаем стратегию расширения пути. Также стоит упомянуть, что в Spring Framework 5.2.4 метод FavorPathExtension(boolean) устарел, чтобы не поощрять использование расширений пути для согласования содержимого.

Затем мы отключаем стратегию параметра URL, а также стратегию заголовка Accept , потому что мы хотим полагаться только на способ расширения пути для определения типа контента.

Затем мы отключаем Java Activation Framework; JAF можно использовать в качестве резервного механизма для выбора выходного формата, если входящий запрос не соответствует ни одной из настроенных нами стратегий. Мы отключаем его, потому что собираемся настроить JSON в качестве типа контента по умолчанию. Обратите внимание, что метод useJaf() устарел, начиная с Spring Framework 5 .

И, наконец, мы настраиваем JSON по умолчанию. Это означает, что если ни одна из двух стратегий не соответствует, все входящие запросы будут сопоставлены с методом контроллера, который обслуживает JSON.

3.2. XML-конфигурация

Давайте также взглянем на точно такую же конфигурацию, только используя XML:

<bean id="contentNegotiationManager" 
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="true" />
<property name="favorParameter" value="false"/>
<property name="ignoreAcceptHeader" value="true" />
<property name="defaultContentType" value="application/json" />
<property name="useJaf" value="false" />
</bean>

4. Стратегия параметров URL

Мы использовали расширения пути в предыдущем разделе — теперь давайте настроим Spring MVC для использования параметра пути.

Мы можем включить эту стратегию, установив для свойства FavorParameter значение true.

Давайте быстро посмотрим, как это будет работать с нашим предыдущим примером:

curl http://localhost:8080/spring-mvc-basics/employee/10?mediaType=json

И вот каким будет тело ответа JSON:

{
"id": 10,
"name": "Test Employee",
"contactNumber": "999-999-9999"
}

Если мы используем параметр XML, вывод будет в формате XML:

curl http://localhost:8080/spring-mvc-basics/employee/10?mediaType=xml

Тело ответа:

<employee>
<contactNumber>999-999-9999</contactNumber>
<id>10</id>
<name>Test Employee</name>
</employee>

Теперь займемся настройкой — опять же, сначала с помощью Java, а затем XML.

4.1. Конфигурация Java

public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false).
favorParameter(true).
parameterName("mediaType").
ignoreAcceptHeader(true).
useJaf(false).
defaultContentType(MediaType.APPLICATION_JSON).
mediaType("xml", MediaType.APPLICATION_XML).
mediaType("json", MediaType.APPLICATION_JSON);
}

Давайте прочитаем эту конфигурацию.

Во-первых, конечно, расширение пути и стратегии заголовка Accept отключены (как и JAF).

В остальном конфигурация такая же.

4.2. XML-конфигурация

<bean id="contentNegotiationManager" 
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false" />
<property name="favorParameter" value="true"/>
<property name="parameterName" value="mediaType"/>
<property name="ignoreAcceptHeader" value="true" />
<property name="defaultContentType" value="application/json" />
<property name="useJaf" value="false" />

<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</property>
</bean>

Кроме того, мы можем включить обе стратегии (расширение и параметр) одновременно:

public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(true).
favorParameter(true).
parameterName("mediaType").
ignoreAcceptHeader(true).
useJaf(false).
defaultContentType(MediaType.APPLICATION_JSON).
mediaType("xml", MediaType.APPLICATION_XML).
mediaType("json", MediaType.APPLICATION_JSON);
}

В этом случае Spring сначала будет искать расширение пути, если его нет, то будет искать параметр пути. И если оба они недоступны во входном запросе, то тип контента по умолчанию будет возвращен обратно.

5. Стратегия принятия заголовка

Если заголовок Accept включен, Spring MVC будет искать его значение во входящем запросе, чтобы определить тип представления.

Мы должны установить значение ignoreAcceptHeader в false, чтобы включить этот подход, и мы отключаем две другие стратегии только для того, чтобы знать, что мы полагаемся только на заголовок Accept .

5.1. Конфигурация Java

public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(true).
favorParameter(false).
parameterName("mediaType").
ignoreAcceptHeader(false).
useJaf(false).
defaultContentType(MediaType.APPLICATION_JSON).
mediaType("xml", MediaType.APPLICATION_XML).
mediaType("json", MediaType.APPLICATION_JSON);
}

5.2. XML-конфигурация

<bean id="contentNegotiationManager" 
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="true" />
<property name="favorParameter" value="false"/>
<property name="parameterName" value="mediaType"/>
<property name="ignoreAcceptHeader" value="false" />
<property name="defaultContentType" value="application/json" />
<property name="useJaf" value="false" />

<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</property>
</bean>

Наконец, нам нужно включить менеджер согласования контента, подключив его к общей конфигурации:

<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />

6. Заключение

И мы закончили. Мы рассмотрели, как согласование контента работает в Spring MVC, и сосредоточились на нескольких примерах его настройки для использования различных стратегий для определения типа контента.

Полную реализацию этой статьи можно найти на GitHub .