知識庫 / Spring / Spring MVC RSS 訂閱

Spring MVC 內容協商

REST,Spring MVC
HongKong
6
03:59 AM · Dec 06 ,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請求頭的用法,讓我們深入探討前兩個策略。

3. URL 後綴策略

在 Spring Boot 2.6.x 版本中,請求路徑與註冊的 Spring MVC 處理器映射進行匹配的默認策略已從 AntPathMatcher 變為 PathPatternParser

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

可以通過在 application.properties 文件中添加 spring.mvc.pathmatch.matching-strategy 來將默認值切換回 AntPathMatcher

默認情況下,此策略已禁用,需要通過在 application.properties 文件中將 spring.mvc.pathmatch.use-suffix-pattern 設置為 true 來啓用它:

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

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

最後——我們將 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 以利用 URL 參數。

通過將 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 標頭策略

如果啓用了 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.