異常
@Controller 和 @ControllerAdvice 類可以有 @ExceptionHandler 方法來處理控制器方法中的異常,如下例所示
-
Java
-
Kotlin
import java.io.IOException;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
@Controller
public class SimpleController {
@ExceptionHandler(IOException.class)
public ResponseEntity<String> handle() {
return ResponseEntity.internalServerError().body("Could not read file storage");
}
}
import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.ExceptionHandler
import java.io.IOException
@Controller
class SimpleController {
@ExceptionHandler(IOException::class)
fun handle() : ResponseEntity<String> {
return ResponseEntity.internalServerError().body("Could not read file storage")
}
}
異常對映
異常可能匹配正在傳播的頂級異常(例如,直接丟擲的 IOException)或包裝器異常中的巢狀原因(例如,包裝在 IllegalStateException 中的 IOException)。從 5.3 版開始,這可以匹配任意原因級別,而以前只考慮直接原因。
對於匹配的異常型別,最好將目標異常宣告為方法引數,如前例所示。當多個異常方法匹配時,通常首選根異常匹配而不是原因異常匹配。更具體地說,ExceptionDepthComparator 用於根據異常與丟擲異常型別的深度對異常進行排序。
或者,註解宣告可以縮小要匹配的異常型別,如下例所示
-
Java
-
Kotlin
@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handleIoException(IOException ex) {
return ResponseEntity.internalServerError().body(ex.getMessage());
}
@ExceptionHandler(FileSystemException::class, RemoteException::class)
fun handleIoException(ex: IOException): ResponseEntity<String> {
return ResponseEntity.internalServerError().body(ex.message)
}
你甚至可以使用特定異常型別的列表和非常通用的引數簽名,如下例所示
-
Java
-
Kotlin
@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handleExceptions(Exception ex) {
return ResponseEntity.internalServerError().body(ex.getMessage());
}
@ExceptionHandler(FileSystemException::class, RemoteException::class)
fun handleExceptions(ex: Exception): ResponseEntity<String> {
return ResponseEntity.internalServerError().body(ex.message)
}
|
根異常匹配和原因異常匹配之間的區別可能令人驚訝。 在前面所示的 在 |
我們通常建議你在引數簽名中儘可能具體,以減少根異常型別和原因異常型別之間不匹配的可能性。考慮將多匹配方法拆分為單獨的 @ExceptionHandler 方法,每個方法透過其簽名匹配單個特定異常型別。
在多 @ControllerAdvice 安排中,我們建議在具有相應順序優先順序的 @ControllerAdvice 上宣告你的主要根異常對映。雖然根異常匹配優先於原因,但這是在給定控制器或 @ControllerAdvice 類的方法之間定義的。這意味著高優先順序 @ControllerAdvice bean 上的原因匹配優先於低優先順序 @ControllerAdvice bean 上的任何匹配(例如,根)。
最後但同樣重要的是,@ExceptionHandler 方法實現可以選擇透過以其原始形式重新丟擲異常例項來退出處理給定異常例項。這在只對根級匹配或在無法靜態確定的特定上下文中匹配感興趣的場景中很有用。重新丟擲的異常透過剩餘的解析鏈傳播,就像給定的 @ExceptionHandler 方法一開始就沒有匹配一樣。
Spring MVC 中對 @ExceptionHandler 方法的支援建立在 DispatcherServlet 級別上,HandlerExceptionResolver 機制。
媒體型別對映
除了異常型別,@ExceptionHandler 方法還可以宣告可生產的媒體型別。這允許根據 HTTP 客戶端請求的媒體型別(通常在 "Accept" HTTP 請求頭中)來細化錯誤響應。
應用程式可以直接在註解上宣告可生產的媒體型別,針對相同的異常型別
-
Java
-
Kotlin
@ExceptionHandler(produces = "application/json")
public ResponseEntity<ErrorMessage> handleJson(IllegalArgumentException exc) {
return ResponseEntity.badRequest().body(new ErrorMessage(exc.getMessage(), 42));
}
@ExceptionHandler(produces = "text/html")
public String handle(IllegalArgumentException exc, Model model) {
model.addAttribute("error", new ErrorMessage(exc.getMessage(), 42));
return "errorView";
}
@ExceptionHandler(produces = ["application/json"])
fun handleJson(exc: IllegalArgumentException): ResponseEntity<ErrorMessage> {
return ResponseEntity.badRequest().body(ErrorMessage(exc.message, 42))
}
@ExceptionHandler(produces = ["text/html"])
fun handle(exc: IllegalArgumentException, model: Model): String {
model.addAttribute("error", ErrorMessage(exc.message, 42))
return "errorView"
}
在這裡,方法處理相同的異常型別,但不會被拒絕為重複。相反,請求“application/json”的 API 客戶端將收到 JSON 錯誤,而瀏覽器將收到 HTML 錯誤檢視。每個 @ExceptionHandler 註解可以宣告多個可生產的媒體型別,錯誤處理階段的內容協商將決定使用哪種內容型別。
方法引數
@ExceptionHandler 方法支援以下引數
| 方法引數 | 描述 |
|---|---|
異常型別 |
用於訪問丟擲的異常。 |
|
用於訪問丟擲異常的控制器方法。 |
|
無需直接使用 Servlet API 即可通用訪問請求引數以及請求和會話屬性。 |
|
選擇任何特定的請求或響應型別(例如, |
|
強制存在會話。因此,此類引數永遠不會為 |
|
當前已認證的使用者——如果已知,可能是特定的 |
|
請求的 HTTP 方法。 |
|
當前請求區域設定,由最具體的 |
|
與當前請求關聯的時區,由 |
|
用於訪問 Servlet API 公開的原始響應體。 |
|
用於訪問錯誤響應的模型。始終為空。 |
|
指定在重定向情況下使用的屬性(即要附加到查詢字串)和臨時儲存的 flash 屬性,直到重定向後的請求。請參閱重定向屬性和Flash 屬性。 |
|
用於訪問任何會話屬性,與因類級別 |
|
用於訪問請求屬性。有關更多詳細資訊,請參閱 |
返回值
@ExceptionHandler 方法支援以下返回值
| 返回值 | 描述 |
|---|---|
|
返回值透過 |
|
返回值指定整個響應(包括 HTTP 頭和正文)透過 |
|
要呈現帶有正文詳細資訊的 RFC 9457 錯誤響應,請參閱錯誤響應。 |
|
要透過 |
|
要與隱式模型(透過命令物件和 |
|
要新增到隱式模型的屬性,檢視名稱透過 |
|
要新增到模型的屬性,檢視名稱透過 請注意, |
|
要使用的檢視和模型屬性,以及可選的響應狀態。 |
|
如果一個方法具有 如果以上都不成立, |
任何其他返回值 |
如果返回值與上述任何一項都不匹配,並且不是簡單型別(由 BeanUtils#isSimpleProperty 確定),則預設情況下,它被視為要新增到模型的模型屬性。如果它是簡單型別,則保持未解析。 |