前言
在平時(shí)的 API 開發(fā)過程中,總會(huì)遇到一些錯(cuò)誤異常沒有捕捉到的情況。那有的小伙伴可能會(huì)想,這還不簡(jiǎn)單么,我在 API 最外層加一個(gè) try...catch
不就完事了。
哈哈哈,沒錯(cuò)。這種方法簡(jiǎn)單粗暴。小編曾經(jīng)也是這么干的,但是你轉(zhuǎn)過來想一想,你會(huì)在每一個(gè) API 入口,都去做 try...catch
嗎?這樣不是代碼非常丑陋的。小伙伴開始思考,突然靈光一現(xiàn),說我們實(shí)現(xiàn)一個(gè) AOP 來做這事不就完了。沒錯(cuò),使用 AOP 來實(shí)現(xiàn)是最佳的選擇。
現(xiàn)在就給大家來介紹介紹 Spring Boot
怎么通過注解來實(shí)現(xiàn)全局異常處理的。
主角 @ControllerAdvice
和 @ExceptionHandler
我們先來介紹一下今天的主角,分別是 @ControllerAdvice
和 @ExceptionHandler
。
@ControllerAdvice
相當(dāng)于controller
的切面,主要用于@ExceptionHandler
,@InitBinder
和@ModelAttribute
,使注解標(biāo)注的方法對(duì)每一個(gè)controller
都起作用。默認(rèn)對(duì)所有controller
都起作用,當(dāng)然也可以通過@ControllerAdvice
注解中的一些屬性選定符合條件的controller
。@ExceptionHandler
用于異常處理的注解,可以通過value
指定處理哪種類型的異常還可以與@ResponseStatus
搭配使用,處理特定的http
錯(cuò)誤。標(biāo)記的方法入?yún)⑴c返回值都有很大的靈活性,具體可以看注釋也可以在后邊的深度探究。
案例分析
今天我們就通過幾種案例的方式,來給大家分析分析,怎么通過全局異常處理的方式玩轉(zhuǎn) Spring Boot 的全局異常處理。
案例一
一般的異常處理,所有的API都需要有相同的異常結(jié)構(gòu)。
exception1
在這種情況下,實(shí)現(xiàn)是非常簡(jiǎn)單的,我們只需要?jiǎng)?chuàng)建 GeneralExceptionHandler
類,用 @ControllerAdvice
注解來注解它,并創(chuàng)建所需的 @ExceptionHandler
,它將處理所有由應(yīng)用程序拋出的異常,如果它能找到匹配的 @ExceptionHandler
,它將相應(yīng)地進(jìn)行轉(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()));
}
}
案例二
我們有一個(gè)API,它需要有一個(gè)或多個(gè)異常以其他格式處理,與其他應(yīng)用程序的 API 不同。
exception2
我們可以采取兩種方式來實(shí)現(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()));
}
}
只針對(duì) 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()));
}
}
案例三
與案例二類似,我們有一個(gè) API 需要以不同于應(yīng)用程序中其他 API 的方式對(duì)異常進(jìn)行格式化,但這次所有的異常都需要進(jìn)行不同的轉(zhuǎn)換。
exception3
為了實(shí)現(xiàn)這個(gè)案例,我們將不得不使用兩個(gè) @ControllerAdvice
,并加上 @Order
注解的注意事項(xiàng)。因?yàn)楝F(xiàn)在我們需要告訴 Spring
,在處理同一個(gè)異常時(shí),哪個(gè) @ControllerAdvice
的優(yōu)先級(jí)更高。如果我們沒有指定 @Order
,在啟動(dòng)時(shí),其中一個(gè)處理程序?qū)⒆詣?dòng)注冊(cè)為更高的順序,我們的異常處理將變得不可預(yù)測(cè)。例如,我最近看到一個(gè)案例,如果你使用 mvn springboot:run
任務(wù)啟動(dòng)一個(gè)應(yīng)用程序,OtherExceptionHandler
是主要的,但是當(dāng)以jar形式啟動(dòng)時(shí),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)過上述的幾個(gè)案例,指北君覺得大家應(yīng)該已經(jīng)能夠輕松應(yīng)對(duì) Spring Boot 中大部分的全局異常處理的情況。
細(xì)心的同學(xué)也許會(huì)覺得為什么不使用 @RestControllerAdvice
呢?如果是用的 @RestControllerAdvice
注解,它會(huì)將數(shù)據(jù)自動(dòng)轉(zhuǎn)換成JSON格式,不再需要 ResponseEntity
的處理來。這種與 Controller
和 RestController
類似,本質(zhì)是一樣的,所以我們?cè)谑褂萌之惓L幚碇罂梢赃M(jìn)行靈活的選擇處理。
-
API
+關(guān)注
關(guān)注
2文章
1472瀏覽量
61750 -
代碼
+關(guān)注
關(guān)注
30文章
4722瀏覽量
68236 -
SpringBoot
+關(guān)注
關(guān)注
0文章
173瀏覽量
161
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論