1.全局異常處理
1.1什么是全局異常處理器
全局異常處理器是SpringMVC框架中的一種異常處理機制,用于統一處理由控制器拋出的異常。
全局異常處理器可以幫助我們捕獲和處理控制器中的異常,并且根據不同的異常類型進行不同的處理操作,從而保障應用的健壯性和穩定性。
當然,SpringMVC中有內置的異常處理對象,但是呈現的結果對于用戶端不友好,所以實際項目我們一般會使用全局異常處理器處理異常。
如果僅僅在項目中寫下以下代碼,會導致異常處理呈現的結果用戶端難以理解。
@RestController
@RequestMapping("/v1/tests/")
public class TestController {@GetMapping("test")public JsonResult test(Integer id) {if (id < 0) {throw new IllegalArgumentException("id不能小于0");}return new JsonResult(200,"成功訪問");}
}
如果我們能做到像一些企業級的異常應對措施,比如bilibili
當輸入網址https://www.bilibili.com/id=111
這個地址根本不存在,結果返回一個“找不到頁面”的頁面。
這種處理效果是 前端+后端共同開發的效果,采用后端捕獲異常 + 前端自定義錯誤頁面渲染 的組合處理方式。
前后端分離(REST 風格)
用全局異常處理器統一返回結構化 JSON
由前端(如 Vue、React)判斷 status 或 code,顯示漂亮的提示頁面
{ "code": 404, "msg": "資源不存在", "data": null }
然后前端根據 code == 404
顯示“找不到頁面”的提示比如嗶哩嗶哩的效果。
1.2 全局異常處理器的配置
Spring MVC中的全局異常處理器可以通過以下方式進行配置:
1. 創建 exception.GlobalExceptionHandler 類,并添加異常處理方法;
使用 @ControllerAdvice 注解 + ResponseBody注解 或者 @RestControllerAdvice 注解標注該類;
2. 在異常處理方法上添加 @ExceptionHandler 注解,用于指定控制器中需要處理的異常類型。
@ControllerAdvice
?
@ControllerAdvice
本質上是一個帶有@Component
的注解,Spring 啟動時會將它的類掃描進容器中。它內部利用 AOP 和 HandlerExceptionResolver 原理,在 Controller 執行過程中如果拋出了異常,就會查找有沒有全局的異常處理器處理它。
@ExceptionHandler
@Exception注解 指定:這個方法能處理哪種異常類型
它的參數是異常對象(如
IllegalArgumentException e
),Spring 會自動注入你可以根據異常信息生成 JSON 響應、記錄日志等
我們來進行優化上面的代碼,在TestController基礎上加上GlobalHandlerException類
@RestController
@RequestMapping("/v1/tests/")
public class TestController {@GetMapping("test")public JsonResult test(Integer id) {if (id < 0) {throw new IllegalArgumentException("id不能小于0");}return new JsonResult(200,"成功訪問");}
}@Slf4j
@RestControllerAdvice
public class GlobalHandlerException {@ExceptionHandlerpublic String doHandlerIllegalArgumentExceptionException(IllegalArgumentException ex){log.error("ex : " + ex);return ex.getMessage();}
}
此時雖然沒有嗶哩嗶哩網址那么華麗,但是總歸是可以讓用戶清晰的知道不能傳遞id < 0這個限制了。
1.3 使用流程
1)創建全局異常處理器類
工程目錄下創建 exception.GlobalExceptionHandler
@ControllerAdvice 注解
定義全局異常處理器,處理Controller中拋出的異常。
@RestControllerAdvice 注解
復合注解,是 @ControllerAdvice 注解和 @ResponseBody 注解的組合;
用于捕獲Controller中拋出的異常并對異常進行統一的處理,還可以對返回的數據進行處理。
2)創建異常處理方法
在異常處理方法上添加 @ExceptionHandler 注解
@ExceptionHandler 注解
用于捕獲Controller處理請求時拋出的異常,并進行統一的處理。
示例
/**ex.getMessage()方法:用于捕獲異常信息
*/
@ExceptionHandler
public JsonResult doHandleRuntimeException(RuntimeException ex){log.error("error is " + ex.getMessage());return new JsonResult(StatusCode.OPERATION_FAILED,ex.getMessage());
}
1.4 全局異常處理器示例
1)微博詳情頁異常拋出
public JsonResult selectById(int id){if(id < 0) {throw new IllegalArgumentException("id值無效");}... ...
}
2)全局異常處理
exception.GlobalExceptionHandler 類
package cn.tedu.weibo.exception;import cn.tedu.weibo.common.response.JsonResult;
import cn.tedu.weibo.common.response.StatusCode;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;/*** RestControllerAdvice 是復合注解,描述的類型為一個全局異常處理對象類型,* 等價于:@ControllerAdvice+@ResponseBody* 當某個Controller方法中出現了異常,系統底層就會查找有沒有定義全局異常處理對象。* 這個全局異常處理對象中有沒有定義對應的異常處理方法,假如有就調用此方法處理異常。*/@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {/*** @ExceptionHandler 描述的方法為一個異常處理方法,在此注解內部可以定義具體的異常處理* 類型(例如RuntimeException),此注解描述的方法需要定義一個異常類型的形式參數,* 通過這個參數接收具體的異常對象(也可以接收其異常類型對應的子類類型的異常)。*/@ExceptionHandlerpublic JsonResult doHandleRuntimeException(RuntimeException ex){log.error("error is " + ex.getMessage());return new JsonResult(StatusCode.OPERATION_FAILED,ex.getMessage());}/*** 假如用全局異常處理對象處理Controller類中出現的異常,全局異常處理對象會優先查找與Controller* 中相匹配的異常處理方法,假如沒有,會查找對應異常的父類異常處理方法。*/@ExceptionHandlerpublic JsonResult doHandleRuntimeException(IllegalArgumentException ex){log.error("IllegalArgumentException is " + ex.getMessage());return new JsonResult(StatusCode.OPERATION_FAILED,ex.getMessage());}
}
3)重啟工程測試
http://localhost:8080/v1/weibo/selectById?id=-1
2 關于Throwable
在開發實踐中,通常會添加一個處理 Throwable
的方法,它將可以處理所有類型的異常,則不會再出現500
錯誤!
Throwable
是 Java 所有異常(Exception)和錯誤(Error)的頂層父類。
GlobalExceptionHandler
中添加處理 Throwable 的方法
@ExceptionHandler
public JsonResult handleThrowable(Throwable e) {return new JsonResult(8888, "程序運行過程中出現了Throwable");
}
這個方法千萬不要隨便加,不然后續出了異常就看不出來了,可以等到項目開發的差不多了,測試bug也都找全了,準備上線了再添加。