成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Spring Boot 優雅捕捉異常的幾種姿勢!

開發 前端
通過@ControllerAdvice和@ExceptionHandler注解實現全局異常攔截,在之前的文章中我們有多次介紹過,它可以攔截controller層請求方法拋出的異常信息,同時外加@ ResponseBody注解,可以實現響應類型為json格式。

01、背景介紹

在上文中,我們介紹了在 Spring Boot 中實現接口數據格式的統一返回處理實現,其中就包括程序運行時的異常處理,通過全局異常處理器,可以簡化代碼邏輯,統一響應格式。

其實在 Spring Boot 中,針對controller層的異常處理有很多種辦法。今天通過這篇文章,我們就一起來總結一下相關異常處理的實現方式。

02、方案實踐

在 Spring Boot 中針對controller層的異常處理,有兩種常用實現方式,都可以達到簡化代碼邏輯的效果。

  • 方式一:通過@ControllerAdvice和@ExceptionHandler注解實現全局異常的處理
  • 方式二:通過實現HandlerExceptionResolver接口來完成全局異常的處理

下面我們一起來看看具體實現。

2.1、全局異常處理方式一

通過@ControllerAdvice和@ExceptionHandler注解實現全局異常攔截,在之前的文章中我們有多次介紹過,它可以攔截controller層請求方法拋出的異常信息,同時外加@ ResponseBody注解,可以實現響應類型為json格式。

例如,現在有兩種異常類型NullPointerException和Exception,分別對其進行捕捉,具體實現如下!

@ControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 優先處理空指針異常
     * @param e
     * @return
     */
    @ExceptionHandler(value = {NullPointerException.class})
    @ResponseBody
    public Object nullPointerExceptionHandler(HttpServletRequest request, NullPointerException e){
        LOGGER.error("發生空指針異常,請求地址:{}, 錯誤信息:{}", request.getRequestURI(), e.getMessage());
        return ResultMsg.fail(500, e.getMessage());
    }


    /**
     * 兜底處理其它異常
     * @param e
     * @return
     */
    @ExceptionHandler(value = {Exception.class})
    @ResponseBody
    public Object exceptionHandler(HttpServletRequest request, Exception e){
        LOGGER.error("未知異常,請求地址:{}, 錯誤信息:{}", request.getRequestURI(), e.getMessage());
        return ResultMsg.fail(999, e.getMessage());
    }
}

測試代碼,如下:

@RestController
public class HelloController {

    @GetMapping(value = "/add")
    public String hello(){
        if(1 ==1){
            throw new NullPointerException("空指針測試");
        }
        return "hello world";
    }

    @GetMapping(value = "/delete")
    public String delete(){
        if(1 ==1){
            throw new RuntimeException("其它測試");
        }
        return "hello world";
    }
}

啟動服務后,在瀏覽器中請求http://localhost:8080/add,結果如下:

圖片圖片

請求http://localhost:8080/delete,結果如下:

圖片圖片

結果與預期一致。

2.1.1、自定義異常類實現

很多場景下,我們希望通過自定義異常類來返回相關錯誤信息,如何實現呢?

首先自定義一個異常類CustomerException。

public class CustomerException extends RuntimeException {

    private Integer code;

    public Integer getCode() {
        return code;
    }

    public CustomerException(String message) {
        super(message);
        this.code = 500;
    }

    public CustomerException(Integer code, String message) {
        super(message);
        this.code = code;
    }
}

然后,在全局異常處理器中增加相關的捕捉方法。

/**
 * 處理自定義的異常
 * @param e
 * @return
 */
@ExceptionHandler(value = {CustomerException.class})
@ResponseBody
public Object customerExceptionHandler(HttpServletRequest request, CustomerException e){
    LOGGER.error("發生業務異常,請求地址:{}, 錯誤信息:{}", request.getRequestURI(), e.getMessage());
    return ResultMsg.fail(e.getCode(), e.getMessage());
}

測試代碼,如下:

