SpringBoot中的统一异常处理示例代码

 更新时间:2026年03月20日 15:28:30   作者:新绿MEHO  
本文给大家介绍SpringBoot中的统一异常处理示例代码,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

统一异常处理

统⼀异常处理使⽤的是 @ControllerAdvice + @ExceptionHandler 来实现的,
@ControllerAdvice 表⽰控制器通知类, @ExceptionHandler 是异常处理器,两个结合表
⽰当出现异常的时候执⾏某个通知,也就是执⾏某个方法事件。

代码示例

ExceptionAdvice 

接⼝返回为数据时, 需要加 @ResponseBody 注解!!!

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import springbook.model.Result;
@Slf4j
@ResponseBody
@ControllerAdvice
public class ExceptionAdvice {
    @ExceptionHandler
    public Result handlerException(Exception e){
        log.error("发生异常, e: {}", e);
        return Result.fail("内部错误");
    }
    @ExceptionHandler
    public Result handlerException(NullPointerException e){
        log.error("发生异常, e:", e);
        return Result.fail("发生空指针异常");
    }
    @ExceptionHandler
    public Result handlerException(ArithmeticException e){
        log.error("发生异常, e:", e);
        return Result.fail("发生算术异常");
    }
}

 Result

import lombok.Data;
import springbook.enums.ResultStatus;
@Data
public class Result<T> {
    private ResultStatus code; 
    private String errMsg; //错误信息, 如果业务成功, errMsg为空
    private T data;
    public static <T> Result success(T data){
        Result result = new Result<>();
        result.setCode(ResultStatus.SUCCESS);
        result.setData(data);
        return result;
    }
    public static Result fail(String msg){
        Result result = new Result<>();
        result.setCode(ResultStatus.FAIl);
        result.setErrMsg(msg);
        return result;
    }
    public static Result fail(ResultStatus resultStatus, String msg){
        Result result = new Result<>();
        result.setCode(resultStatus);
        result.setErrMsg(msg);
        return result;
    }
}

TestController

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/test")
@RestController
public class TestController {
    @RequestMapping("/t1")
    public String t1(){
        int result = 10/0;
        return "string";
    }
    @RequestMapping("/t2")
    public Integer t2(){
        String str = null;
        System.out.println(str.length());
        return 1;
    }
    @RequestMapping("/t3")
    public Boolean t3(){
        Integer[] integers = new Integer[]{1,2,3,4};
        System.out.println(integers[5]);
        return true;
    }
}

运行结果 

t1的运行结果:

t2的运行结果:

t3的运行结果:

问题

我们知道,ArithmeticException和NullPointerException都属于RuntimeException,同时RuntimeException又属于Exception。

那么为什么同时有处理ArithmeticException和Exception的方法时,针对ArithmeticException异常,会调用处理ArithmeticException异常的方法而不是调用处理Exception异常的方法?

那么为什么同时有处理NullPointerException和Exception的方法时,针对NullPointerException异常,会调用处理NullPointerException异常的方法而不是调用处理Exception异常的方法?

结合源码了解问题源头 

下面通过Debug的方式,结合源码来剖析为什么会出现上面的问题。

以上面代码的访问test/t1路径下方法导致ArithmeticException异常为例:

经过Debug,我了解到,处理异常会走到下图所示的ExceptionHandlerMethodResolver类里面的getMapperMethod()方法:

在刚进入该方法的时候,经过第一个黄色框内代码的处理后,会把当前具有处理异常的方法结合当前发生的异常进行匹配,最终匹配到两个合适类型的异常,分别是Exception异常和ArithmeticException异常:

但是在经过第二个黄色框内的代码处理后,会对刚刚匹配到的异常进行排序,根据异常的深度进行排序,并返回深度最浅的异常(即返回最合适的异常)。

经过第二个黄色框内的代码处理后,matches里面的内容顺序发生变动:

此时,我们就知道了为什么同时有处理ArithmeticException和Exception的方法时,针对ArithmeticException异常,会调用处理ArithmeticException异常的方法而不是调用处理Exception异常的方法;以及为什么同时有处理NullPointerException和Exception的方法时,针对NullPointerException异常,会调用处理NullPointerException异常的方法而不是调用处理Exception异常的方法。

