天天看點

Spring Boot 2.X(十一):全局異常處理

前言

在 Java Web 系統開發中,不管是 Controller 層、Service 層還是 Dao 層,都有可能抛出異常。如果在每個方法中加上各種 try catch 的異常處理代碼,那樣會使代碼非常繁瑣。在Spring MVC 中,我們可以将所有類型的異常處理從各個單獨的方法中解耦出來,進行異常資訊的統一處理和維護。

在 Spring MVC 中全局異常捕獲處理的解決方案通常有兩種方式:

1.使用 @ControllerAdvice + @ExceptionHandler 注解進行全局的 Controller 層異常處理。

2.實作 org.springframework.webb.servlet.HandlerExceptionResolver 接口中的 resolveException 方法。

使用 @ControllerAdvice + @ExceptionHandler 注解

1.定義統一異常處理類

@ControllerAdvice
public class GlobalExceptionHandler {

    private Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(value = Exception.class)
    public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) {
        log.error("ExceptionHandler ===>" + e.getMessage());
        e.printStackTrace();
        // 這裡可根據不同異常引起的類做不同處理方式
        String exceptionName = ClassUtils.getShortName(e.getClass());
        log.error("ExceptionHandler ===>" + exceptionName);
        ModelAndView mav = new ModelAndView();
        mav.addObject("stackTrace", e.getStackTrace());
        mav.addObject("errorMessage", e.getMessage());
        mav.addObject("url", req.getRequestURL());
        mav.setViewName("forward:/error/500");
        return mav;
    }
}           

其中 @ExceptionHandler(value = Exception.class) 中的捕獲異常 value 可以自定義,如下:

類型 描述
NullPointerException 當應用程式試圖通路空對象時,則抛出該異常
SQLException 提供關于資料庫通路錯誤或其他錯誤資訊的異常
IndexOutOfBoundsException 訓示某排序索引(例如對數組、字元串或向量的排序)超出範圍時抛出
NumberFormatException 當應用程式試圖将字元串轉換成一種數值類型,但該字元串不能轉換為适當格式時,抛出該異常
FileNotFoundException 當試圖打開指定路徑名表示的檔案失敗時,抛出此異常
IOException 當發生某種I/O異常時,抛出此異常。此類是失敗或中斷的I/O操作生成的異常的通用類
ClassCastException 當試圖将對象強制轉換為不是執行個體的子類時,抛出該異常
ArrayStoreException 試圖将錯誤類型的對象存儲到一個對象數組時抛出的異常
IllegalArgumentException 抛出的異常表明向方法傳遞了一個不合法或不正确的參數
ArithmeticException 當出現異常的運算條件時,抛出此異常。例如,一個整數“除以零”時,抛出此類的一個執行個體
NegativeArraySizeException 如果應用程式試圖建立大小為負的數組,則抛出該異常
NoSuchMethodException 無法找到某一特定方法時,抛出該異常
SecurityException 由安全管理器抛出的異常,訓示存在安全侵犯
UnsupportedOperationException 當不支援請求的操作時,抛出該異常
RuntimeException 是那些可能在Java虛拟機正常運作期間抛出的異常的超類

當捕獲到響應的異常類型時,會進入 defaultErrorHandler() 方法中的邏輯:把異常資訊放入 model,跳轉至 /error/500 請求URL。

2.異常資訊展現

視圖控制器配置

@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

    /**
     * 視圖控制器配置
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {    
        registry.addViewController("/").setViewName("/index");//設定預設跳轉視圖為 /index
        registry.addViewController("/error/500").setViewName("/error/500");
        registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
        super.addViewControllers(registry);
        
    }
    
}           

視圖模闆

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>Exception</h1>
<h3 th:text="${url}"></h3>
<h3 th:text="${errorMessage}"></h3>
<p  th:each="line : ${stackTrace}" th:text="${line}">  </p>
</body>
</html>           

3.測試異常類

@Controller
public class TestController {

    @GetMapping("/index")
    public String hello() {
        int x = 1 / 0;
        return "hello";
    }
}
           

4.運作測試

浏覽器通路:

http://127.0.0.1:8080/index
Spring Boot 2.X(十一):全局異常處理
@ControllerAdvice 還能結合 @ModelAttribute 、@InitBinder 注解一起使用,實作全局資料綁定和全局資料預處理等功能。

實作 HandlerExceptionResolver 接口

@Component
public class GlobalHandlerExceptionResolver implements HandlerExceptionResolver {

    private Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) {
        Exception e = new Exception();
        //處理 UndeclaredThrowableException
        if (ex instanceof UndeclaredThrowableException) {
            e = (Exception) ((UndeclaredThrowableException) ex).getUndeclaredThrowable();
        } else {
            e = ex;
        }
        e.printStackTrace();
        //這裡可以根據不同異常引起的類做不同處理方式
        String exceptionName = ClassUtils.getShortName(e.getClass());
        if(exceptionName.equals("ArrayIndexOutOfBoundsException")) {
            log.error("GlobalHandlerExceptionResolver resolveException ===>" + exceptionName);
            ModelAndView mav = new ModelAndView();
            mav.addObject("stackTrace", e.getStackTrace());
            mav.addObject("exceptionName", exceptionName);
            mav.addObject("errorMessage", e.getMessage());
            mav.addObject("url", request.getRequestURL());
            mav.setViewName("forward:/error/500");
            return mav;
        }
        return null;
    }

}           
UndeclaredThrowableException 異常通常是在 RPC 接口調用場景或者使用 JDK 動态代理的場景時發生。如果不預先處理轉換,測試捕獲到的異常則為 UndeclaredThrowableException,而不是真實的異常對象。

2.異常資訊展現 同上

@Controller
public class TestController {

    @GetMapping("/test")
    public String test() {
        String[] ss = new String[] { "1", "2" };
        System.out.print(ss[2]);
        return "hello";
    }

}           

4.測試運作

測試前先把 @ControllerAdvice 注釋了。

http://127.0.0.1:8080/test
Spring Boot 2.X(十一):全局異常處理

示例代碼

github 碼雲

非特殊說明,本文版權歸

朝霧輕寒

所有,轉載請注明出處.

原文标題:Spring Boot 2.X(十一):全局異常處理

原文位址:

https://www.zwqh.top/article/info/20

如果文章對您有幫助,請掃碼關注下我的公衆号,文章持續更新中...