SpringMVC異常處理的三種方式
HandlerExceptionResolver接口
在SpringMVC中,提供了一個全局異常處理器,用于對系統(tǒng)中出現(xiàn)的異常進行統(tǒng)一處理
在一般的系統(tǒng)中,DAO層、Service層及Controller層出現(xiàn)異常都以“throws Exception”的形式向上層拋出,最后都會由SpringMVC的前端控制器(DispatcherServlet)統(tǒng)一交給全局異常處理器進行異常處理
在SpringMVC中提供的HandlerExceptionResolver接口可以實現(xiàn)全局異常處理器
Spring MVC
接口HandlerExceptionResolver
用于抽象一個異常解析器
這種異常解析器被用于分析請求處理器Handler
映射或者執(zhí)行過程中的異常,將這些異常轉(zhuǎn)換成其他形式展示給用戶
可以看到,HandlerExceptionResolver接口中定義了一個名為resolveException的方法,該方法主要用于處理Controller中的異常
參數(shù)“Exception ex”即為Controller或其下層拋出的異常
參數(shù)“Object handler”就是處理器適配器要執(zhí)行的Handler對象
resolveException方法的返回值類型是ModelAndView,也就是說,可以通過這個返回值來設(shè)置發(fā)送異常時的顯示頁面
典型的做法是轉(zhuǎn)換成一個錯誤視圖,或者返回某個HTTP
狀態(tài)碼給請求端
使用HandlerExceptionResolver實現(xiàn)全局異常處理器;當拋出異常后,要有相應(yīng)的符合用戶體驗的友好界面顯示異常
綜合實例:
(1)創(chuàng)建自定義異常類,名稱為OperationException
注意:
Spring管理的事務(wù),無論是聲明式事務(wù)還是注解式事務(wù)默認是在拋出運行異常(RuntimeException異常)時,才會被Spring框架捕獲到然后回滾
該自定義異常類繼承的是RuntimeException類,因為一般項目的Service層邏輯都會使用Spring提供的事務(wù)管理,當Service層需要拋出自定義異常時,如果該自定義異常繼承的是Exception類,則Spring提供的事務(wù)管理將會失效,所以這里的自定義異常類繼承的是RuntimeException類,這樣才不會使Spring提供的事務(wù)管理失效
(2)創(chuàng)建全局異常處理器OperationExceptionResolver類,該類實現(xiàn)HandlerExceptionResolver接口,并且實現(xiàn)resolveException方法
(3)創(chuàng)建名稱為error.jsp的頁面,符合用戶體驗的友好界面,用于顯示異常信息
Spring MVC 為HandlerExceptionResolver提供了四個實現(xiàn)類:
(1)ExceptionHandlerExceptionResolver
找到使用@ExceptionHandler注解的ServletInvocableHandlerMethod并調(diào)用,基于其執(zhí)行結(jié)果構(gòu)建ModelAndView
(2)SimpleMappingExceptionResolver
映射異常類名到視圖名稱,處理時使用此映射關(guān)系構(gòu)建ModelAndView,或者使用缺省視圖
(3)ResponseStatusExceptionResolver
如果異常是ResponseStatusException或者使用了注解@ResponseStatus,則利用這些信息將異常翻譯成HTTP狀態(tài)字調(diào)用相應(yīng)的sendError,返回空ModelAndView
注意:該異常解析器會遞歸檢查異常的cause異常
(4)DefaultHandlerExceptionResolver
Spring MVC缺省異常處理器,解析時將標準MVC異常翻譯成HTTP狀態(tài)字調(diào)用相應(yīng)對象的方法#sendError,返回一個空ModelAndView對象(注意:不是null)
使用注解實現(xiàn)異常分類管理(@ControllerAdvice 和 @ExceptionHandler)
引言:
在開發(fā)中,我們會有如下的場景:某個接口中,存在一些業(yè)務(wù)異常
例如用戶輸入的參數(shù)校驗失敗、用戶名密碼不存在等
當觸發(fā)這些業(yè)務(wù)異常時,我們需要拋出這些自定義的業(yè)務(wù)異常,并對其進行處理
一般我們要把這些異常信息的狀態(tài)碼和異常描述,友好地返回給調(diào)用者,調(diào)用者則利用狀態(tài)碼等信息判斷異常的具體情況
過去,我們可能需要在 controller 層通過 try/catch 處理
首先 catch 自定義異常,然后 catch 其它異常
對于不同的異常,我們需要在 catch 的同時封裝將要返回的對象
然而,這么做的弊端就是代碼會變得冗長
每個接口都需要做 try/catch 處理,而且一旦需要調(diào)整,所有的接口都需要修改一遍,非常不利于代碼的維護,如下段代碼所示:
那么,有沒有什么方法可以簡便地處理這些異常信息呢?
答案是肯定的
Spring 3.2 中,新增了 @ControllerAdvice 注解,可以用于定義 @ExceptionHandler、@InitBinder、@ModelAttribute,并應(yīng)用到所有 @RequestMapping 中
簡單來說就是,可以通過 @ControllerAdvice 注解配置一個全局異常處理類,來統(tǒng)一處理 controller 層中的異常,于此同時 controller 中可以不用再寫 try/catch,這使得代碼既整潔又便于維護
綜合實例:定義自定義異常
(1)自定義業(yè)務(wù)異常類
(2)@ControllerAdvice + @ExceptionHandler 配置全局異常處理類
@ControllerAdvice
類型:類注解;定義該類為全局異常處理類
@ExceptionHandler
類型:方法注解;定義該方法為異常處理方法
value 的值為需要處理的異常類的 class 文件
這樣,就可以對不同的異常進行統(tǒng)一處理了
通常,為了使 controller 中不再使用任何 try/catch,也可以在 GlobalExceptionHandler 中對 Exception 做統(tǒng)一處理
這樣其他沒有用 @ExceptionHandler 配置的異常就都會統(tǒng)一被處理
遇到異常時拋出異常即可
在業(yè)務(wù)中,遇到業(yè)務(wù)異常的地方,直接使用 throw 拋出對應(yīng)的業(yè)務(wù)異常即可
例如:
注意:
- 不一定必須在 controller 層本身拋出異常才能被 GlobalExceptionHandler 處理,只要異常最后是從 contoller 層拋出去的就可以被全局異常處理器處理
- 異步方法中的異常不會被全局異常處理
- 拋出的異常如果被代碼內(nèi)的 try/catch 捕獲了,就不會被 GlobalExceptionHandler 處理了
優(yōu)點:
- 減少代碼冗余,代碼便于維護
缺點:
- 只能處理 controller 層拋出的異常,對例如 Interceptor(攔截器)層的異常、定時任務(wù)中的異常、異步方法中的異常,不會進行處理
使用 @ControllerAdvice 對不同的 Controller 分別捕獲異常并處理
引言
- 上文介紹了如何在 SpringBoot 工程中對 Controller 配置全局異常處理
- 后來在實際工程中,又有了如下需求:有些接口在發(fā)生異常時,需要持久化錯誤信息,而有的接口則不需要
- 如果使用了全局異常處理,那每次發(fā)生了異常,還需要判斷是哪個接口發(fā)生的異常,進而選擇是否持久化錯誤日志
- 那能不能對全局異常進行配置,對不同類型的接口使用不同的全局異常進行處理呢?
- 經(jīng)過查閱文檔發(fā)現(xiàn),Spring 提供了對 @ControllerAdvice 注解的配置,我們可以通過配置 @ControllerAdvice 指定攔截范圍
@ControllerAdvice 指定 Controller 范圍
- 根據(jù) API,我們可以看到注解 @ControllerAdvice 有如下幾種配置:
(1)basePackages
- basePackages:指定一個或多個包,這些包及其子包下的所有 Controller 都被該 @ControllerAdvice 管理
- 其中上面兩種等價于 basePackages
(2)basePackageClasses
- basePackageClasses:是 basePackages 的一種變形,指定一個或多個 Controller 類,這些類所屬的包及其子包下的所有 Controller 都被該 @ControllerAdvice 管理
(3)assignableTypes
- assignableTypes:指定一個或多個 Controller 類,這些類被該 @ControllerAdvice 管理
(4)annotations
- annotations:指定一個或多個注解,被這些注解所標記的 Controller 會被該 @ControllerAdvice 管理
例子
- 這里用 assignableTypes 配置指定的 Controller 進行測試
(1)創(chuàng)建三個 Controller
其中,BusinessException 是自定義的異常類
(2)創(chuàng)建兩個全局異常處理類
(3)分別調(diào)用接口,查看錯誤日志
(1)調(diào)用 localhost:8080/test1
返回:GlobalExceptionHandler1 服務(wù)錯誤
即 MyController1 異常被 GlobalExceptionHandler1 全局異常類捕獲
(2)調(diào)用 localhost:8080/test2
返回:GlobalExceptionHandler2 服務(wù)錯誤
即 MyController2 異常被 GlobalExceptionHandler2 全局異常類捕獲
(3)調(diào)用 localhost:8080/test3
返回:
即 MyController3 異常沒有被全局異常捕獲
總結(jié)
到此這篇關(guān)于SpringMVC異常處理的三種方式的文章就介紹到這了,更多相關(guān)SpringMVC異常處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringMVC @GetMapping注解路徑?jīng)_突問題解決
MD5對密碼進行加密存儲是常見的一種加密方式,本文主要介紹了Java雙重MD5加密實現(xiàn)安全登錄,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07Java調(diào)用打印機的2種方式舉例(無驅(qū)/有驅(qū))
我們平時使用某些軟件或者在超市購物的時候都會發(fā)現(xiàn)可以使用打印機進行打印,這篇文章主要給大家介紹了關(guān)于Java調(diào)用打印機的2種方式,分別是無驅(qū)/有驅(qū)的相關(guān)資料,需要的朋友可以參考下2023-11-11解決Error:(5, 28) java: 程序包org.apache.ibatis.io
這篇文章主要介紹了解決Error:(5, 28) java: 程序包org.apache.ibatis.io不存在問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05RabbitMQ消費者限流實現(xiàn)消息處理優(yōu)化
這篇文章主要介紹了RabbitMQ消費者限流實現(xiàn)消息處理優(yōu)化,消費者限流是用于消費者每次獲取消息時限制條數(shù),注意前提是手動確認模式,并且在手動確認后才能獲取到消息,感興趣想要詳細了解可以參考下文2023-05-05Java中Json與List、Map、entity的互相轉(zhuǎn)化
在開發(fā)中,Json轉(zhuǎn)換的場景往往也就是那么幾個,本文主要介紹了Java中Json與List、Map、entity的互相轉(zhuǎn)化,具有一定的參考價值,感興趣的可以了解一下2022-07-07Spring Boot 會員管理系統(tǒng)之處理文件上傳功能
Spring Boot會員管理系統(tǒng)的中,需要涉及到Spring框架,SpringMVC框架,Hibernate框架,thymeleaf模板引擎。這篇文章主要介紹了Spring Boot會員管理系統(tǒng)之處理文件上傳功能,需要的朋友可以參考下2018-03-03淺談Java(SpringBoot)基于zookeeper的分布式鎖實現(xiàn)
這篇文章主要介紹了Java(SpringBoot)基于zookeeper的分布式鎖實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03