前言
在平時的 API 開發(fā)過程中,總會遇到一些錯誤異常沒有捕捉到的情況。那有的小伙伴可能會想,這還不簡單么,我在 API 最外層加一個 try...catch
不就完事了。
哈哈哈,沒錯。這種方法簡單粗暴。小編曾經(jīng)也是這么干的,但是你轉過來想一想,你會在每一個 API 入口,都去做 try...catch
嗎?這樣不是代碼非常丑陋的。小伙伴開始思考,突然靈光一現(xiàn),說我們實現(xiàn)一個 AOP 來做這事不就完了。沒錯,使用 AOP 來實現(xiàn)是最佳的選擇。
現(xiàn)在就給大家來介紹介紹 Spring Boot
怎么通過注解來實現(xiàn)全局異常處理的。
主角 @ControllerAdvice
和 @ExceptionHandler
我們先來介紹一下今天的主角,分別是 @ControllerAdvice
和 @ExceptionHandler
。
@ControllerAdvice
相當于controller
的切面,主要用于@ExceptionHandler
,@InitBinder
和@ModelAttribute
,使注解標注的方法對每一個controller
都起作用。默認對所有controller
都起作用,當然也可以通過@ControllerAdvice
注解中的一些屬性選定符合條件的controller
。@ExceptionHandler
用于異常處理的注解,可以通過value
指定處理哪種類型的異常還可以與@ResponseStatus
搭配使用,處理特定的http
錯誤。標記的方法入?yún)⑴c返回值都有很大的靈活性,具體可以看注釋也可以在后邊的深度探究。
案例分析
今天我們就通過幾種案例的方式,來給大家分析分析,怎么通過全局異常處理的方式玩轉 Spring Boot 的全局異常處理。
案例一
一般的異常處理,所有的API都需要有相同的異常結構。
exception1
在這種情況下,實現(xiàn)是非常簡單的,我們只需要創(chuàng)建 GeneralExceptionHandler
類,用 @ControllerAdvice
注解來注解它,并創(chuàng)建所需的 @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
我們可以采取兩種方式來實現(xiàn)這種情況。我們可以在 OtherController
內(nèi)部添加 @ExceptionHandler
來處理 OtherException
,或者為 OtherController
創(chuàng)建新的@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
為了實現(xiàn)這個案例,我們將不得不使用兩個 @ControllerAdvice
,并加上 @Order
注解的注意事項。因為現(xiàn)在我們需要告訴 Spring
,在處理同一個異常時,哪個 @ControllerAdvice
的優(yōu)先級更高。如果我們沒有指定 @Order
,在啟動時,其中一個處理程序?qū)⒆詣幼詾楦叩捻樞颍覀兊漠惓L幚韺⒆兊貌豢深A測。例如,我最近看到一個案例,如果你使用 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()));
}
}
總結
經(jīng)過上述的幾個案例,指北君覺得大家應該已經(jīng)能夠輕松應對 Spring Boot 中大部分的全局異常處理的情況。
細心的同學也許會覺得為什么不使用 @RestControllerAdvice
呢?如果是用的 @RestControllerAdvice
注解,它會將數(shù)據(jù)自動轉換成JSON格式,不再需要 ResponseEntity
的處理來。這種與 Controller
和 RestController
類似,本質(zhì)是一樣的,所以我們在使用全局異常處理之后可以進行靈活的選擇處理。
-
API
+關注
關注
2文章
1485瀏覽量
61817 -
代碼
+關注
關注
30文章
4748瀏覽量
68355 -
SpringBoot
+關注
關注
0文章
173瀏覽量
169
發(fā)布評論請先 登錄
相關推薦
評論