优点

1. 提高用户体验
        友好的错误信息:通过统一异常处理,可以为前端或其他服务提供一致的、易于理解的错误信息,而不是直接暴露后端的堆栈跟踪或技术细节,从而提升用户体验。
        避免敏感信息泄露:统一处理可以避免在异常响应中不小心泄露敏感信息,如数据库表结构、内部实现细节等。
2. 业务逻辑和异常处理逻辑解耦
        代码结构清晰:将异常处理逻辑从业务逻辑中分离出来,使得业务代码更加专注于业务逻辑的实现,而异常处理代码则专注于异常的捕获、处理和响应。
        易于维护:当需要修改异常处理逻辑时,只需在统一异常处理类中修改,而无需在多个业务代码中逐一修改,降低了维护成本。
3. 减少冗余代码
        避免重复编写:在传统的Java开发中,异常处理通常是分散在代码的各个部分中的。而使用统一异常处理可以避免在每个可能抛出异常的地方编写重复的异常处理代码。
        提高代码复用性:通过定义全局的异常处理类,可以实现对多种异常的统一处理,提高代码的复用性。
4. 便于代码风格统一
        风格一致:统一异常处理有助于保持代码风格的一致性,使得整个项目的代码更加规范、整洁。
        提升可读性:对于其他开发者来说,阅读和理解统一异常处理的代码也更为容易。
5. 便于异常监控和日志记录
        集中监控:通过统一异常处理,可以更容易地实现对异常情况的集中监控和统计,为后续的故障排查和性能优化提供依据。
        详细日志:在异常处理过程中,可以记录详细的异常信息和上下文信息,便于后续的日志分析和问题定位。

到此这篇关于SpringBoot中的统一异常处理示例代码的文章就介绍到这了,更多相关SpringBoot统一异常处理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 使用Runtime 调用Process.waitfor导致的阻塞问题

    使用Runtime 调用Process.waitfor导致的阻塞问题

    这篇文章主要介绍了使用Runtime 调用Process.waitfor导致的阻塞问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • java学习DongTai被动型IAST工具部署过程

    java学习DongTai被动型IAST工具部署过程

    被动型IAST被认为是DevSecOps测试阶段实现自动化安全测试的最佳工具,而就在前几天,洞态IAST正式开源了,这对于甲方构建安全工具链来说,绝对是一个大利好
    2021-10-10
  • JavaSE中compare、compareTo的区别

    JavaSE中compare、compareTo的区别

    本文主要介绍了JavaSE中compare、compareTo的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • 使用mockito编写测试用例教程

    使用mockito编写测试用例教程

    这篇文章主要为大家介绍了使用mockito编写测试用例教程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • SSM框架下如何实现数据从后台传输到前台

    SSM框架下如何实现数据从后台传输到前台

    这篇文章主要介绍了SSM框架下如何实现数据从后台传输到前台,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-05-05
  • SpringBoot2.6.x升级后循环依赖及Swagger无法使用问题

    SpringBoot2.6.x升级后循环依赖及Swagger无法使用问题

    这篇文章主要为大家介绍了SpringBoot2.6.x升级后循环依赖及Swagger无法使用问题,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • Java中的多线程与并发编程的核心原理

    Java中的多线程与并发编程的核心原理

    本文系统讲解Java多线程与并发编程,涵盖线程创建方式、同步机制及并发工具类,并提供最佳实践,指导开发者构建高效、可靠的多线程应用,感兴趣的朋友跟随小编一起看看吧
    2025-08-08
  • mybatis3中@SelectProvider传递参数方式

    mybatis3中@SelectProvider传递参数方式

    这篇文章主要介绍了mybatis3中@SelectProvider传递参数方式。具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • 剖析Java中线程编程的概念

    剖析Java中线程编程的概念

    这篇文章主要介绍了Java中线程编程的概念,是Java入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09
  • 深入Java不可变类型的详解

    深入Java不可变类型的详解

    本篇文章是Java中的不可变类型进行了详细的分析介绍,需要的朋友参考下
    2013-06-06

最新评论