@GetMapping(value = "/update")
public String update(){
    if(1 ==1){
        throw new CustomerException(4003, "請求ID不能為空");
    }
    return "hello world";
}

啟動服務后,在瀏覽器中請求http://localhost:8080/update,結果如下:

圖片圖片

結果與預期一致!

2.1.2、404 異常特殊處理

默認情況下,@ExceptionHandler注解無法捕捉到 404 異常,比如請求一個無效的地址,返回信息如下:

圖片圖片

如果想要捕捉到這種異常,可以在application.properties文件中添加如下配置來實現。

# 如果沒有找到請求地址,拋異常
spring.mvc.throw-exception-if-no-handler-found=true
# 關閉默認的靜態資源路徑映射
spring.resources.add-mappings=false

啟動服務后,再次發起地址請求,結果如下:

圖片圖片

對于前后端分離開發的情況,這種方式非常實用;但是如果前后端不分離的項目,比如訪問項目/static目錄下的靜態資源,可能前端無法正常訪問。

此時,我們可以手動添加資源映射,比如如下操作,前端就能正常訪問靜態資源了。

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 允許訪問localhost:8080/static/目錄下的靜態資源
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
    }
}
2.1.3、自定義異常頁面實現

某些場景下,當發生異常時希望跳轉到自定義的異常頁面,如何實現呢?

首先,這里基于thymeleaf模板引擎來開發頁面,在templates目錄下創建一個異常頁面error.html。

<!DOCTYPE html>
<html lang="en" >
<head>
    <meta charset="UTF-8">
    <title>錯誤頁面</title>
</head>
<body>
出錯啦,請與管理員聯系<br>
<span th:text="${message}"></span>
</body>
</html>

然后,修改異常捕捉方法,這里無需添加@ResponseBody注解,示例如下。

@ControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 跳轉到異常頁面
     * @param e
     * @return
     */
    @ExceptionHandler(value = {Exception.class})
    public ModelAndView exceptionHandler(HttpServletRequest request, Exception e){
        LOGGER.error("未知異常,請求地址:{}, 錯誤信息:{}", request.getRequestURI(), e.getMessage());
        ModelAndView mv = new ModelAndView();
        // 添加錯誤信息對象
        mv.addObject("message", e.getMessage());
        // 要跳轉的頁面視圖
        mv.setViewName("error");
        return mv;
    }
}

啟動服務后,在瀏覽器中再次請求http://localhost:8080/update,結果如下:

圖片圖片

結果與預期一致!

2.1.4、RestControllerAdvice和ControllerAdvice的區別

很多同學喜歡用@RestControllerAdvice來代替@ControllerAdvice和@ResponseBody。

例如如下示例!

@RestControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 處理所有異常,以json方式響應
     * @param e
     * @return
     */
    @ExceptionHandler(value = {Exception.class})
    public Object exceptionHandler(HttpServletRequest request, Exception e){
        LOGGER.error("未知異常,請求地址:{}, 錯誤信息:{}", request.getRequestURI(), e.getMessage());
        return ResultMsg.fail(999, e.getMessage());
    }
}

實現效果,與上文等價。

打開@RestControllerAdvice的源碼,你會發現它將@ControllerAdvice和@ResponseBody注解組合在一起了,因此同時具備兩者效果,部分源碼如下:

package org.springframework.web.bind.annotation;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ControllerAdvice
@ResponseBody
public @interface RestControllerAdvice {
    @AliasFor("basePackages")
    String[] value() default {};

    @AliasFor("value")
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};

    Class<?>[] assignableTypes() default {};

    Class<? extends Annotation>[] annotations() default {};
}

2.2、全局異常處理方式二

在 Spring Boot 中,除了通過@ControllerAdvice和@ExceptionHandler注解實現全局異常處理外,還有一種通過實現HandlerExceptionResolver接口來完成全局異常的處理。

具體實現示例如下:

