基于spring boot实现一个全局异常处理器

 更新时间:2023年09月10日 16:39:54   作者:Java小卷  
在项目开发中,我们可以基于spring boot提供的切面特性,来很轻松的实现全局异常的处理,所以本文主要为大家介绍了如何基于spring boot实现一个全局异常处理器,有需要的可以参考下

还记得前面我们的实现逻辑,在service层如果有校验失败我们会抛出异常,而controller中我们对其并没有处理,实际上spring boot有自己全局的错误处理形式。我们可以基于spring boot提供的切面特性,来很轻松的实现全局异常的处理,现在我们约定,只要后台逻辑处理失败的情况,我们都将抛出异常,包括controller中的处理逻辑。

实现全局异常处理器

现在我们就来编写全局异常处理器。

package com.xiaojuan.boot.common.web.support;
import ...
import static com.xiaojuan.boot.common.enums.BusinessError.*;
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    /** 维护一个错误码与http状态码的映射 */
    private Map<Integer, HttpStatus> httpStatusMap;
    @PostConstruct
    private void init() {
        httpStatusMap = new HashMap<>();
        httpStatusMap.put(NO_LOGIN.getValue(), HttpStatus.UNAUTHORIZED);
        httpStatusMap.put(HAS_NO_ROLE.getValue(), HttpStatus.FORBIDDEN);
    }
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<Response<?>> handleException(BusinessException ex) {
        log.error(ex.getMessage(), ex);
        // 默认服务器端错误,返回500状态码
        HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;
        if (!StringUtils.isEmpty(ex.getErrCode()) && httpStatusMap.containsKey(ex.getErrCode())) {
            status = httpStatusMap.get(ex.getErrCode());
        }
        return ResponseEntity.status(status).body(Response.fail(ex.getMessage(), ex.getErrCode(), ex.getData()));
    }
    @ExceptionHandler(Exception.class)
    public ResponseEntity<Response<?>> handleException(Exception ex) {
        log.error(ex.getMessage(), ex);
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Response.fail("小卷生鲜电商系统异常:" + ex.getMessage()));
    }
}

代码详解

这里我们用了@RestControllerAdvice注解对所有的@RestController修饰的controller都进行拦截,只要抛出了异常,就交给这个处理器来处理。

这里要说下响应的http状态码,一般都返回200,某些情况下我们将返回一个可以让前端特别处理的状态码,比如用户未登录的请求被拦截了我们可以返回401,用户登录了却没有权限的操作,我们返回403,这样前端对这块直接从http状态就能识别请求结果的状态。而对于我们业务开发来说,关注的是业务处理的错误码,在这里我们和请求http状态码之间做了一个映射转换,维护在httpStatusMap成员变量中。

接下来,我们写了两个异常处理方法,它们都必须用@ExceptionHandler注解来指定我们要处理的异常的类型,这里我们只考虑两种异常:我们自定义的业务异常BusinessException和最大的Exception

对于BusinessException,我们要考虑HttpStatus的判断逻辑,如果我们将某些业务错误码和http状态码做了映射,那么对于这些业务错误码我们就取映射到的http状态码来返回,否则我们返回服务器端错误的500状态码。

注意处理方法最后的返回结果,我们使用的是ResponseEntity<Response<?>>,spring web模块提供的ResponseEntity可以帮助我们按照指定的http状态码并解析指定格式的内容体(Spring Boot默认配置json形式)进行前端响应。而要响应的对象就是我们之前定义的Response,只不过我们将字段errCode的类型从原来的String改成了Integer,因为业务错误码我们就定义为数值型,同样的还有BusinessException类中的errCode字段类型的调整。

除了BusinessException,我们只处理最大的Exception,http状态码固定为500,错误消息也统一以固定的形式开头。

错误码枚举类

将应用中业务错误码我们定义在一个枚举中进行维护:

package com.xiaojuan.boot.common.enums;
import ...
@Getter
@AllArgsConstructor
public enum BusinessError {
    PARAM_INVALID("参数校验失败", 10001),
    RECORD_EXISTS("后台记录已存在", 10002),
    HAS_NO_ROLE("用户未授权,不能访问", 403),
    NO_LOGIN("请先登录再操作", 401);
    private final String label;
    private final Integer value;
}

