前言
在平時的 API 開發(fā)過程中,總會遇到一些錯誤異常沒有捕捉到的情況。那有的小伙伴可能會想,這還不簡單么,我在 API 最外層加一個 try...catch
不就完事了。
哈哈哈,沒錯。這種方法簡單粗暴。小編曾經(jīng)也是這么干的,但是你轉(zhuǎn)過來想一想,你會在每一個 API 入口,都去做 try...catch
嗎?這樣不是代碼非常丑陋的。小伙伴開始思考,突然靈光一現(xiàn),說我們實現(xiàn)一個 AOP 來做這事不就完了。沒錯,使用 AOP 來實現(xiàn)是最佳的選擇。
現(xiàn)在就給大家來介紹介紹 Spring Boot
怎么通過注解來實現(xiàn)全局異常處理的。
主角 @ControllerAdvice
和 @ExceptionHandler
我們先來介紹一下今天的主角,分別是 @ControllerAdvice
和 @ExceptionHandler
。
@ControllerAdvice
相當(dāng)于controller
的切面,主要用于@ExceptionHandler
,@InitBinder
和@ModelAttribute
,使注解標(biāo)注的方法對每一個controller
都起作用。默認對所有controller
都起作用,當(dāng)然也可以通過@ControllerAdvice
注解中的一些屬性選定符合條件的controller
。@ExceptionHandler
用于異常處理的注解,可以通過value
指定處理哪種類型的異常還可以與@ResponseStatus
搭配使用,處理特定的http
錯誤。標(biāo)記的方法入?yún)⑴c返回值都有很大的靈活性,具體可以看注釋也可以在后邊的深度探究。
案例分析
今天我們就通過幾種案例的方式,來給大家分析分析,怎么通過全局異常處理的方式玩轉(zhuǎn) Spring Boot 的全局異常處理。
案例一
一般的異常處理,所有的API都需要有相同的異常結(jié)構(gòu)。
exception1
在這種情況下,實現(xiàn)是非常簡單的,我們只需要創(chuàng)建 GeneralExceptionHandler
類,用 @ControllerAdvice
注解來注解它,并創(chuàng)建所需的 @ExceptionHandler
,它將處理所有由應(yīng)用程序拋出的異常,如果它能找到匹配的 @ExceptionHandler
,它將相應(yīng)地進行轉(zhuǎn)換。
@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,它需要有一個或多個異常以其他格式處理,與其他應(yīng)用程序的 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 需要以不同于應(yīng)用程序中其他 API 的方式對異常進行格式化,但這次所有的異常都需要進行不同的轉(zhuǎn)換。
exception3
為了實現(xiàn)這個案例,我們將不得不使用兩個 @ControllerAdvice
,并加上 @Order
注解的注意事項。因為現(xiàn)在我們需要告訴 Spring
,在處理同一個異常時,哪個 @ControllerAdvice
的優(yōu)先級更高。如果我們沒有指定 @Order
,在啟動時,其中一個處理程序?qū)⒆詣幼詾楦叩捻樞颍覀兊漠惓L幚韺⒆兊貌豢深A(yù)測。例如,我最近看到一個案例,如果你使用 mvn springboot:run
任務(wù)啟動一個應(yīng)用程序,OtherExceptionHandler
是主要的,但是當(dāng)以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()));
}
}
總結(jié)
經(jīng)過上述的幾個案例,指北君覺得大家應(yīng)該已經(jīng)能夠輕松應(yīng)對 Spring Boot 中大部分的全局異常處理的情況。
細心的同學(xué)也許會覺得為什么不使用 @RestControllerAdvice
呢?如果是用的 @RestControllerAdvice
注解,它會將數(shù)據(jù)自動轉(zhuǎn)換成JSON格式,不再需要 ResponseEntity
的處理來。這種與 Controller
和 RestController
類似,本質(zhì)是一樣的,所以我們在使用全局異常處理之后可以進行靈活的選擇處理。
-
API
+關(guān)注
關(guān)注
2文章
1518瀏覽量
62458 -
代碼
+關(guān)注
關(guān)注
30文章
4837瀏覽量
69128 -
SpringBoot
+關(guān)注
關(guān)注
0文章
174瀏覽量
201
發(fā)布評論請先 登錄
相關(guān)推薦
Spring Boot如何實現(xiàn)異步任務(wù)
啟動Spring Boot項目應(yīng)用的三種方法
使用Spring自定義注解的實現(xiàn)
Spring Boot框架錯誤處理
Spring Boot 系列(八)@ControllerAdvice 攔截異常并統(tǒng)一處理
Spring Boot Web相關(guān)的基礎(chǔ)知識
簡述Spring Boot數(shù)據(jù)校驗
Spring Bean相關(guān)的4個注解及使用方法
![<b class='flag-5'>Spring</b> Bean相關(guān)的4個<b class='flag-5'>注解</b>及使用方法](https://file1.elecfans.com/web2/M00/81/FF/wKgaomQvjviAWyDeAADCHy-wd84212.jpg)
Spring中@Component注解是怎么實現(xiàn)的
![<b class='flag-5'>Spring</b>中@Component<b class='flag-5'>注解</b>是怎么<b class='flag-5'>實現(xiàn)</b>的](https://file.elecfans.com/web2/M00/9D/F3/pYYBAGQvxC2ADEcoAAAxhbkime4164.png)
Spring Boot啟動 Eureka流程
![<b class='flag-5'>Spring</b> <b class='flag-5'>Boot</b>啟動 Eureka流程](https://file1.elecfans.com/web2/M00/A7/86/wKgaomUkx7OAdMOGAAIBWIj8ao0506.jpg)
Spring Boot的啟動原理
![<b class='flag-5'>Spring</b> <b class='flag-5'>Boot</b>的啟動原理](https://file1.elecfans.com/web2/M00/A9/C0/wKgZomUovNCAdZmWAADhZidr2zI277.jpg)
Spring Boot 的設(shè)計目標(biāo)
![<b class='flag-5'>Spring</b> <b class='flag-5'>Boot</b> 的設(shè)計目標(biāo)](https://file1.elecfans.com/web2/M00/A8/04/wKgaomUo6gmAEQN0AAESfDw9EW8049.jpg)
評論