Spring MVC
Spring Boot 有許多 starter 包含了 Spring MVC。請注意,有些 starter 包含對 Spring MVC 的依賴,而不是直接包含它。本節回答關於 Spring MVC 和 Spring Boot 的常見問題。
撰寫 JSON REST 服務
Spring Boot 應用程式中的任何 Spring @RestController
預設應呈現 JSON 回應,只要 classpath 上有 Jackson2 即可,如下例所示
-
Java
-
Kotlin
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@RequestMapping("/thing")
public MyThing thing() {
return new MyThing();
}
}
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
@RestController
class MyController {
@RequestMapping("/thing")
fun thing(): MyThing {
return MyThing()
}
}
只要 MyThing
可以被 Jackson2 序列化(對於一般的 POJO 或 Groovy 物件來說是如此),那麼 localhost:8080/thing
就會預設提供它的 JSON 表示。請注意,在瀏覽器中,您有時可能會看到 XML 回應,因為瀏覽器傾向於發送偏好 XML 的 accept header。
撰寫 XML REST 服務
如果您的 classpath 上有 Jackson XML 擴充功能 (jackson-dataformat-xml
),您可以使用它來呈現 XML 回應。我們用於 JSON 的前一個範例也可以運作。若要使用 Jackson XML 渲染器,請將以下依賴項新增至您的專案
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
如果 Jackson 的 XML 擴充功能不可用且 JAXB 可用,則可以使用 XML 進行渲染,但需要額外將 MyThing
註解為 @XmlRootElement
,如下例所示
-
Java
-
Kotlin
import jakarta.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class MyThing {
private String name;
// getters/setters ...
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
import jakarta.xml.bind.annotation.XmlRootElement
@XmlRootElement
class MyThing {
var name: String? = null
}
您需要確保 JAXB 函式庫是您專案的一部分,例如透過新增
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
</dependency>
為了讓伺服器渲染 XML 而不是 JSON,您可能需要發送 Accept: text/xml header(或使用瀏覽器)。 |
自訂 Jackson ObjectMapper
Spring MVC(客戶端和伺服器端)使用 HttpMessageConverters
來協商 HTTP 交換中的內容轉換。如果 Jackson 在 classpath 上,您已經獲得了 Jackson2ObjectMapperBuilder
提供的預設轉換器,Jackson2ObjectMapperBuilder
的實例會為您自動組態。
ObjectMapper
(或 Jackson XML 轉換器的 XmlMapper
)實例(預設建立)具有以下自訂屬性
-
MapperFeature.DEFAULT_VIEW_INCLUSION
已停用 -
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
已停用 -
SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
已停用 -
SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS
已停用
Spring Boot 也有一些功能可以更輕鬆地自訂此行為。
您可以使用環境變數來組態 ObjectMapper
和 XmlMapper
實例。Jackson 提供了一套廣泛的 on/off 功能,可用於組態其處理的各個方面。這些功能在(Jackson 中的)幾個枚舉中描述,這些枚舉映射到環境變數中的屬性
枚舉 | 屬性 | 值 |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
例如,若要啟用美化列印,請設定 spring.jackson.serialization.indent_output=true
。請注意,由於使用了寬鬆綁定,indent_output
的大小寫不必與對應的枚舉常數 INDENT_OUTPUT
的大小寫相符。
此基於環境變數的組態適用於自動組態的 Jackson2ObjectMapperBuilder
bean,並適用於使用 builder 建立的任何 mapper,包括自動組態的 ObjectMapper
bean。
context 的 Jackson2ObjectMapperBuilder
可以透過一個或多個 Jackson2ObjectMapperBuilderCustomizer
beans 進行自訂。此類 customizer beans 可以排序(Boot 自己的 customizer 的順序為 0),允許在 Boot 自訂之前和之後都應用額外的自訂。
任何類型為 com.fasterxml.jackson.databind.Module
的 beans 都會自動註冊到自動組態的 Jackson2ObjectMapperBuilder
,並應用於它建立的任何 ObjectMapper
實例。當您向應用程式新增新功能時,這提供了一種全域機制來貢獻自訂模組。
如果您想要完全取代預設的 ObjectMapper
,請定義該類型的 @Bean
,或者,如果您喜歡基於 builder 的方法,請定義 Jackson2ObjectMapperBuilder
@Bean
。當定義 ObjectMapper
bean 時,建議將其標記為 @Primary
,因為它將取代的自動組態 ObjectMapper
是 @Primary
。請注意,在任何一種情況下,這樣做都會停用 ObjectMapper
的所有自動組態。
如果您提供任何類型為 MappingJackson2HttpMessageConverter
的 @Beans
,它們會取代 MVC 組態中的預設值。此外,還提供了一個方便的類型為 HttpMessageConverters
的 bean(如果您使用預設的 MVC 組態,則始終可用)。它有一些有用的方法可以存取預設和使用者增強的訊息轉換器。
請參閱自訂 @ResponseBody 渲染章節和 WebMvcAutoConfiguration
原始碼以取得更多詳細資訊。
自訂 @ResponseBody 渲染
Spring 使用 HttpMessageConverters
來渲染 @ResponseBody
(或來自 @RestController
的回應)。您可以透過在 Spring Boot context 中新增適當類型的 beans 來貢獻額外的轉換器。如果您新增的 bean 的類型原本就會預設包含(例如 JSON 轉換的 MappingJackson2HttpMessageConverter
),它會取代預設值。提供了一個方便的類型為 HttpMessageConverters
的 bean,如果您使用預設的 MVC 組態,則始終可用。它有一些有用的方法可以存取預設和使用者增強的訊息轉換器(例如,如果您想要手動將它們注入到自訂 RestTemplate
中,這可能會很有用)。
與正常的 MVC 用法一樣,您提供的任何 WebMvcConfigurer
beans 也可以透過覆寫 configureMessageConverters
方法來貢獻轉換器。但是,與正常的 MVC 不同,您只能提供您需要的額外轉換器(因為 Spring Boot 使用相同的機制來貢獻其預設值)。最後,如果您透過提供您自己的 @EnableWebMvc
組態來選擇退出預設的 Spring Boot MVC 組態,您可以完全掌控並使用來自 WebMvcConfigurationSupport
的 getMessageConverters
手動完成所有操作。
請參閱WebMvcAutoConfiguration
原始碼以取得更多詳細資訊。
處理 Multipart 檔案上傳
Spring Boot 採用 servlet 5 jakarta.servlet.http.Part
API 來支援上傳檔案。預設情況下,Spring Boot 將 Spring MVC 組態為每個檔案的最大大小為 1MB,單個請求中的檔案資料最大為 10MB。您可以使用 MultipartProperties
類別中公開的屬性來覆寫這些值、儲存中間資料的位置(例如,到 /tmp
目錄)以及將資料刷新到磁碟的閾值。例如,如果您想要指定檔案大小不受限制,請將 spring.servlet.multipart.max-file-size
屬性設定為 -1
。
當您想要在 Spring MVC 控制器處理方法中接收作為 MultipartFile
類型的 @RequestParam
註解參數的 multipart 編碼檔案資料時,multipart 支援非常有用。
請參閱 MultipartAutoConfiguration
原始碼以取得更多詳細資訊。
建議使用容器的內建 multipart 上傳支援,而不是引入額外的依賴項,例如 Apache Commons File Upload。 |
關閉 Spring MVC DispatcherServlet
預設情況下,所有內容都從應用程式的根目錄 (/
) 提供。如果您寧願映射到不同的路徑,您可以如下組態一個路徑
-
屬性
-
YAML
spring.mvc.servlet.path=/mypath
spring:
mvc:
servlet:
path: "/mypath"
如果您有其他 servlet,您可以為每個 servlet 宣告一個 Servlet
或 ServletRegistrationBean
類型的 @Bean
,Spring Boot 會將它們透明地註冊到容器中。由於 servlet 是以這種方式註冊的,因此它們可以映射到 DispatcherServlet
的子 context,而無需調用它。
自行組態 DispatcherServlet
是不尋常的,但如果您真的需要這樣做,也必須提供一個 DispatcherServletPath
類型的 @Bean
,以提供自訂 DispatcherServlet
的路徑。
自訂 ViewResolver
ViewResolver
是 Spring MVC 的核心組件,它將 @Controller
中的視圖名稱轉換為實際的 View
實作。請注意,ViewResolver
主要用於 UI 應用程式,而不是 REST 風格的服務(View
不用於渲染 @ResponseBody
)。有多種 ViewResolver
實作可供選擇,Spring 本身對於您應該使用哪種實作沒有既定的看法。另一方面,Spring Boot 會為您安裝一到兩個,具體取決於它在 classpath 和應用程式 context 中找到的內容。DispatcherServlet
使用它在應用程式 context 中找到的所有解析器,依序嘗試每個解析器,直到獲得結果。如果您新增自己的解析器,您必須注意順序以及您的解析器新增的位置。
WebMvcAutoConfiguration
將以下 ViewResolver
新增到您的 context 中
-
一個名為 ‘defaultViewResolver’ 的
InternalResourceViewResolver
。這個解析器會尋找可以使用DefaultServlet
渲染的物理資源(包括靜態資源和 JSP 頁面,如果您使用的話)。它會將前綴和後綴應用於視圖名稱,然後在 servlet context 中尋找具有該路徑的物理資源(預設值都為空,但可以透過spring.mvc.view.prefix
和spring.mvc.view.suffix
進行外部組態)。您可以透過提供相同類型的 bean 來覆寫它。 -
一個名為 ‘beanNameViewResolver’ 的
BeanNameViewResolver
。這是視圖解析器鏈中一個有用的成員,它會拾取任何與要解析的View
同名的 beans。應該不需要覆寫或取代它。 -
只有在實際存在
View
類型的 beans 時,才會新增一個名為 ‘viewResolver’ 的ContentNegotiatingViewResolver
。這是一個複合解析器,它委派給所有其他解析器,並嘗試尋找與客戶端發送的 ‘Accept’ HTTP header 相符的項目。有一篇關於ContentNegotiatingViewResolver
的有用的部落格文章,您可能想要研究以了解更多資訊,您也可以查看原始碼以了解詳細資訊。您可以透過定義一個名為 ‘viewResolver’ 的 bean 來關閉自動組態的ContentNegotiatingViewResolver
。 -
如果您使用 Thymeleaf,您也會有一個名為 ‘thymeleafViewResolver’ 的
ThymeleafViewResolver
。它透過使用前綴和後綴包圍視圖名稱來尋找資源。前綴是spring.thymeleaf.prefix
,後綴是spring.thymeleaf.suffix
。前綴和後綴的值預設分別為 ‘classpath:/templates/’ 和 ‘.html’。您可以透過提供同名的 bean 來覆寫ThymeleafViewResolver
。 -
如果您使用 FreeMarker,您也會有一個名為 ‘freeMarkerViewResolver’ 的
FreeMarkerViewResolver
。它透過使用前綴和後綴包圍視圖名稱,在載入器路徑(外部化為spring.freemarker.templateLoaderPath
,預設值為 ‘classpath:/templates/’)中尋找資源。前綴外部化為spring.freemarker.prefix
,後綴外部化為spring.freemarker.suffix
。前綴和後綴的預設值分別為空字串和 ‘.ftlh’。您可以透過提供同名的 bean 來覆寫FreeMarkerViewResolver
。 -
如果您使用 Groovy 模板(實際上,如果
groovy-templates
在您的 classpath 上),您也會有一個名為 ‘groovyMarkupViewResolver’ 的GroovyMarkupViewResolver
。它透過使用前綴和後綴包圍視圖名稱(外部化為spring.groovy.template.prefix
和spring.groovy.template.suffix
),在載入器路徑中尋找資源。前綴和後綴的預設值分別為 ‘classpath:/templates/’ 和 ‘.tpl’。您可以透過提供同名的 bean 來覆寫GroovyMarkupViewResolver
。 -
如果您使用 Mustache,您也會有一個名為 ‘mustacheViewResolver’ 的
MustacheViewResolver
。它透過使用前綴和後綴包圍視圖名稱來尋找資源。前綴是spring.mustache.prefix
,後綴是spring.mustache.suffix
。前綴和後綴的值預設分別為 ‘classpath:/templates/’ 和 ‘.mustache’。您可以透過提供同名的 bean 來覆寫MustacheViewResolver
。
如需更多詳細資訊,請參閱以下章節
自訂 ‘whitelabel’ 錯誤頁面
如果您遇到伺服器錯誤(機器客戶端使用 JSON 和其他媒體類型應會看到帶有正確錯誤代碼的合理回應),Spring Boot 會安裝一個 ‘whitelabel’ 錯誤頁面,您可以在瀏覽器客戶端中看到它。
設定 server.error.whitelabel.enabled=false 以關閉預設錯誤頁面。這樣做會恢復您正在使用的 servlet 容器的預設值。請注意,Spring Boot 仍然會嘗試解析錯誤視圖,因此您應該新增自己的錯誤頁面,而不是完全停用它。 |
使用您自己的錯誤頁面覆寫錯誤頁面取決於您使用的模板技術。例如,如果您使用 Thymeleaf,您可以新增一個 error.html
模板。如果您使用 FreeMarker,您可以新增一個 error.ftlh
模板。一般來說,您需要一個解析為名稱為 error
的 View
或一個處理 /error
路徑的 @Controller
。除非您取代了一些預設組態,否則您應該在您的 ApplicationContext
中找到一個 BeanNameViewResolver
,因此名為 error
的 @Bean
將是一種方法。請參閱 ErrorMvcAutoConfiguration
以取得更多選項。
另請參閱關於 錯誤處理 的章節,以了解如何在 servlet 容器中註冊處理常式的詳細資訊。