编写一个全局异常处理器

(来自鱼皮项目编程导航 - 程序员一站式编程学习交流社区,做您编程学习路上的导航员,作者:liyupi (程序员鱼皮) · GitHub

有不正确的地方,欢迎更正

一、什么是全局异常处理器?

全局异常处理器是一种用于集中处理应用程序中未被捕获的异常的机制。我们在编写程序时,会判断这个方法是否返回正确,是否出现了异常。基于全局考虑,我们将异常处理放到一个类去判断,它的主要作用是统一异常处理逻辑,避免重复代码,并确保返回给客户端的错误信息格式一致。这样就对项目进行了解耦,更好地维护项目程序。

二、编写全局异常处理器

编写一个自定义错误码 ErrorCode.java

public enum ErrorCode {

    SUCCESS(0, "ok"),
    PARAMS_ERROR(40000, "请求参数错误"),
    NOT_LOGIN_ERROR(40100, "未登录"),
    NO_AUTH_ERROR(40101, "无权限"),
    NOT_FOUND_ERROR(40400, "请求数据不存在"),
    FORBIDDEN_ERROR(40300, "禁止访问"),
    SYSTEM_ERROR(50000, "系统内部异常"),
    OPERATION_ERROR(50001, "操作失败");

    /**
     * 状态码
     */
    private final int code;

    /**
     * 信息
     */
    private final String message;

    ErrorCode(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }

}

编写一个通用返回类 BaseResponse.java

作用:用于对响应做出封装,统一返回值

定义三个变量code——错误码;data——数据;message——异常信息

根据JAVA多态的特性,编写两个处理方法BaseResponse,来接收、处理传入的不一样的参数

@Data
public class BaseResponse<T> implements Serializable {

    private int code;

    private T data;

    private String message;

    public BaseResponse(int code, T data, String message) {
        this.code = code;
        this.data = data;
        this.message = message;
    }

    public BaseResponse(int code, T data) {
        this(code, data, "");
    }

    public BaseResponse(ErrorCode errorCode) {
        this(errorCode.getCode(), null, errorCode.getMessage());
    }
}

拓展:

1.什么是JAVA多态特性?

JAVA的多态特性是指:JAVA的类或者方法在被调用时,会根据传入的参数的个数和类型来判断使用哪一个方法。

其中有两个类型:

方法重载:多个方法名字相同,但是传入的参数个数或者类型不同,当被调用时,就会判断传递参数的个数和类型,来确定应该调用的是哪个方法。

方法重写:在子类继承父类时,可能会重写父类的方法,当子类调用父类的方法时,会根据调用的对象,去执行相应的对象重写的方法。

2.@Data的作用

@Data是Lombok库中的一个注解,他的主要作用是通过自动生成以下代码来减少开发者手动编写工作:

  • Getter和Setter方法:为类中每个字段生成getter和setter方法
  • toString方法:生成toString()方法,用于打印对象是输出字段信息
  • equals和hasCode方法:生成equals()和hasCode()方法,用于比较对象是否相等以及哈希值计算
  • 构造方法(可选):如果类中有final字段,会生成包含这些字段的构造方法

注意:如果要使用该注解

  • 需要在项目中引入依赖
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.28</version> <!-- 版本号根据实际需求选择 -->
    <scope>provided</scope>
</dependency>
  • 在IDEA中安装Lombok插件

编写一个返回工具类 ResultUtils.java

作用:封装业务逻辑的响应结果。通过静态方法,将操作的成功或失败结果以统一的格式(BaseResponse对象)返回给调用结果

public class ResultUtils {

    /**
     * 成功
     *
     * @param data
     * @param <T>
     * @return
     */
    public static <T> BaseResponse<T> success(T data) {  //返回成功
        return new BaseResponse<>(0, data, "ok");
        //主要目的是封装业务逻辑的响应结果,将状态码 (code)、
        // 数据 (data) 和消息 (message) 封装到 BaseResponse 对象中
    }

    /**
     * 失败 ————方法重载
     *
     * @param errorCode
     * @return
     */
    public static BaseResponse error(ErrorCode errorCode) { //如果返回的是
        return new BaseResponse<>(errorCode);
    }

    /**
     * 失败 ————方法重载
     *
     * @param code
     * @param message
     * @return
     */
    public static BaseResponse error(int code, String message) {
        return new BaseResponse(code, null, message);
    }

    /**
     * 失败 ————方法重载
     *
     * @param errorCode
     * @return
     */
    public static BaseResponse error(ErrorCode errorCode, String message) {
        return new BaseResponse(errorCode.getCode(), null, message);
    }
}

使用场景实示例:

成功响应:

  @GetMapping("/getUser")
  public BaseResponse<User> getUser() {
      User user = userService.getUserById(1);
      return ResultUtils.success(user);
  }

失败响应:

  @PostMapping("/saveUser")
  public BaseResponse<String> saveUser(@RequestBody User user) {
      if (user == null) {
          return ResultUtils.error(ErrorCode.PARAMS_ERROR, "用户信息不能为空");
      }
      userService.saveUser(user);
      return ResultUtils.success("保存成功");
  }

编写一个自定义异常类 BusinessException.java

public class BusinessException extends RuntimeException {

    private final int code; //错误码

    public BusinessException(int code, String message) {
        super(message); //super:调用父类的RuntimeException的构造方法,并将message传递给父类
        //如果子类重写了父类的方法或者是隐藏了父类字段,可以通过super关键字访问父类的原始版本
        //将message传递给RuntimeException的构造方法,从而初始化异常的消息内容
        this.code = code;
    }

    public BusinessException(ErrorCode errorCode) {
        super(errorCode.getMessage());
        this.code = errorCode.getCode();
    }

    public BusinessException(ErrorCode errorCode, String message) {
        super(message);
        this.code = errorCode.getCode();
    }

    public int getCode() {
        return code;
    }
}

编写一个全局异常处理器 GlobalExceptionHandler.java

其中包括两个异常情况,第一个是BusinessException类型的异常,第二个是RuntimeException类型的异常。其中BusinessException类型的异常是我们自己编写的,也是继承RuntimeException类,重写了父类的方法,对我们能遇见的异常情况进行了处理

@RestControllerAdvice //局处理控制器中的异常和响应增强
@Slf4j //想控制台播报日志
public class GlobalExceptionHandler {

    //业务异常处理器
    @ExceptionHandler(BusinessException.class) //用于指定该方法处理 BusinessException 类型的异常
    public BaseResponse<?> businessExceptionHandler(BusinessException e) {
        //当控制器中抛出BusinessException异常时,Spring会自动调用businessExceptionHandler方法进行处理,
        // 返回一个 BaseResponse<?> 类型的响应对象
        log.error("BusinessException", e);//记录异常信息到日志中,输出到后端的控制台中
        return ResultUtils.error(e.getCode(), e.getMessage());
        //返回一个失败的错误码和错误信息,将异常的 code 和 message 封装为 BaseResponse 对象并返回
    }

    //主要用于处理未被捕获的运行时异常(系统异常
    @ExceptionHandler(RuntimeException.class) //用于指定该方法处理RutimeException.class类型的异常
    public BaseResponse<?> runtimeExceptionHandler(RuntimeException e) {
        log.error("RuntimeException", e);
        return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统错误");//方法重载
    }
}

使用场景示例:

//在ServiceImpl层里的方法:   
 @Override //标记重写父类的方法
    public void validPost(Post post, boolean add) {
        //写一些方法

        // 有参数则校验
        if (title.length() > 80) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "标题过长");
        }
        if (content.length() > 8192) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "内容过长");
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值