自定义全局异常处理器

什么是异常

异常是在程序运行过程中可能遇到的不正常情况,异常的出现可能导致程序出现预期之外的行为,或者直接中止程序。在 Java 中,异常分为 Exception Error ,这两个异常有一个共同的祖先 Throwable 类。

Exception 是指程序中可能出现的可以被处理的异常,通常使用 try / catch 进行捕获处理。Exception 又可以分为受检查异常和不受检查异常。

Error 是指程序无法处理的异常,比如虚拟机内存不足,虚拟机运行错误等异常。

受检查异常

受检查异常是在编译时期就需要进行处理的异常,通常是外部因素引起,比如找不到文件,网络连接失败等。必须通过 try / catch 或者 throws 进行捕获处理抛出,否则程序代码无法通过编译。

不受检查异常

不受检查异常,也成为运行时异常,一般是因为程序逻辑错误引起,比如常见的空指针异常、数组 index 越界等边界问题。虽然这类异常不强制进行处理,但是如果出现还是可能导致程序出现预期之外的问题。所以最好还是进行捕获处理。

什么是全局异常处理器,为什么要自定义全局异常处理器

在写代码的过程中,常常会因为需要提前处理上述的异常,就会出现大量的 try / catch 语句,影响代码的可读性。此时使用全局异常处理器就能减少这些冗余的代码。

自定义全局异常处理器,可以更清楚返回给客户端异常的原因即相关描述,更加个性化以及更加灵活。

自定义全局异常处理器

相关注解

@ControllerAdvice 学名是 Controller 增强器,作用是给 Controller 控制器添加统一的操作和处理。结合 @ExceptionHandler 实现全局异常处理。

@ExceptionHandler 用于处理应用程序中的异常,当程序发生异常时,该注解会将其拦截并处理,并返回结果给前端。

@RestControllerAdvice 相当于 @ControllerAdvice 和 @RequestBody 的结合。

实现

以下实现自己使用习惯,如有错误烦请指出。

1. 自定义异常信息枚举类

自定义异常类,个性化得返回异常的状态码,异常信息,异常描述给前端。

public enum ErrorCode {
    SUCCESS(0,"OK",""),
    PARAMS_ERROR(40000,"请求参数错误",""),
    NULL_ERROR(40001,"请求数据为空",""),
    NOT_LOGIN(40100,"未登录",""),
    NO_AUTH(40101,"无权限",""),
    SYSTEM_ERROR(50000,"系统内部异常","");
    /**
     * 状态码
     */
    private int code;
    /**
     * 状态码信息
     */
    private final String message;
    /**
     * 状态码描述
     */
    private final String description;
    ErrorCode(int code, String message, String description) {
        this.code = code;
        this.message = message;
        this.description = description;
    }
    //枚举类不能使用 @Data 注解生成 get方法
    public int getCode() {
        return code;
    }
    public String getMessage() {
        return message;
    }
    public String getDescription() {
        return description;
    }
}

2. 自定义全局异常类

自定义异常类,当抛出异常的时候直接调用这个异常,然后通过这个异常获取到自定义的枚举类异常信息,或者自定义异常的描述等。

import com.pb.demo.common.ErrorCode;
/**
 * 自定义异常类,继承 RuntimeException 类中的异常信息属性
 */
public class BusinessException extends RuntimeException{
    /**
    * 异常状态码
    *
    */
    private final int code;
    /**
    *异常状态描述
    *
    */
    private final String description;
    /**
    *构造方法,自定义异常信息,异常状态码,异常描述
    *
    */
    public BusinessException(String message, int code, String description) {
        super(message);
        this.code = code;
        this.description = description;
    }
    /**
    *构造方法,直接使用异常状态枚举类中的信息
    *
    */
    public BusinessException(ErrorCode errorCode) {
        super(errorCode.getMessage());
        this.code = errorCode.getCode();
        this.description = errorCode.getDescription();
    }
    /**
    *构造方法,使用枚举类中的状态码和信息,自定义描述,比如输入的字数超过了20个
    *
    */
    public BusinessException(ErrorCode errorCode,String description) {
        super(errorCode.getMessage());
        this.code = errorCode.getCode();
        this.description = description;
    }
    public int getCode() {
        return code;
    }
    public String getDescription() {
        return description;
    }
}

