(转)Spring Boot项目优雅的全局异常处理方式

2023-05-16

转自: Spring Boot项目优雅的全局异常处理方式(全网最新) - 掘金


【0】readme

在日常项目开发中,异常是常见的,但是如何更高效的处理好异常信息,让我们能快速定位到BUG,是很重要的,不仅能够提高我们的开发效率,还能让你代码看上去更舒服,SpringBoot的项目已经对有一定的异常处理了,但是对于我们开发者而言可能就不太合适了,因此我们需要对这些异常进行统一的捕获并处理。


【1】全局异常处理方式一

SpringBoot中,@ControllerAdvice 即可开启全局异常处理,使用该注解表示开启了全局异常的捕获,我们只需在自定义一个方法使用@ExceptionHandler注解然后定义捕获异常的类型即可对这些捕获的异常进行统一的处理。

【1.1】自定义全局异常类

/**
 * @description: 自定义异常处理
 * @author: DT
 * @date: 2021/4/19 21:17
 * @version: v1.0
 */
@ControllerAdvice
public class MyExceptionHandler {

    @ExceptionHandler(value =Exception.class)
    @ResponseBody
    public String exceptionHandler(Exception e){
        System.out.println("全局异常捕获>>>:"+e);
        return "全局异常捕获,错误原因>>>"+e.getMessage();
    }
}

【1.2】手动抛出异常

 @GetMapping("/getById/{userId}")
public CommonResult<User> getById(@PathVariable Integer userId){
    // 手动抛出异常
    int a = 10/0;
    return CommonResult.success(userService.getById(userId));
}

【1.3】测试打印

 

很显然这样的用户体验效果是极差的,虽然这种能够让我们知道异常的原因,但是在很多的情况下来说,可能还是不够人性化,不符合我们的要求。


【2】 全局异常处理方式二

【2.1】定义基础接口类

/**
 * @description: 服务接口类
 * @author: DT
 * @date: 2021/4/19 21:39
 */
public interface BaseErrorInfoInterface {

    /**
     *  错误码
     * @return
     */
    String getResultCode();

    /**
     * 错误描述
     * @return
     */
    String getResultMsg();
}

【2.2】定义枚举类

/**
 * @description: 异常处理枚举类
 * @author: DT
 * @date: 2021/4/19 21:41
 * @version: v1.0
 */
public enum ExceptionEnum implements BaseErrorInfoInterface{
    
    // 数据操作错误定义
    SUCCESS("2000", "成功!"),
    BODY_NOT_MATCH("4000","请求的数据格式不符!"),
    SIGNATURE_NOT_MATCH("4001","请求的数字签名不匹配!"),
    NOT_FOUND("4004", "未找到该资源!"),
    INTERNAL_SERVER_ERROR("5000", "服务器内部错误!"),
    SERVER_BUSY("5003","服务器正忙,请稍后再试!");

    /**
     * 错误码
     */
    private final String resultCode;

    /**
     * 错误描述
     */
    private final String resultMsg;

    ExceptionEnum(String resultCode, String resultMsg) {
        this.resultCode = resultCode;
        this.resultMsg = resultMsg;
    }

    @Override
    public String getResultCode() {
        return resultCode;
    }

    @Override
    public String getResultMsg() {
        return resultMsg;
    }
}

【2.3】自定义异常类

/**
 * @description: 自定义异常类
 * @author: DT
 * @date: 2021/4/19 21:44
 * @version: v1.0
 */
public class BizException extends RuntimeException{

    private static final long serialVersionUID = 1L;

    /**
     * 错误码
     */
    protected String errorCode;
    /**
     * 错误信息
     */
    protected String errorMsg;

    public BizException() {
        super();
    }

    public BizException(BaseErrorInfoInterface errorInfoInterface) {
        super(errorInfoInterface.getResultCode());
        this.errorCode = errorInfoInterface.getResultCode();
        this.errorMsg = errorInfoInterface.getResultMsg();
    }

    public BizException(BaseErrorInfoInterface errorInfoInterface, Throwable cause) {
        super(errorInfoInterface.getResultCode(), cause);
        this.errorCode = errorInfoInterface.getResultCode();
        this.errorMsg = errorInfoInterface.getResultMsg();
    }

    public BizException(String errorMsg) {
        super(errorMsg);
        this.errorMsg = errorMsg;
    }

    public BizException(String errorCode, String errorMsg) {
        super(errorCode);
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
    }

    public BizException(String errorCode, String errorMsg, Throwable cause) {
        super(errorCode, cause);
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
    }


    public String getErrorCode() {
        return errorCode;
    }

    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }

    public String getErrorMsg() {
        return errorMsg;
    }

    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }

    @Override
    public Throwable fillInStackTrace() {
        return this;
    }
}

【2.4】自定义数据传输

/**
 * @description: 自定义数据传输
 * @author: DT
 * @date: 2021/4/19 21:47
 * @version: v1.0
 */
public class ResultResponse {
    /**
     * 响应代码
     */
    private String code;

    /**
     * 响应消息
     */
    private String message;

    /**
     * 响应结果
     */
    private Object result;

