Spring MVC 內容協商

REST,Spring MVC
Remote
1
04:29 PM · Dec 01 ,2025

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.17.2</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.17.2</version>
</dependency>

對於 XML 支持,我們可以使用 JAXB、XStream 或較新的 Jackson-XML 支持。

由於我們在先前關於 HttpMessageConverters 的文章中已經解釋了 Accept 請求頭的用法,讓我們深入研究這兩種策略。

,而非

由於後綴模式匹配不支持 PathPatternParser,因此首先需要使用遺留路徑匹配器,然後再使用該策略。

可以通過在 application.properties 文件中添加 ,將默認策略切換回

默認情況下,此策略已禁用,需要通過在 application.properties 中設置 來啓用它:

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

啓用後,框架可以從 URL 中檢查路徑擴展名,以確定輸出內容類型。

在進行配置之前,讓我們先查看一個示例。我們有一個典型的 Spring 控制器中簡單的 API 方法實現:

@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 配置。

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

讓我們過一遍細節。

首先,我們啓用了路徑擴展策略。 此外,值得注意的是,自 Spring Framework 5.2.4 版本起,為了不鼓勵使用路徑擴展進行內容協商, 方法已棄用。

然後,我們還禁用了 URL 參數策略以及 頭部策略——因為我們只想依賴路徑擴展方式來確定內容類型。

我們關閉了 Java 激活框架;JAF 可用作備用機制來選擇輸出格式,如果傳入請求不匹配我們配置的任何策略,則可以用來選擇輸出格式。我們關閉了它,因為我們將 JSON 設置為默認內容類型。請注意, 方法自 Spring Framework 5 版本起已棄用。

最後——我們設置 JSON 為默認值。這意味着如果未匹配任何兩個策略,所有傳入請求都將映射到提供 JSON 內容的控制器方法。

讓我們也快速查看相同的配置,僅使用 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. The URL Parameter Strategy

我們之前在上一部分中使用了路徑擴展 – 現在讓我們設置 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 Configuration

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 Configuration

<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) 策略

如果接受請求頭 (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 中內容協商的工作方式,並重點介紹瞭如何設置各種策略以確定內容類型。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.