3. 自定义通用响应类

在自定义全局异常处理器的同时,可以自定义一个通用的响应类,目的是将异常的信息封装成一个固定的格式,用于返回给前端固定格式的信息,更方便前端处理信息。

import lombok.Data;
import java.io.Serializable;

/**
 * 通用响应类
 * @param <T>
 */
@Data
public class  BaseResponse<T> implements Serializable {
    /**
    * 响应码
    */
    private int code;
    /**
    * 响应数据,比如 id ,json 格式的信息等
    */
    private T data;
    /**
    * 响应信息
    */
    private String message;
    /**
    * 响应描述
    */
    private String description;
    /*
    *构造函数,自定义响应码、响应信息、响应数据、响应描述
    */
    public BaseResponse(int code, T data, String message,String description) {
        this.code = code;
        this.data = data;
        this.message = message;
        this.description = description;
    }
    /*
    *构造函数,自定义响应码、响应信息、响应数据,响应描述为空
    */
    public BaseResponse(int code, T data,String message) {
        this.code = code;
        this.data = data;
        this.message = message;
        this.description="";
    }
    /*
    *构造函数,直接返回自定义异常枚举类的信息
    */
    public BaseResponse(ErrorCode errorCode){
        //code, data, message, description
        this(errorCode.getCode(), null,
                errorCode.getMessage(),errorCode.getDescription());
    }
}

4. 自定义通用返回类

配合通用响应类使用,将返回的信息封装成通用响应类的格式

/*
*自定义通用返回类
*/
public class ResultUtils {
    /*
    *静态泛型方法,直接返回成功,以及传入的数据 data
    */
    public static <T> BaseResponse<T> success(T data){
        return new BaseResponse<>(0,data,"ok","");
    }
    /*
    *返回异常信息
    */
    public static BaseResponse error(ErrorCode errorCode){
        return new BaseResponse<>(errorCode);
    }

    public static BaseResponse error(ErrorCode errorCode,String message,String description)         {

        return new BaseResponse<>(errorCode.getCode(),null,message,description);
    }

    public static BaseResponse error(int code,String message,String description){

        return new BaseResponse<>(code,null,message,description);
    }
}

5. 自定义全局异常处理器

package com.pb.demo.exception;
import com.pb.demo.common.BaseResponse;
import com.pb.demo.common.ErrorCode;
import com.pb.demo.common.ResultUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
  全局异常处理器
 @author p'b
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    /*
    *捕获自定义的异常,并通过自定义通用返回类进行返回异常信息
    */
    @ExceptionHandler(BusinessException.class) //方法只捕获参数内的异常
    public BaseResponse businessExceptionHandler(BusinessException e){
        log.error("businessException: "+ e.getMessage(),e);  //集中记录日志
        return ResultUtils.error(e.getCode(),e.getMessage(),e.getDescription());
    }
    /*
    *捕获运行时的异常,并通过自定义通用返回类进行返回异常信息
    */
    @ExceptionHandler(RuntimeException.class)
    public BaseResponse runtimeExceptionHandler(RuntimeException r){
        log.error("runtimeException: ",r);  //集中记录日志
        return ResultUtils.error(ErrorCode.SYSTEM_ERROR,r.getMessage(),"");
    }
}

调用举例

throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码设置不正确");

抛出密码错误的异常,直接使用枚举类中的的状态码的信息,然后自定义全局异常处理器捕获到该异常以及异常信息,通过通用返回类返回给响应类进行封装,最后以固定的格式响应给前端。前端能更清晰获取到信息以及处理信息。

以上内容均是自己使用时的习惯,部分代码方法没有使用到,可以删除或者自定义其他形式的返回格式,毕竟构造方法可以创建很多个。

如果哪里有错误烦请指出,我一直保持学习。

  • 12
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值