    public ResultResponse() {
    }

    public ResultResponse(BaseErrorInfoInterface errorInfo) {
        this.code = errorInfo.getResultCode();
        this.message = errorInfo.getResultMsg();
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getResult() {
        return result;
    }

    public void setResult(Object result) {
        this.result = result;
    }

    /**
     * 成功
     *
     * @return
     */
    public static ResultResponse success() {
        return success(null);
    }

    /**
     * 成功
     * @param data
     * @return
     */
    public static ResultResponse success(Object data) {
        ResultResponse rb = new ResultResponse();
        rb.setCode(ExceptionEnum.SUCCESS.getResultCode());
        rb.setMessage(ExceptionEnum.SUCCESS.getResultMsg());
        rb.setResult(data);
        return rb;
    }

    /**
     * 失败
     */
    public static ResultResponse error(BaseErrorInfoInterface errorInfo) {
        ResultResponse rb = new ResultResponse();
        rb.setCode(errorInfo.getResultCode());
        rb.setMessage(errorInfo.getResultMsg());
        rb.setResult(null);
        return rb;
    }

    /**
     * 失败
     */
    public static ResultResponse error(String code, String message) {
        ResultResponse rb = new ResultResponse();
        rb.setCode(code);
        rb.setMessage(message);
        rb.setResult(null);
        return rb;
    }

    /**
     * 失败
     */
    public static ResultResponse error( String message) {
        ResultResponse rb = new ResultResponse();
        rb.setCode("-1");
        rb.setMessage(message);
        rb.setResult(null);
        return rb;
    }

    @Override
    public String toString() {
        return JSONObject.toJSONString(this);
    }

}

【2.5】自定义全局异常处理

/**
 * @description: 自定义异常处理
 * @author: DT
 * @date: 2021/4/19 21:51
 * @version: v1.0
 */
@ControllerAdvice
public class GlobalExceptionHandler {
    
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 处理自定义的业务异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = BizException.class)
    @ResponseBody
    public ResultResponse bizExceptionHandler(HttpServletRequest req, BizException e){
        logger.error("发生业务异常!原因是:{}",e.getErrorMsg());
        return ResultResponse.error(e.getErrorCode(),e.getErrorMsg());
    }

    /**
     * 处理空指针的异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =NullPointerException.class)
    @ResponseBody
    public ResultResponse exceptionHandler(HttpServletRequest req, NullPointerException e){
        logger.error("发生空指针异常!原因是:",e);
        return ResultResponse.error(ExceptionEnum.BODY_NOT_MATCH);
    }

    /**
     * 处理其他异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =Exception.class)
    @ResponseBody
    public ResultResponse exceptionHandler(HttpServletRequest req, Exception e){
        logger.error("未知异常!原因是:",e);
        return ResultResponse.error(ExceptionEnum.INTERNAL_SERVER_ERROR);
    }
}

【2.6】测试代码

【2.6.1】自定义异常

@PostMapping("/add")
public boolean add(@RequestBody User user) {
    //如果姓名为空就手动抛出一个自定义的异常!
    if(user.getName()==null){
        throw  new BizException("-1","用户姓名不能为空!");
    }
    return true;
}

【2.6.2】空指针异常

 @PutMapping("/update")
public boolean update(@RequestBody User user) {
    //这里故意造成一个空指针的异常,并且不进行处理
    String str = null;
    str.equals("111");
    return true;
}

【2.6.3】数值转换异常 

 @DeleteMapping("/delete")
public boolean delete(@RequestBody User user)  {
    //这里故意造成一个异常,并且不进行处理
    Integer.parseInt("abc123");
    return true;
}

如果我们想捕获这个类型转换异常,是不是再添加一个异常处理方法就可了。

【2.6.4】处理类型转换异常(新增一个异常)

/**
* 处理类型转换异常
 * @param req
 * @param e
 * @return
 */
@ExceptionHandler(value = NumberFormatException.class)
@ResponseBody
public ResultResponse exceptionHandler(HttpServletRequest req, NumberFormatException e){
    logger.error("发生类型转换异常!原因是:",e);
    return ResultResponse.error(ExceptionEnum.PARAMS_NOT_CONVERT);
}


PARAMS_NOT_CONVERT("4002","类型转换不对!"), 

【注意】

自定义全局异常处理除了可以处理上述的数据格式之外,也可以处理页面的跳转,只需在新增的异常方法的返回处理上填写该跳转的路径并不使用ResponseBody 注解即可。

【总结】

异常处理,能够减少代码的重复度和复杂度,有利于代码的维护,并且能够快速定位到BUG,大大提高我们的开发效率。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

(转)Spring Boot项目优雅的全局异常处理方式 的相关文章

随机推荐

  • 维修1台联想SR550服务器亮黄灯 感叹号 开不了机

    客户信息 xff1a 一个省外客户朋友公司 设备型号 xff1a Lenovo ThinkSystem SR550 故障问题 xff1a 主机前面板亮黄灯 xff0c 能开机但无法正常完成BIOS UEFI自检程序 xff0c 故障界面 x
  • Android 8.0 利用Settings.Global属性跨应用定义标志位

