前言
在平時的 API 開發過程中,總會遇到一些錯誤異常沒有捕捉到的情況。那有的小伙伴可能會想,這還不簡單么,我在 API 最外層加一個 try...catch
不就完事了。
哈哈哈,沒錯。這種方法簡單粗暴。小編曾經也是這么干的,但是你轉過來想一想,你會在每一個 API 入口,都去做 try...catch
嗎?這樣不是代碼非常丑陋的。小伙伴開始思考,突然靈光一現,說我們實現一個 AOP 來做這事不就完了。沒錯,使用 AOP 來實現是最佳的選擇。
現在就給大家來介紹介紹 Spring Boot
怎么通過注解來實現全局異常處理的。
主角 @ControllerAdvice
和 @ExceptionHandler
我們先來介紹一下今天的主角,分別是 @ControllerAdvice
和 @ExceptionHandler
。
@ControllerAdvice
相當于controller
的切面,主要用于@ExceptionHandler
,@InitBinder
和@ModelAttribute
,使注解標注的方法對每一個controller
都起作用。默認對所有controller
都起作用,當然也可以通過@ControllerAdvice
注解中的一些屬性選定符合條件的controller
。@ExceptionHandler
用于異常處理的注解,可以通過value
指定處理哪種類型的異常還可以與@ResponseStatus
搭配使用,處理特定的http
錯誤。標記的方法入參與返回值都有很大的靈活性,具體可以看注釋也可以在后邊的深度探究。
案例分析
今天我們就通過幾種案例的方式,來給大家分析分析,怎么通過全局異常處理的方式玩轉 Spring Boot 的全局異常處理。
案例一
一般的異常處理,所有的API都需要有相同的異常結構。
exception1
在這種情況下,實現是非常簡單的,我們只需要創建 GeneralExceptionHandler
類,用 @ControllerAdvice
注解來注解它,并創建所需的 @ExceptionHandler
,它將處理所有由應用程序拋出的異常,如果它能找到匹配的 @ExceptionHandler
,它將相應地進行轉換。
@ControllerAdvice
public class GeneralExceptionHandler {
@ExceptionHandler(Exception.class)
protected ResponseEntity< Error > handleException(Exception ex) {
MyError myError = MyError.builder()
.text(ex.getMessage())
.code(ex.getErrorCode()).build();
return new ResponseEntity(myError,
HttpStatus.valueOf(ex.getErrorCode()));
}
}
案例二
我們有一個API,它需要有一個或多個異常以其他格式處理,與其他應用程序的 API 不同。
exception2
我們可以采取兩種方式來實現這種情況。我們可以在 OtherController
內部添加 @ExceptionHandler
來處理 OtherException
,或者為 OtherController
創建新的@ControllerAdvice
,以備我們也想在其他 API 中處理 OtherException
。
在 OtherController
中添加 @ExceptionHandler
來處理 OtherException
的代碼示例。
@RestController
@RequestMapping("/other")
public class OtherController {
@ExceptionHandler(OtherException.class)
protected ResponseEntity< Error > handleException(OtherException ex) {
MyOtherError myOtherError = MyOtherError.builder()
.message(ex.getMessage())
.origin("Other API")
.code(ex.getErrorCode()).build();
return new ResponseEntity(myOtherError,
HttpStatus.valueOf(ex.getErrorCode()));
}
}
只針對 OtherController
控制器的 @ControllerAdvice
的代碼示例
@ControllerAdvice(assignableTypes = OtherController.class)
public class OtherExceptionHandler {
@ExceptionHandler(OtherException.class)
protected ResponseEntity< Error > handleException(OtherException ex) {
MyOtherError myOtherError = MyOtherError.builder()
.message(ex.getMessage())
.origin("Other API")
.code(ex.getErrorCode()).build();
return new ResponseEntity(myOtherError,
HttpStatus.valueOf(ex.getErrorCode()));
}
}
案例三
與案例二類似,我們有一個 API 需要以不同于應用程序中其他 API 的方式對異常進行格式化,但這次所有的異常都需要進行不同的轉換。
exception3
為了實現這個案例,我們將不得不使用兩個 @ControllerAdvice
,并加上 @Order
注解的注意事項。因為現在我們需要告訴 Spring
,在處理同一個異常時,哪個 @ControllerAdvice
的優先級更高。如果我們沒有指定 @Order
,在啟動時,其中一個處理程序將自動注冊為更高的順序,我們的異常處理將變得不可預測。例如,我最近看到一個案例,如果你使用 mvn springboot:run
任務啟動一個應用程序,OtherExceptionHandler
是主要的,但是當以jar形式啟動時,GeneralExceptionHandler
是主要的。
@ControllerAdvice
public class GeneralExceptionHandler {
@ExceptionHandler(Exception.class)
protected ResponseEntity< Error > handleException(Exception ex) {
MyError myError = MyError.builder()
.text(ex.getMessage())
.code(ex.getErrorCode()).build();
return new ResponseEntity(myError,
HttpStatus.valueOf(ex.getErrorCode()));
}
}
@ControllerAdvice(assignableTypes = OtherController.class)
@Order(Ordered.HIGHEST_PRECEDENCE)
public class OtherExceptionHandler {
@ExceptionHandler(Exception.class)
protected ResponseEntity< Error > handleException(Exception ex) {
MyError myError = MyError.builder()
.message(ex.getMessage())
.origin("Other API")
.code(ex.getErrorCode()).build();
return new ResponseEntity(myError,
HttpStatus.valueOf(ex.getErrorCode()));
}
}
總結
經過上述的幾個案例,指北君覺得大家應該已經能夠輕松應對 Spring Boot 中大部分的全局異常處理的情況。
細心的同學也許會覺得為什么不使用 @RestControllerAdvice
呢?如果是用的 @RestControllerAdvice
注解,它會將數據自動轉換成JSON格式,不再需要 ResponseEntity
的處理來。這種與 Controller
和 RestController
類似,本質是一樣的,所以我們在使用全局異常處理之后可以進行靈活的選擇處理。
-
API
+關注
關注
2文章
1502瀏覽量
62101 -
代碼
+關注
關注
30文章
4791瀏覽量
68685 -
SpringBoot
+關注
關注
0文章
173瀏覽量
183
發布評論請先 登錄
相關推薦
評論