SpringBoot Web開發(fā)中的異常處理自動配置原理解析
默認規(guī)則
1. 默認情況下,SpringBoot提供/error處理所有錯誤的映射
2. 對于機器客戶端,它將生成JSON響應,其中包含錯誤,HTTP狀態(tài)和異常消息的詳細信息
- 例如postman發(fā)送請求

3. 對于瀏覽器客戶端,響應一個“whitelabel”錯誤視圖,以HTML格式呈現(xiàn)相同的數(shù)據(jù)

4. 自定義錯誤視圖解析規(guī)則
- 完全替換默認行為,可以實現(xiàn) ErrorController 并注冊該類型的Bean定義,或添加ErrorAttributes類型的組件
定制錯誤處理邏輯
1. 自定義錯誤頁
- 替換默認的“whitelabel”錯誤視圖,在templates在創(chuàng)建error文件夾,定義404和5xx的視圖error/404.html error/5xx.html
- 有精確的錯誤狀態(tài)碼頁面就匹配精確,沒有就找4xx.html或者N(錯誤狀態(tài)碼首數(shù)字)xx.html;如果都沒有就觸發(fā)白頁

2. 方法一:@ExceptionHandler處理異常
- 注解用來定義一個或多個具體的異常類型,發(fā)生異常時由此處理
- @ControllerAdvice+@ExceptionHandler處理全局異常
- 底層是 ExceptionHandlerExceptionResolver 支持的
/**
* 處理整個web controller的異常
*/
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
//定義可以處理的異常
@ExceptionHandler({ArithmeticException.class,
NullPointerException.class})
public String handleArithException(Exception e){
log.error("異常是:{}",e);
//返回視圖地址,也可以返回ModelAndView
return "login";
}
}3. 方法二:@ResponseStatus+自定義異常
- 指定發(fā)生異常時的響應狀態(tài)碼,自定義異常類型
- 底層是 ResponseStatusExceptionResolver
- 把ResponseStatus注解的信息組裝成ModelAndView返回
- 底層調用 response.sendError(statusCode, resolvedReason);
- tomcat發(fā)送的/error
//異常響應狀態(tài)碼+異常原因
@ResponseStatus(value= HttpStatus.FORBIDDEN,reason = "用戶數(shù)量太多")
public class UserTooManyException extends RuntimeException {
public UserTooManyException(){
}
public UserTooManyException(String message){
super(message);
}
}4. Spring底層的異常
- 如參數(shù)類型轉換異常
- DefaultHandlerExceptionResolver 處理框架底層的異常
- 解析異常時做了一系列異常類型的判斷
- 每個異常處理都會執(zhí)行response.sendError(.....),tomcat發(fā)送/error請求
- 如果還是解析不了,就會響應tomcat的錯誤頁面

5. 方法三:自定義實現(xiàn) HandlerExceptionResolver 處理異常
- @Order(value = Ordered.HIGHEST_PRECEDENCE) 將優(yōu)先級設為最高
- 如果不加優(yōu)先級,默認是排列在自動配置的異常處理器之后,若默認的處理器可以處理異常,故自定義的異常處理器不會生效
- 調用response.sendError(.....),tomcat發(fā)送/error請求
//優(yōu)先級,數(shù)字越小優(yōu)先級越高
@Order(value= Ordered.HIGHEST_PRECEDENCE)
@Component
public class CustomerHandlerExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex) {
try {
//狀態(tài)碼+異常信息
response.sendError(511,"我喜歡的錯誤");
} catch (IOException e) {
e.printStackTrace();
}
return new ModelAndView();
}
}6. 關于response.sendError()
- 自己調用response.sendError(),請求會被轉發(fā)給basicErrorController進行處理
- 如果自己沒有調用,并且異常沒有任何人能夠處理,tomact底層會自動調用response.sendError()將請求轉發(fā)給basicErrorController處理。
- 總之,三種方法最后都會調用sendError()轉交給basicErrorController處理,ErrorViewResolver進行解析,最后會轉到一個頁面或者返回json數(shù)據(jù)。
異常處理自動配置原理
- ErrorMvcAutoConfiguration 自動配置異常處理規(guī)則
1. 綁定配置文件的server 和 spring.mvc

