【springboot全局异常处理2】--- 模仿log.error()自定义异常+自定义checkedException


本文源码地址: https://github.com/nieandsun/NRSC-STUDY

1 简单介绍项目中遇到的情况

项目中碰到了比较复杂的参数校验,于是自定义了校验规则,但前端想要获取到具体失败的原因。


问题也就成了这样: 都是参数异常,但是由于各个参数不一样,且校验失败的原因也不一样,感觉使用太多枚举来定义这些异常也没太大的必要 — 因为这些异常信息几乎没有通用性。


于是想到了像打印log日志一样来定义输出的异常,举例来讲,要抛异常时,直接按照下面的方式进行抛出:

 //比较复杂的异常 --  类似于log.error()方法
 //第一个参数为异常code;
 //第二个参数是要给前端的提示信息,但有些地方使用了占位符
 //其余的参数是占位符实际的值
 else if (id == -2) {
     throw new ElegantRuntimeException(ResultEnum.COMPLEX_FAILURE.getCode(),
             "我是比较{}复杂的异常{}", "=====", "哈哈");
 }

2 具体代码实现

仅仅列出了关键代码,具体代码有兴趣的可从github上clone下来看一下。

  • ElegantRuntimeException的构造方法
/***
  * 含有占位符的异常
  * @param code
  * @param message
  * @param arguments
  */
 public ElegantRuntimeException(Integer code, String message, Object... arguments) {
     super("自定义异常---之复杂异常");
     String formatMsg = FormatStringUtils.formatMessage(message, '{', '}');
     //利用arguments替换占位符
     this.complexMsg = MessageFormat.format(formatMsg, arguments);
     this.code = code;
 }
  • formatMessage方法的具体实现
package com.nrsc.elegant.util;

import java.util.LinkedList;

public class FormatStringUtils {

    private FormatStringUtils() {
    }
    
    /***
     * 将字符串  我是{},你是{},他是{} ----> 转成 我是{0},你是{1},他是{2}
     * @param message
     * @param prefix
     * @param suffix
     * @return
     */
    public static String formatMessage(String message, char prefix, char suffix) {
        LinkedList<Character> chars = new LinkedList<>();
        int j = 0;
        for (int i = 0; i < message.length(); i++) {
            if (prefix == message.charAt(i) && suffix == message.charAt(i + 1)) {
                chars.add(prefix);
                chars.add(Character.forDigit(j, 10));
                j++;
            } else {
                chars.add(message.charAt(i));
            }
        }
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < chars.size(); i++) {
            sb.append(chars.get(i));
        }
        return sb.toString();
    }
}

3 简单测试

测试方法如下:

在这里插入图片描述
即当启动程序,访问/getUserById/-2时,会抛出上面自定义的异常。

—> 效果如下,说明我们自定义的异常已经成功。
在这里插入图片描述


4 自定义checkedException在真实项目中几乎也必不可少

众所周知,异常主要分为两类:

  • 检查式异常(checkedException),也称为非运行时异常

这种异常需要try…catch捕获,或者向上抛出,否则无法通过编译(程序中会有报错)。

  • 运行时异常(RuntimeException)

这种异常不需要捕获,也不需要向上抛出,虚拟机会处理。


在实际开发中,我们可能很容易想到要自定义一个运行时异常,然后借助统一异常处理的方式来简化代码的开发 —> 提高代码的质量。

但是自定义检查式异常(checkedException)在真实项目中几乎也必不可少,举个栗子来讲 —>

假设有一个方法A依赖于另一个方法B的运行结果
假如方法B报了异常,而如果该异常没有向上抛出,那A方法将无法捕捉到该异常
那A 方法就会无法判断B方法到底有没有运行成功

因此我在代码里同时自定义了一个checkedException,代码基本和自定义的RuntimeException一致,只是该类继承了Exception类,而自定义的RuntimeException继承了RuntimeException类,代码如下:

package com.nrsc.elegant.exception;


import com.nrsc.elegant.enums.ResultEnum;
import com.nrsc.elegant.util.FormatStringUtils;
import lombok.Getter;

import java.text.MessageFormat;

/***
 * @author : Sun Chuan
 * @date : 2019/10/18 22:21
 * Description:自定义异常
 *                  --- 该异常如果在代码语句里抛出,方法上也必须抛出异常
 *                  --- 当然也可以直接try..catch掉
 *
 *                  ---在实际开发中可以发现这种自定义异常几乎也是必不可少的
 */
@Getter
public class ElegantCheckedException extends Exception {

    private Integer code;

    private String complexMsg;


    public ElegantCheckedException(ResultEnum resultEnum) {
        super(resultEnum.getMessage());
        this.code = resultEnum.getCode();
    }

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

    public ElegantCheckedException(Integer code, String message, Object... arguments) {
        super("自定义异常---之复杂异常");
        String formatMsg = FormatStringUtils.formatMessage(message, '{', '}');
        this.complexMsg = MessageFormat.format(formatMsg, arguments);
        this.code = code;
    }
}

此时统一处理自定义异常的方法就变成了下面的样子:


/***
 * 自定义异常 --- 自定义异常一般不要设置为ERROR级别,因为我们用自定义的异常主要是为了辅助我们处理业务逻辑,
 *          --- 它们其实并不能被真正当作异常来看待
 * @param e
 * @return
 */
@ResponseStatus(HttpStatus.IM_USED)
@ExceptionHandler(value = {ElegantRuntimeException.class})
@ResponseBody
public ResultVO elegantExceptionHandle(ElegantRuntimeException e) {
    log.warn("【自定义异常】", e);
    if (e.getComplexMsg() != null) {
        return ResultVOUtil.error(e.getCode(), e.getComplexMsg());
    }
    return ResultVOUtil.error(e.getCode(), e.getMessage());
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值