@Component
public class CustomExceptionResolver implements HandlerExceptionResolver {

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomExceptionResolver.class);

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {
        LOGGER.error("接口請求出現異常,請求地址:{},錯誤信息:{}", request.getRequestURI(), e.getMessage());
        if(e instanceof RuntimeException){
            // 設置響應類型為json格式
            ModelAndView mv = new ModelAndView(new MappingJackson2JsonView());
            mv.addObject("code", 500);
            mv.addObject("msg", e.getMessage());
            return mv;
        } else {
            // 設置響應類型為錯誤頁面
            ModelAndView mv = new ModelAndView();
            mv.addObject("message", e.getMessage());
            mv.setViewName("error");
            return mv;
        }
    }
}

當出現異常的時候,結果會以json格式響應給客戶端。

啟動服務后,發起地址請求,結果如下:

圖片

這種思路的實現原理,主要是通過 SpringMVC 的異常處理鏈路器來完成異常的全局處理。

SpringMVC 支持用戶自定義異常處理類(需要實現HandlerExceptionResolver),當發生異常時,默認異常處理類無法處理時,就會交給自定義異常處理類來完成。實現方面比較靈活,即可以實現以json格式響應,也可以以頁面視圖的方式響應。

雖然這種方式能夠處理全局異常,但是 Spring 官方不推薦使用它;同時實測過程中發現它無法攔截 404 錯誤,當請求錯誤地址時,會優先被DefaultHandlerExceptionResolver默認異常處理類攔截,自定義的異常處理類無法捕捉。

03、小結

最后總結一下,雖然方式一和方式二都可以實現controller層接口請求異常的全局處理,但是在實際使用中,推薦方式一,簡單好維護。

示例代碼地址:

https://gitee.com/pzblogs/spring-boot-example-demo

責任編輯:武曉燕 來源: 潘志的研發筆記
相關推薦

2025-03-11 00:55:00

Spring停機安全

2024-10-18 08:53:49

SpringMybatis微服務

2019-08-29 14:30:16

代碼開發工具

2022-10-26 07:14:25

Spring 6Spring業務

2021-04-20 10:50:38

Spring Boot代碼Java

2021-09-15 16:20:02

Spring BootFilterJava

2020-08-05 08:30:25

Spring BootJavaSE代碼

2020-03-16 17:20:02

異常處理Spring Boot

2023-01-30 07:41:43

2011-01-20 10:09:25

2025-02-19 12:00:00

SpringBootDeepSeekAI

2025-02-07 09:11:04

JSON對象策略

2020-04-13 15:25:01

MySQL數據庫模糊搜索

2020-06-18 08:18:35

密碼加密安全

2024-08-01 09:10:03

2024-08-12 10:13:01

2023-04-17 23:49:09

開發代碼Java

2024-12-06 09:27:28

2021-09-26 09:40:25

React代碼前端

2022-04-08 16:27:48

SpringBoot異常處理
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产一区二区久久 | 欧美特级黄色 | 日韩欧美网 | 欧美一区二区三区在线播放 | 国产黄色网 | 中文字幕 国产 | 亚洲一区在线日韩在线深爱 | 亚洲成av人影片在线观看 | 亚洲成人久久久 | 天堂中文字幕av | 国产精品免费在线 | 在线观看成人小视频 | 日韩欧美视频在线 | 亚洲电影第三页 | 国产一级成人 | 亚洲高清在线观看 | 中文字幕加勒比 | www国产亚洲精品 | 日日操操 | 中文日本在线 | 久久久精品天堂 | 成人在线视频一区 | 国精产品一区二区三区 | 欧美日韩视频在线播放 | 欧洲一级视频 | 婷婷综合五月天 | 久久久噜噜噜www成人网 | 天堂av免费观看 | www..99re| 国产免费色 | 精品国产欧美 | 青青久在线视频 | 天天av网| 亚洲不卡在线观看 | 久久精品国产亚洲一区二区三区 | 久久久性 | 国产视频第一页 | 久久中文字幕一区 | 丁香五月网久久综合 | 国产一级成人 | 精品国产乱码久久久久久久久 |