• SpringBoot-全局异常处理


    背景

    在 Web 开发中, 我们经常会需要处理各种异常, 这是一件棘手的事情, 需要考虑以下几个问题 :

    • 什么时候需要捕获 ( try-catch ) 异常, 什么时候需要抛出 ( throws ) 异常到上层 ?
    • 在 dao 层捕获还是在 service 捕获, 还是在 controller 层捕获 ?
    • 抛出异常后要怎么处理. 怎么返回给页面错误信息 ?

    全局异常处理

    推荐做法

    • 不要在业务代码中进行捕获异常, 即 dao, service, controller 层的所有异常都全部抛出到上层. 这样不会导致业务代码中的一堆 try-catch 导致业务代码混乱.
    • 哪一层都不捕获.
    • 返回统一的结果集 ( 错误码 + 错误描述 ).

    通常会将事务配置在 Service 层, 当数据库操作失败时, 让 Service 层抛出运行时异常, 而不进行 try-catch 处理,  Spring 事物管理器就会进行回滚. 为了事务回滚

    但 Service 层抛出后. 在 Controller 层就需要 try-catch 去捕获异常, 否则会返回原生错误信息到客户端. 但是, 如果在 Controller 层的每个方法体里面都写一些模板化的 try-catch 的代码, 代码不但不美观, 也增加了维护的难度, 特别是还需要对 Service 层的不同异常进行不同处理的时候.

    @ControllerAdvice 注解是 Spring 3.2 中新增的. 用于拦截全局的 Controller 的异常. 注意:该注解只能拦截 Controller 不能拦截 Interceptor 的异常.

    全局异常处理的步骤

    • 在 SpringMVC / SpringBoot 项目中, 只需要使用 AOP 编写一个全局的异常处理切面类, 用它来统一处理所有的异常即可.
    • 定义一个类, 在类上添加 @ControllerAdvice+@ExceptionHandler注解, 同时需要使用 @ResponseBody 注解表示返回值为 JSON 字符串.

    全局异常处理-实例

    在 Github 上的代码地址:

    github.com/SanJingYe88…

    ① 使用统一的返回值

    在 Controller 层的返回值只有两种, 一种是 Result 作为非分页请求的返回值, 一种是 PageResult 作为分页请求的返回值.

    • Result 非分页请求, 返回结果实体类.
    • PageResult 分页请求, 返回结果实体类.

    ② 全局异常错误

    编写一个 CodeMsg 全局异常错误码实体类. 将错误码集中管理, 然后通过 Result.error(CodeMsg codeMsg) 这种方式调用, 将业务错误码直接传回前端. 并且错误码可以随意扩展.

    ③ 自定义异常类

    • ServiceException 自定义业务异常类. 通过组合, 内部维持一个 CodeMsg 的引用, 在业务层对异常进行实例化并抛出, 让切面 GlobalExceptionHandler 捕获处理. ServiceException
    • CheckException 自定义参数校验异常类.

    ④ 校验工具类

    可以创建校验工具类来对常用的校验做统一抽取, 还可以进行 i18n 国际化显示消息. 这里是我们自己手动编写了校验工具类, 还可以使用 Guava 提供的 Preconditions 类.

    ⑤ 全局异常处理类

    编写 GlobalExceptionHandler 全局异常处理类. 对业务层传输来的异常做判断, 通过 Result.error(ex.getCodeMsg()) 对不同类型的异常统一返回.

    • @ControllerAdvice 注解, 在类上使用, 表示该类为全局异常处理类, 当 Controller 层抛出异常时调用.
    • @ExceptionHandler 注解, 在方法上使用, 表示该方法在发生何种类型异常时会被调用. 由该注解的 value 属性决定.

    全局异常处理不生效的可能原因

    • 被 Swagger自带的注解影响到了,RequestMapping 注解,一定要放在 Swagger 相关注解的前面。
    • 多模块工程,全局异常处理器没有被 Sping 扫描到,所以无法处理。

  • 相关阅读:
    从零开始C语言精讲篇2:分支与循环
    源码分享-M3U8数据流ts的AES-128解密并合并---GoLang实现
    AI绘画普及课【二】文生图入门
    Vue2.js:v-click-outside自定义指令和vue-click-outside监听鼠标点击元素外部区域事件
    Beego入门简单构建, 连接MySQL实现增查操作
    基于三维GIS的不动产管理应用
    leetcode 764. 最大加号标志
    若依系统分离版去除redis数据库
    开源美颜滤镜SDK代码解析
    TRex学习之旅十一
  • 原文地址:https://blog.csdn.net/Trouvailless/article/details/126462631