首页 > 其他分享 >SpringBoot统一异常处理

SpringBoot统一异常处理

时间:2023-05-08 10:23:25浏览次数:35  
标签:code return String message 统一 异常 public SpringBoot

SpringBoot统一异常处理

概述

Spring在3.2版本增加了一个注解@ControllerAdvice,可以与@ExceptionHandler@InitBinder@ModelAttribute 等注解注解配套使用。

简单的说,该注解可以把异常处理器应用到所有控制器,而不是单个控制器。借助该注解,我们可以实现:在独立的某个地方,比如单独一个类,定义一套对各种异常的处理机制,然后在类的签名加上注解@ControllerAdvice,统一对 不同阶段的、不同异常 进行处理。这就是统一异常处理的原理。

对异常按阶段进行分类,大体可以分成:进入Controller前的异常 和 Service 层异常

image

目标就是消灭95%以上的 try catch 代码块,并以优雅的 Assert(断言) 方式来校验业务的异常情况,只关注业务逻辑,而不用花费大量精力写冗余的 try catch 代码块。

为什么要优雅的处理异常

在后端发生异常或者是请求出错时,前端通常显示如下

Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.

Fri Jun 07 15:38:07 CST 2022
There was an unexpected error (type=Not Found, status=404).
No message available

对于用户来说非常不友好。

在 Controller 里提供接口,通常需要捕捉异常,进行异常处理。最简单的方法使用try/catch进行异常捕捉。

@Slf4j
@Api(value = "User Interfaces", tags = "User Interfaces")
@RestController
@RequestMapping("/user")
public class UserController {

    /**
     * http://localhost:8080/user/add .
     *
     * @param userParam user param
     * @return user
     */
    @ApiOperation("Add User")
    @ApiImplicitParam(name = "userParam", type = "body", dataTypeClass = UserParam.class, required = true)
    @PostMapping("add")
    public ResponseEntity<String> add(@Valid @RequestBody UserParam userParam) {
        // 每个接口充斥着大量的异常处理
        try {
            // do something
        } catch(Exception e) {
            return ResponseEntity.fail("error");
        }
        return ResponseEntity.ok("success");
    }
}

当方法很多,每个都需要 try catch,代码会显得臃肿,写起来也比较麻烦。

这时就需要进行统一的异常处理。

全局异常统一处理

通过 Spring 的 AOP 特性就可以很方便的实现异常的统一处理:使用@ControllerAdvice、@RestControllerAdvice捕获运行时异常。

创建全局异常处理类GlobalExceptionHandler

@RestControllerAdvice
public class GlobalExceptionHandler {

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

    /**
     * 基础异常
     */
    @ExceptionHandler(BaseException.class)
    public R baseException(BaseException e) {
        log.warn(e.getMessage(), e);
        return R.error(e.getMessage());
    }

    /**
     * 业务异常
     */
    @ExceptionHandler(BusinessException.class)
    public R businessException(BusinessException e) {
        log.warn(e.getMessage(), e);
        if (StringUtils.isNull(e.getCode())) {
            return R.error(e.getMessage());
        }
        return R.error(e.getCode(), e.getMessage());
    }
}

创建基础异常处理类BaseException

public class BaseException extends RuntimeException {
    private static final long serialVersionUID = 1L;

    /**
     * 所属模块
     */
    private String module;

    /**
     * 错误码
     */
    private String code;

    /**
     * 错误码对应的参数
     */
    private Object[] args;

    /**
     * 错误消息
     */
    private String defaultMessage;

    public BaseException(String module, String code, Object[] args, String defaultMessage) {
        this.module = module;
        this.code = code;
        this.args = args;
        this.defaultMessage = defaultMessage;
    }

    public BaseException(String module, String code, Object[] args) {
        this(module, code, args, null);
    }

    public BaseException(String module, String defaultMessage) {
        this(module, null, null, defaultMessage);
    }

    public BaseException(String code, Object[] args) {
        this(null, code, args, null);
    }

    public BaseException(String defaultMessage) {
        this(null, null, null, defaultMessage);
    }

    @Override
    public String getMessage() {
        String message = null;
        if (!StringUtils.isEmpty(code)) {
            message = MessageUtils.message(code, args);
        }
        if (message == null) {
            message = defaultMessage;
        }
        return message;
    }

    public String getModule() {
        return module;
    }

    public String getCode() {
        return code;
    }

    public Object[] getArgs() {
        return args;
    }

    public String getDefaultMessage() {
        return defaultMessage;
    }
}

创建业务异常处理类BusinessException

public class BusinessException extends RuntimeException {
    private static final long serialVersionUID = 1L;

    private Integer code;

    private String message;

    public BusinessException(String message) {
        this.message = message;
    }

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

    public BusinessException(String message, Throwable e) {
        super(message, e);
        this.message = message;
    }

    @Override
    public String getMessage() {
        return message;
    }

    public Integer getCode() {
        return code;
    }
}

业务实现类中抛出异常

@Service
public class UserServiceImpl {

    public Object getBusinessException() {
        throw new BusinessException(ExceptionEnum.IS_NOT_NULL.getCode(),
                ExceptionEnum.IS_NOT_NULL.getMsg(), "参数");
    }
}

具体的异常代码可以在ExceptionEnum枚举类中自定义