这里我们给出默认的说明,一般在抛出业务异常时我们可以指定更具体的错误,而不会使用这里默认的错误消息。

service层抛出异常调整

现在我们对service层抛出异常做下调整,一般我们只要传入错误信息来构造BusinessException。有些时候我们还可以传入错误码来进一步区分这些错误。

实现自己的Assert工具

既然我们先前定义了自己的BusinessException,并且在其中维护了业务错误码errCode,就没必要用spring的Assert工具了,因为它抛出来的是IllegalStateException异常,最终被我们全局异常处理器以最大的Exception的处理逻辑进行包装响应结果,自然“参数校验失败”的错误码类型就丢了,因此这里我们基于spring对Assert的实现,我们包装为自己的Assert

package com.xiaojuan.boot.util;
import ...
public class Assert {
    public static void hasText(@Nullable String text, String message) {
        if (!StringUtils.hasText(text)) {
            throw new BusinessException(message, BusinessError.PARAM_INVALID.getValue());
        }
    }
}

controller层抛出异常

最后我们将原来预留todo注释的地方改为抛出异常的形式:

最后,我们再基于test.http对抛出异常的测试场景进行测试,看是否达到预期的http状态码和json结构,这个大家自行测试。

到此这篇关于基于spring boot实现一个全局异常处理器的文章就介绍到这了,更多相关spring boot全局异常处理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java桥接模式实例详解【简单版与升级版】

    Java桥接模式实例详解【简单版与升级版】

    这篇文章主要介绍了Java桥接模式,结合实例形式分析了java桥接模式简单版与升级版两种实现技巧,需要的朋友可以参考下
    2019-07-07
  • Java批量插入数据的代码实现

    Java批量插入数据的代码实现

    日常工作或者学习中,可能会遇到批量插入数据的需求,一般情况下数据量少的时候,我们会直接调用批量接口插入数据即可,当数据量特别大时,我们就会用到分批插入数据,所以本文给大家介绍了Java批量插入数据的代码实现,需要的朋友可以参考下
    2024-01-01
  • springmvc实现导出数据信息为excle表格示例代码

    springmvc实现导出数据信息为excle表格示例代码

    本篇文章主要介绍了springmvc实现导出数据信息为excle表格,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧。
    2017-01-01
  • 基于Jenkins搭建.NET FrameWork持续集成环境

    基于Jenkins搭建.NET FrameWork持续集成环境

    这篇文章主要介绍了基于Jenkins搭建.NET FrameWork持续集成环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • Java使用JXLS实现导出Excel

    Java使用JXLS实现导出Excel

    jxls作为一个开源工具,提供了一种高效且易于维护的方式来处理复杂的Excel导出需求,下面就跟随小编一起来学习一下如何使用jxls实现导出Excel吧
    2025-01-01
  • IDEA下Maven的pom文件导入依赖出现Auto build completed with errors的问题

    IDEA下Maven的pom文件导入依赖出现Auto build completed with errors的问题

    这篇文章主要介绍了IDEA下Maven的pom文件导入依赖出现Auto build completed with errors,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-06-06
  • java制作广告图片自动轮播控件

    java制作广告图片自动轮播控件

    本文给大家分享了2款java实现的首页广告图片自动轮播的控件,分别是PC端和移动端的,效果非常不错,有需要的小伙伴可以参考下。
    2015-10-10
  • Java访问权限控制的重要性深入讲解

    Java访问权限控制的重要性深入讲解

    这篇文章主要给大家介绍了关于Java访问权限控制的重要性的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-11-11
  • 详解java倒计时三种简单实现方式

    详解java倒计时三种简单实现方式

    这篇文章主要介绍了详解java倒计时三种简单实现方式,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • 详解HttpSecurity是如何组装过滤器链的

    详解HttpSecurity是如何组装过滤器链的

    HttpSecurity 本质上也是一个 SecurityBuilder,我们平时在 HttpSecurity 配置的各种东西,本质上其实就是一个 xxxConfigure,这些 xxxConfigure 被 HttpSecurity 收集起来,本文将给大家介绍HttpSecurity是如何组装过滤器链的,需要的朋友可以参考下
    2024-06-06

最新评论