2. 自動添加組件:類型:DefaultErrorAttributes -> id:errorAttributes
- DefaultErrorAttributes:定義錯誤頁面中可以包含哪些數(shù)據(jù)
- DefaultErrorAttributes implements ErrorAttributes,HandlerExceptionResolver
- 自定義錯誤頁面屬性



3. 自動添加組件:類型:BasicErrorController --> id:basicErrorController
- 可以通過BasicErrorController 自定義頁面跳轉邏輯
- 處理默認 /error 路徑的請求;頁面響應 new ModelAndView("error", model),
- 要么響應一個HTML頁面,要么響應一個json


- 容器中有組件 View->id是error;(響應默認錯誤頁)


- 容器中放組件 BeanNameViewResolver(視圖解析器);按照返回的視圖名作為組件的id去容器中找View對象

4. 自動添加組件:類型:DefaultErrorViewResolver -> id:conventionErrorViewResolver
- 如果發(fā)生錯誤,會以HTTP的狀態(tài)碼 作為視圖名字(viewName),找到真正的頁面
- 比如error/404、5xx.html



異常處理步驟流程
- 舉例,執(zhí)行一個controller方法,除數(shù)為0拋出異常
1. doDispatch()中執(zhí)行controller目標方法
- 目標方法運行期間有任何異常都會被catch、而且標志當前請求結束
- 并且將異常賦值給 dispatchException
- 即使目標方法發(fā)生異常,也執(zhí)行視圖解析流程

2. 處理handler發(fā)生的異常,處理完成返回ModelAndView

- 遍歷所有的 handlerExceptionResolvers,看誰能處理當前異常【HandlerExceptionResolver處理器異常解析器】
- DefaultErrorAttributes先來處理異常,把異常信息保存到request域,并且返回null
- 然后交由HandlerExceptionResolverComposite,遍歷其中的異常處理器處理,但此例子默認無法處理
- ExceptionHandlerExceptionResolver,使用注解@ExceptionHandler才能由此解析處理
- ResponseStatusExceptionHandler,使用注解@ResponseStatus才能由此解析處理


3. 默認無法處理目標方法異常時,異常會被拋出
- 底層就會發(fā)送 /error 請求,會被BasicErrorController處理

- 解析錯誤視圖;遍歷所有的 ErrorViewResolver 看誰能解析

4. 模板引擎響應出錯誤視圖
- 默認的 DefaultErrorViewResolver ,作用是把響應狀態(tài)碼作為錯誤頁的地址,error/500.html
- 查找順序:
- '/templates/error/500.html' >
- '/static/error/500.html' >
- '/templates/error/5xx.html' >
- '/static/error/5xx.html'

相關文章
SpringBoot下使用MyBatis-Puls代碼生成器的方法
這篇文章主要介紹了SpringBoot下使用MyBatis-Puls代碼生成器的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-10-10
SpringBoot整合Swagger接口文檔工具的流程步驟
我們在開發(fā)接口的時候,會將接口文檔給前端的開發(fā)者進行對接,我們可以通過Postman或者Yapi等接口管理工具進行編寫管理,實際開發(fā)中,接口的管理確實也應該通過專業(yè)的工具管理,本文,我們就來談談怎么在SpringBoot整合Swagger接口文檔工具2023-08-08
SpringBoot整合Minio實現(xiàn)文件上傳和讀取功能
最近有一個需求是關于視頻上傳播放的,需要設計一個方案,中間談到了Minio這個技術,于是來學習一下,所以本文給大家介紹了SpringBoot整合Minio實現(xiàn)文件上傳和讀取功能,文中有詳細的代碼示例供大家參考,需要的朋友可以參考下2024-07-07
Spring Boot 2 實戰(zhàn):自定義啟動運行邏輯實例詳解
這篇文章主要介紹了Spring Boot 2 實戰(zhàn):自定義啟動運行邏輯,結合實例形式詳細分析了Spring Boot 2自定義啟動運行邏輯詳細操作技巧與注意事項,需要的朋友可以參考下2020-05-05