/**
 * 异常枚举类
 */
public enum ExceptionEnum {
    // 400
    BAD_REQUEST("400", "请求数据格式不正确!"),
    UNAUTHORIZED("401", "登录凭证过期!"),
    FORBIDDEN("403", "没有访问权限!"),
    NOT_FOUND("404", "请求的资源找不到!"),
    // 500
    INTERNAL_SERVER_ERROR("500", "服务器内部错误!"),
    SERVICE_UNAVAILABLE("503", "服务器正忙,请稍后再试!"),
    // 未知异常
    UNKNOWN("10000", "未知异常!"),
    // 自定义
    IS_NOT_NULL("10001","%s不能为空");

    /**
     * 错误码
     */
    private String code;

    /**
     * 错误描述
     */
    private String msg;

    ExceptionEnum(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public String getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

Controller接口中无需处理异常

@Api(tags = "用户")
@RestController
@RequestMapping("/user")
public class UserController{
	
	@ApiOperation("Add User")
	@ApiImplicitParam(name = "userParam", type = "body", dataTypeClass = UserParam.class, required = true)
	@PostMapping("add")
	public ResponseEntity<UserParam> add(@Valid @RequestBody UserParam userParam) {
	    return ResponseEntity.ok(userParam);
	}
}

标签:code,return,String,message,统一,异常,public,SpringBoot
From: https://www.cnblogs.com/leepandar/p/17380910.html

相关文章

  • SpringBoot添加日志
    SpringBoot添加日志前言SpringBoot使用ApacheCommons日志记录进行所有内部日志记录。SpringBoot的默认配置支持使用JavaUtilLogging,Log4j2和Logback。使用这些,可以配置控制台日志记录以及文件日志记录。如果使用的是SpringBootStarters,Logback将为日志记录提供良好的支......
  • Java开发、SpringBoot开发(狂神说Java)
    目录JavaSpringBoot开发学习(狂神说Java)SpringBoot概述微服务SpringBoot程序安装测试配置文件原理自动配置主启动类yaml语法给属性赋值的几种方式JR303校验多环境配置及配置文件位置SpringBootWeb开发理论静态资源首页模板引擎Thymeleaf语法MVC配置原理,扩展SpringMVC视图解析视......
  • SpringBoot访问外部接口
    SpringBoot访问外部接口原生的Http请求@RequestMapping("/doPostGetJson")publicStringdoPostGetJson()throwsParseException{//此处将要发送的数据转换为json格式字符串StringjsonText="{id:1}";JSONObjectjson=(JSONObject)JSONObject.parse(jsonTe......
  • 记一次 .NET 某车零件MES系统 登录异常分析
    一:背景1.讲故事这个案例有点特殊,以前dump分析都是和软件工程师打交道,这次和非业内人士交流,隔行如隔山,从指导dump怎么抓到问题解决,需要一个强大的耐心。前几天有位朋友在微信上找到我,说他们公司采购的MES系统登录的时候出现了异常,让我帮忙看一下,我在想解铃还须系铃人,怎么的也不......
  • java基于springboot+vue非前后端分离的学生成绩管理系统、学生信息管理系统,附源码+数
    1、项目介绍java基于springboot+vue非前后端分离的学生成绩管理系统、学生信息管理系统。本文首先介绍了学生成绩管理的技术发展背景与发展现状,然后遵循软件常规开发流程,首先针对系统选取适用的语言和开发平台,根据需求分析制定模块并设计数据库结构,再根据系统总体功能模块的设计......
  • Solon 统一的返回结果调整
    使用“统一的渲染控制”可以对输出做统一的控制外。。。还可以借助路由拦截器RouterInterceptor,对mvc返回结果做提交确认机制(即可修改)进行控制(相对来讲,这个可能更简单)。。。关于全局的请求异常处理,最好不要放在这里。。。放到过滤器(因为它是最外层的,还可以捕捉mvc之外的异......
  • swagger3.0集成 (springboot2.6.7)
    springboot2.6.7+swagger3.0导入依赖<dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version></dependency>s......
  • Springboot 自定义Web容器
    Springboot自定义Web容器如果你的项目并发量比较高,想要修改最大线程数、最大连接数等配置信息,可以通过自定义Web容器的方式,代码如下所示。@SpringBootApplication(proxyBeanMethods=false)publicclassAppimplementsWebServerFactoryCustomizer<ConfigurableServletWebSer......
  • Mac睡眠时经常异常唤醒问题的处理
    源引自:https://wo.zhaoxin.pro/16682846375746.html问题最近从英特尔芯片的iMac5K,换成了苹果芯片的Macmini。一切都好,就是电脑在睡眠之后,经常会异常唤醒。表现为显示器由黑转亮,同时显示为无信号;键盘背景灯变亮;外置机械硬盘启动,发出噪音。然后几秒后,电脑又睡眠了。这个过程在......
  • 存储双活同步导致数据库异常恢复---惜分飞
    联系:手机/微信(+8617813235971)QQ(107644445)标题:存储双活同步导致数据库异常恢复作者:惜分飞©版权所有[未经本人同意,不得以任何形式转载,否则有进一步追究法律责任的权利.]客户双活存储异常之后,单个存储运行,故障存储修复之后,双活同步,出现多套系统异常,上一篇:Controlf......