SpringBoot中的異常處理與參數(shù)校驗(yàn)的方法實(shí)現(xiàn)
兄弟們好,這次來(lái)跟老鐵交流兩個(gè)問(wèn)題,異常和參數(shù)校驗(yàn),在說(shuō)參數(shù)校驗(yàn)之前我們先來(lái)說(shuō)異常處理吧,因?yàn)楹竺鎱?shù)的校驗(yàn)會(huì)牽扯到異常處理這塊的內(nèi)容。
異常處理
說(shuō)到異常處理,我不知道大家有沒(méi)有寫(xiě)過(guò)或者遇到過(guò)如下的寫(xiě)法。
public void saveUser() {
try {
// 所有的業(yè)務(wù)內(nèi)容,目測(cè)幾百行
}catch (Exception e) {
e.printStackTrace();
}
}
如果出現(xiàn)上述的代碼,里面包含了大量的業(yè)務(wù)代碼,如果是你寫(xiě)的,趕緊改掉,不是你寫(xiě)的找寫(xiě)的,吐槽趕緊改掉。
存在的問(wèn)題:
1、會(huì)遇到性能瓶頸;
2、很難定位問(wèn)題;
3、try嵌套過(guò)多可讀性很差;
不管什么原因出現(xiàn)了上述代碼,那么最好還是改一下,如果非要在業(yè)務(wù)代碼中try,那么也應(yīng)該只在可能出現(xiàn)異常的地方使用try,而不是try整個(gè)業(yè)務(wù)代碼。
SpringBoot中的異常捕獲
直接上代碼
@RestControllerAdvice
public class GlobalException {
@ExceptionHandler(value = Exception.class) // 捕獲的異常類型
public Object globalException(Exception ex) {
// 異常處理
ex.printStackTrace();
return "出現(xiàn)異常";
}
}
那么在SpringBoot中我們就可以通過(guò)這樣的一個(gè)配置可以獲取到項(xiàng)目中出現(xiàn)異常的地方,我們可以在這個(gè)方法中可以獲取出現(xiàn)異常的類的詳細(xì)信息,那么是不是所有的異常我們?nèi)渴褂肊xception來(lái)處理呢?那么肯定是不合適的。
我們模擬一個(gè)by zero的異常,然后再配置一個(gè)處理ArithmeticException異常的處理器,代碼如下:
@RestControllerAdvice
public class GlobalException {
@ExceptionHandler(value = Exception.class) // 捕獲的異常類型
public Object globalException(Exception ex) {
ex.printStackTrace();
return "出現(xiàn)異常";
}
@ExceptionHandler(value = ArithmeticException.class)
public Object arithmeticException(ArithmeticException ex) {
ex.printStackTrace();
return "by zero異常";
}
}
如果這個(gè)時(shí)候出現(xiàn)by zero異常,走ArithmeticException異常處理,原因就是因?yàn)槿绻懈》秶漠惓L幚眍?,那么?huì)走小范圍的異常處理器。不會(huì)走globalException更大的異常處理類。
這樣處理之后,我們就不需要在項(xiàng)目中去寫(xiě)那么多的try了,是不是方便了很多。
除了使用這些已經(jīng)存在的異常外,其實(shí)我們還可以自定義我們的異常,比如我們常用的用戶未登錄異常、參數(shù)錯(cuò)誤異常等等。但是考慮到這篇文章的篇幅問(wèn)題,這次就先不寫(xiě)了,有興趣的朋友可以直接下面留言,人多了我盡快更新。
注意坑:
這里跟大家分享一個(gè)踩過(guò)的坑,不能再Filter過(guò)濾器中拋出異常,如果通過(guò)在過(guò)濾器中拋出異常,然后通過(guò)異常處理類來(lái)處理,那么是不可能的,因?yàn)樘幚砥魇遣东@不到Filter拋出的異常的。
參數(shù)校驗(yàn)
老規(guī)矩,先來(lái)看一段代碼
@RequestMapping(value = "/save/user")
public Object saveUser(UserPO userPO) {
if (userPO.getAge() == null) {
return "請(qǐng)求參數(shù)錯(cuò)誤";
}
if (userPO.getSex() == null) {
return "請(qǐng)求參數(shù)錯(cuò)誤";
}
if (userPO.getUsername() == null) {
return "請(qǐng)求參數(shù)錯(cuò)誤";
}
// ...
return "SUCCESS";
}
應(yīng)該見(jiàn)過(guò)這種校驗(yàn)參數(shù)的吧,說(shuō)實(shí)話我寫(xiě)過(guò)。越寫(xiě)感覺(jué)越low,所以狠心一下,還是趁早改吧。
@Validated注解
這個(gè)注解其實(shí)是Spring提供的,如果你的項(xiàng)目不是SpringBoot項(xiàng)目,需要引一下需要的pom文件,如果是,那么就不用管了,SpringBoot已經(jīng)幫我們引入了。
網(wǎng)上看了好多的博客,許多都說(shuō)的不是很全,大部分都是說(shuō)JavaBean參數(shù)的校驗(yàn),但是我們項(xiàng)目中有些接口可能就涉及一個(gè)參數(shù),根本不需要寫(xiě)一個(gè)JavaBean,對(duì)于單一參數(shù)的校驗(yàn)好多博客還是沒(méi)說(shuō)的,那么我們這次就一次性講清楚。
單一參數(shù)的校驗(yàn)
直接看代碼吧
@Validated
@RestController
public class BookController {
@RequestMapping(value = "/book/info", method = RequestMethod.GET)
public Object getBookInfo(@NotBlank(message = "書(shū)籍ID不能為空") String bookId) {
return "SUCCESS";
}
}
這里要跟大家特別說(shuō)明下,如果是單一參數(shù)的校驗(yàn),那么我們必須要在類上面添加@Validated注解,不然我們整個(gè)單個(gè)參數(shù)校驗(yàn)是不會(huì)生效的,可以看到我們?cè)谛r?yàn)參數(shù)bookId的時(shí)候,使用了@NotBlank那么顧名思義,就是這個(gè)參數(shù)不能為null,在調(diào)用了trim()方法之后也不能是空字符。
如果參數(shù)不滿足要求,那么會(huì)拋出ConstraintViolationException異常,這個(gè)異常只有在單一參數(shù)校驗(yàn)的時(shí)候拋出,如果你的參數(shù)是JavaBean,那么就不是這個(gè)異常了。
既然我們知道了它會(huì)拋出異常,并且我們也知道是什么異常類型,那么久超級(jí)簡(jiǎn)單了,我們可以直接使用上面剛學(xué)的異常處理類來(lái)處理我們的異常。
我找個(gè)里面寫(xiě)的比較簡(jiǎn)單,如果你想寫(xiě)的復(fù)雜一點(diǎn),其實(shí)也是可以的,但是作為后端來(lái)說(shuō),我覺(jué)得沒(méi)必要,因?yàn)槲覀儾荒芙o前端提示太過(guò)明顯的錯(cuò)誤提示,防止別人惡意攻擊我們,就像用戶名密碼錯(cuò)誤,不能明確的告訴用戶到底是用戶名錯(cuò)誤還是密碼錯(cuò)誤,只能提示用戶名或密碼錯(cuò)誤。
如果大家非要把詳細(xì)的錯(cuò)誤信息打出來(lái),要看到到底是哪個(gè)參數(shù)校驗(yàn)不通過(guò),也可以通過(guò)下面的方式將具體的參數(shù)錯(cuò)誤信息打印出來(lái)。輸出的錯(cuò)誤結(jié)果其實(shí)就是上面message里面的內(nèi)容。
@RestControllerAdvice
public class ExceptionCatch {
/**
* 單個(gè)參數(shù)異常處理
*
* @param ex
* @return
*/
@ExceptionHandler(value = ConstraintViolationException.class)
public Object constraintViolationException(ConstraintViolationException ex) {
// 獲取具體的錯(cuò)誤信息
Set<ConstraintViolation<?>> violations = ex.getConstraintViolations();
// 打印數(shù)據(jù)
violations.forEach(e -> System.out.println(e.getMessage()));
return "單個(gè)-請(qǐng)求參數(shù)錯(cuò)誤";
}
}
JavaBean參數(shù)校驗(yàn)(form-data)
JavaBean的寫(xiě)法
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserPO {
@NotBlank(message = "用戶名不能為空")
private String username;
@NotNull(message = "年齡不能為空")
@Min(value = 1, message = "年齡最小為1")
@Max(value = 200, message = "年齡最大為200")
private Integer age;
@NotBlank(message = "性別不能為空")
private String sex;
}
Controller寫(xiě)法
@RequestMapping(value = "/save/user")
public Object saveUser(@Validated UserPO userPO) {
// ...
return "SUCCESS";
}
跟單一參數(shù)校驗(yàn)不一樣的是JavaBean的校驗(yàn)方式需要將@Validated寫(xiě)在方法參數(shù),而不是類上。如果出現(xiàn)了參數(shù)校驗(yàn)不通過(guò),同樣的也會(huì)拋出一個(gè)異常,BindException。
/**
* 一般參數(shù)校驗(yàn)綁定異常處理
*
* @param ex
* @return
*/
@ExceptionHandler(value = BindException.class)
public Object bindException(BindException ex) {
BindingResult bindingResult = ex.getBindingResult();
// 獲取所有的錯(cuò)誤信息
List<ObjectError> allErrors = bindingResult.getAllErrors();
// 輸出
allErrors.forEach(e -> System.out.println(e.getDefaultMessage()));
return "請(qǐng)求參數(shù)錯(cuò)誤";
}
注意:大家要注意post請(qǐng)求有兩種方式,一種是基于form-data格式的數(shù)據(jù)傳遞,另外一種就是基于json格式的數(shù)據(jù)傳遞,兩種傳遞方式引發(fā)的異常也是不一樣的,所以我們還要單獨(dú)處理基于json的參數(shù)校驗(yàn)異常處理。
JavaBean參數(shù)校驗(yàn)(json)
我們先來(lái)看下Controller接收方式
@RequestMapping(value = "/save/user")
public Object saveUser(@Validated @RequestBody UserPO userPO) {
// ...
return "SUCCESS";
}
對(duì)應(yīng)的參數(shù)異常處理
/**
* JSON參數(shù)校驗(yàn)綁定異常處理
*
* @param ex
* @return
*/
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public Object methodArgumentNotValidException(MethodArgumentNotValidException ex) {
BindingResult bindingResult = ex.getBindingResult();
// 獲取所有的錯(cuò)誤信息
List<ObjectError> allErrors = bindingResult.getAllErrors();
// 輸出
allErrors.forEach(e -> System.out.println(e.getDefaultMessage()));
return "請(qǐng)求參數(shù)錯(cuò)誤-json";
}
最后的話
那么到這里,我們本篇文章就結(jié)束了,主要介紹了兩部分內(nèi)容,異常的處理和參數(shù)的校驗(yàn)。雖然很簡(jiǎn)單,但是我個(gè)人感覺(jué)還是挺常用的技能。所以與大家進(jìn)行分享,如果對(duì)你有點(diǎn)幫助,就來(lái)點(diǎn)個(gè)贊吧。如果有什么不明白的也歡迎下方留言,一起來(lái)交流。
到此這篇關(guān)于SpringBoot中的異常處理與參數(shù)校驗(yàn)的方法實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)SpringBoot 異常處理與參數(shù)校驗(yàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot進(jìn)行參數(shù)校驗(yàn)的方法詳解
- 詳解SpringBoot中的參數(shù)校驗(yàn)(項(xiàng)目實(shí)戰(zhàn))
- SpringBoot參數(shù)校驗(yàn)之@Valid的使用詳解
- SpringBoot參數(shù)校驗(yàn)與國(guó)際化使用教程
- SpringBoot參數(shù)校驗(yàn)Validator框架詳解
- SpringBoot 如何自定義請(qǐng)求參數(shù)校驗(yàn)
- SpringBoot使用validation做參數(shù)校驗(yàn)的實(shí)現(xiàn)步驟
- Springboot參數(shù)校驗(yàn)之分組校驗(yàn)、嵌套校驗(yàn)的實(shí)現(xiàn)
相關(guān)文章
JVM參數(shù)NativeMemoryTracking的使用
本文主要介紹了JVM參數(shù)NativeMemoryTracking的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-01-01
Java實(shí)現(xiàn)XML與JSON的互相轉(zhuǎn)換詳解
這篇文章主要為大家詳細(xì)介紹了如何使用Java實(shí)現(xiàn)XML與JSON的互相轉(zhuǎn)換,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-03-03
使用SpringMVC在redirect重定向的時(shí)候攜帶參數(shù)的問(wèn)題
這篇文章主要介紹了使用SpringMVC在redirect重定向的時(shí)候攜帶參數(shù)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
談?wù)凧ava中對(duì)象,類和this,super,static關(guān)鍵字的使用
對(duì)象:對(duì)象是類的一個(gè)實(shí)例,有狀態(tài)和行為。類:類是一個(gè)模板,它描述一類對(duì)象的行為和狀態(tài)。本文就來(lái)和大家聊聊Java中對(duì)象,類和關(guān)鍵字的使用,需要的可以參考一下2022-08-08
IDEA在一個(gè)項(xiàng)目空間下管理多個(gè)項(xiàng)目的操作方法
這篇文章主要介紹了IDEA如何在一個(gè)項(xiàng)目空間下管理多個(gè)項(xiàng)目,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04
利用Socket.io 實(shí)現(xiàn)消息實(shí)時(shí)推送功能
這篇文章主要介紹了利用Socket.io 實(shí)現(xiàn)消息實(shí)時(shí)推送功能,需要的朋友可以參考下2017-12-12
java實(shí)現(xiàn)Rabbitmq延遲隊(duì)列和惰性隊(duì)列
本文主要介紹了java實(shí)現(xiàn)Rabbitmq延遲隊(duì)列和惰性隊(duì)列,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-12-12
Dubbo?LoadBalance基于權(quán)重的隨機(jī)負(fù)載均衡算法提高服務(wù)性能
這篇文章主要為大家介紹了Dubbo?LoadBalance基于權(quán)重的隨機(jī)負(fù)載均衡算法提高服務(wù)性能詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪<BR>2023-10-10
springboot請(qǐng)求找不到路徑異常的問(wèn)題
這篇文章主要介紹了springboot請(qǐng)求找不到路徑異常的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01