    需求 需要在不同应用中定义一个标志位 xff0c 这里介绍下系统级别的应用和非系统级别应用如何添加 当然这不一定是最好的办法 xff0c 因为不能够添加intent putExtra 属性 系统级别应用 在需要定义的地方使用 SystemP
  • k-近邻算法实现手写数字识别系统

    k 近邻算法实现手写数字识别系统 一 实验介绍 1 1 实验内容 本实验将会从电影题材分类的例子入手 xff0c 详细讲述k 近邻算法的原理 在这之后 xff0c 我们将会使用该算法实现手写数字识别系统 1 2 课程来源 本课程源自 图灵教
  • 调整eclipse控制台console的方法

    调整eclipse控制台console的方法 会把在用eclipse的过程中产生的问题和找到的解决方案记录一下 xff0c 以便之后再用到 今天在运行代码的时候 xff0c 突然控制台和代码并列了 然后百度了一下找到了方法 windows
  • Linux: 运行sh命令时command not found

    问题 xff1a 解决 xff1a 1 查看PATH变量 echo PATH 2 把查询出来的PATH放到sh文件中并导入
  • 修改git tag的描述信息

    今天手贱 xff0c 非要用TortoiseGit打tag xff0c 没用命令行 xff0c 结果这不是还没有学习么 xff0c 然后就出现问题了 不过好在是我自己的Toy代码 xff0c 那就看看如何解决吧 问题描述 使用Tortois
  • Linux 设置用户登录超时

    Linux 系统中使用SSH进行远程登录 xff0c 如果长时间不操作将自动注销用户的登录 原本以为在 etc ssh sshd config文件中配置 查了资料和测试只需要在shell环境变量中设置即可 span class hljs c
  • rime配置

    文件路径 AppData Rime 配置修改 default custom yaml span class hljs label customization span span class hljs label distribution c
  • matlab中(),[],与{}的区别认识

    转载自 http blog csdn net CV YOU article details 52873666 在matlab中 xff0c 常常会遇到 xff0c 和 这个3种符号怎么区分 xff0c 怎么用 xff0c 这里我来总结一下
  • WinServer2012 R2忘记密码的解决方案+远程连接另一种莫名其妙故障

    WinServer2012 R2忘记密码的解决方案 43 远程连接另一种莫名其妙故障 参考文章 xff1a xff08 1 xff09 WinServer2012 R2忘记密码的解决方案 43 远程连接另一种莫名其妙故障 xff08 2 x
  • 迅雷 应版权方要求,文件无法下载 解决方法

    迅雷 应版权方要求 xff0c 文件无法下载 解决方法 参考文章 xff1a xff08 1 xff09 迅雷 应版权方要求 xff0c 文件无法下载 解决方法 xff08 2 xff09 https www cnblogs com sui
  • redis集群搭建报错-(error) CLUSTERDOWN The cluster is down

    README 最近搭建一个redis集群 xff0c 参考博文 xff08 https www cnblogs com mafly p redis cluster html xff09 对集群配置后 xff0c master xff0c s
  • rabbitmq-通配符模式

    README 本文介绍 通配符模式 xff0c 及代码示例 1 intro to rabbitmq通配符模式 0 xff09 通配符模式 交换机类型为 Topic xff1b 1 xff09 与路由模式相比 xff0c 相同点是 两者都可以
  • springboot:BeanPostProcessor示例及分析

    README 1 xff0c 本文主要分析 BeanPostProcessor 的作用 xff0c 开发方式 xff1b 2 xff0c BeanPostProcessor 是bean后置处理器 xff0c 简而言之就是bean被创建好了
  • 字节数组转jsonobject(如读取HttpServletRequest.inputstream到jsonobject)

    README 本文po出了 如何读取 字节数组到jsonobject xff1b 字节数组如何获取 xff0c 本文不再赘述 xff1b 1 代码 64 Description 字节数组转json演示 64 author xiao tang
  • 中断屏蔽技术

    README 本文总结自bilibili 计算机组成原理 xff08 哈工大刘宏伟 xff09 的视频讲解 xff0c 非常棒 xff0c 墙裂推荐 xff1b 1 中断屏蔽 1 xff0c 中断屏蔽的意思是 xff0c 在中断1的服务程序
  • NIST BGP SRx的使用

    NIST BGPsec的使用 地址 xff1a https github com usnistgov NIST BGP SRx 推荐使用centos 7 安装依赖包 xff0c 就是CAT CONTENT grep requires下面那个
  • (转)微服务架构图

    转自 xff1a https blog csdn net qq 38036909 article details 127847139
  • (转)Servlet的过滤器与Spring拦截器详解

    转自 xff1a https blog csdn net vbirdbest article details 72898776 1 过滤器 Filter 1 1 Filter简介 Servlet API中提供了一个javax servlet
  • (转)Spring Boot项目优雅的全局异常处理方式

    转自 xff1a Spring Boot项目优雅的全局异常处理方式 xff08 全网最新 xff09 掘金 0 readme 在日常项目开发中 xff0c 异常是常见的 xff0c 但是如何更高效的处理好异常信息 xff0c 让我们能快速定