springboot实战(九)之全局异常捕获&异常统一处理

目录

序言:

1.环境:

2.全局异常处理:

2.1配置全局捕获异常

2.2创建统一返回类、异常码

2.3创建自定义异常类

2.4测试

2.5扩展


序言:

1.生产环境中为了前后端更加友好的交互,我们需要对异常做标准化处理,向前端返回约定好的的状态码和异常信息

2.生产环境中为了更快的定位到程序异常,解决问题,我们需要对异常进行处理,处理成符合我们接受习惯的,更加友好的异常日志信息。

1.环境:

版本:spring boot:2.7.15

jdk:1.8

2.全局异常处理:

全局异常处理springboot项目给我们提供了增强类@RestControllerAdvice供我们使用

2.1配置全局捕获异常

异常捕获通过注解@ExceptionHandler

package com.iterge.iterge_pre.config;

import com.iterge.iterge_pre.entity.Response;
import com.iterge.iterge_pre.exception.BizException;
import com.iterge.iterge_pre.exception.ErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;

/**
 * @author liuph
 * @date 2023/9/27 15:37:21
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionConfig {
    @ExceptionHandler(Throwable.class)
    public Response handleException(Throwable e, HttpServletRequest request) {
        log.error("执行异常,异常信息:接口:{},信息:{}",request.getRequestURI(),e.getMessage());
        return Response.of(new BizException(ErrorCode.UNKNOWN_EXCEPTION, e.getMessage()));
    }

    //自定义异常
    @ExceptionHandler(BizException.class)
    public Response bizHandleException(BizException e, HttpServletRequest request) {
        log.error("执行异常,异常信息:接口:{},信息:{}",request.getRequestURI(),e.getMsg());
        return Response.of(e);
    }
}

2.2创建统一返回类、异常码

package com.iterge.iterge_pre.entity;

import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.iterge.iterge_pre.exception.BizException;
import lombok.Data;

/**
 * @author liuph
 * @date 2023/9/27 15:34:20
 */
@Data
public class Response {
    /**
     * 成功返回ok, 异常返回错误原因。
     */

    /**
     * 返回的协议版本号
     */
    private int version = 0;

    /**
     * 返回的状态码
     */
    private int status = 0;

    /**
     * 错误信息
     */
    @JsonProperty("err_msg")
    @JsonAlias("errMsg")
    private String errMsg = "";

    /**
     * 错误信息
     */
    @JsonProperty("error_msg")
    @JsonAlias("errorMsg")
    private String errorMsg = "";

    /**
     * 服务器时间戳
     */
    private long ts;

    /**
     * 返回的数据
     */
    private T data;

    public Response() {
        ts = System.currentTimeMillis();
    }

    public static  Response ok() {
        return ok(null);
    }

    public static  Response ok(T data) {
        return ok(0, data);
    }

    public static  Response ok(int version, T data) {
        return ok(version, System.currentTimeMillis(), data);
    }

    public static  Response ok(int version, long ts, T data) {
        return ok(0, version, ts, "ok", data);
    }

    public static  Response ok(int status, int version, long ts, String msg, T data) {
        Response resp = new Response<>();
        resp.setData(data);
        if (null != msg)
            resp.setErrMsg(msg);
        resp.setVersion(version);
        resp.setTs(ts);
        return resp;
    }

    public static  Response of(BizException e) {
        Response response = new Response<>();
        response.setStatus(e.getCode());
        response.setErrMsg(e.getMsg());
        response.setErrorMsg(e.getMessage());
        response.setData(null);
        return response;
    }
}

package com.iterge.iterge_pre.exception;

/**
 * @author liuph
 * @date 2023/9/27 15:43:37
 */
public class ErrorCode {
    public static final ErrorCode OK = define(0, "ok");
    public static final ErrorCode PARAM_INVALID = define(-1, "参数错误");
    public static final ErrorCode DB_EXCEPTION = define(-2, "数据库错误");
    public static final ErrorCode REDIS_EXCEPTION = define(-3, "Redis错误");
    public static final ErrorCode MEMCACHE_EXCEPTION = define(-4, "Memcache错误");
    public static final ErrorCode MQ_EXCEPTION = define(-5, "MQ错误");
    public static final ErrorCode RPC_EXCEPTION = define(-6, "RPC调用错误");
    public static final ErrorCode CONFIG_EXCEPTION = define(-7, "配置错误");
    public static final ErrorCode DATA_NOT_EXIST = define(-20, "数据不存在");
    public static final ErrorCode AUTHENTICATION_FAILED = define(-41, "认证失败");
    public static final ErrorCode PERMISSION_DENIED = define(-42, "权限不足");
    public static final ErrorCode BUSINESS_EXCEPTION = define(-50, "业务异常");
    public static final ErrorCode UNKNOWN_EXCEPTION = define(-100, "未知异常");
    private int code;
    private String msg;

    protected ErrorCode() {
        this.code = 0;
        this.msg = null;
    }

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

    public static ErrorCode define(int code, String msg) {
        return new ErrorCode(code, msg);
    }

    public static ErrorCode define(int code) {
        return define(code, (String)null);
    }

    public int getCode() {
        return this.code;
    }

    public String getMsg() {
        return this.msg;
    }

    public boolean equals(Object o) {
        if (this == o) {
            return true;
        } else if (o != null && this.getClass() == o.getClass()) {
            ErrorCode errorCode = (ErrorCode)o;
            return this.code == errorCode.code;
        } else {
            return false;
        }
    }
}

2.3创建自定义异常类

package com.iterge.iterge_pre.exception;

/**
 * @author liuph
 * @date 2023/9/27 15:43:37
 */
public class ErrorCode {
    public static final ErrorCode OK = define(0, "ok");
    public static final ErrorCode PARAM_INVALID = define(-1, "参数错误");
    public static final ErrorCode DB_EXCEPTION = define(-2, "数据库错误");
    public static final ErrorCode REDIS_EXCEPTION = define(-3, "Redis错误");
    public static final ErrorCode MEMCACHE_EXCEPTION = define(-4, "Memcache错误");
    public static final ErrorCode MQ_EXCEPTION = define(-5, "MQ错误");
    public static final ErrorCode RPC_EXCEPTION = define(-6, "RPC调用错误");
    public static final ErrorCode CONFIG_EXCEPTION = define(-7, "配置错误");
    public static final ErrorCode DATA_NOT_EXIST = define(-20, "数据不存在");
    public static final ErrorCode AUTHENTICATION_FAILED = define(-41, "认证失败");
    public static final ErrorCode PERMISSION_DENIED = define(-42, "权限不足");
    public static final ErrorCode BUSINESS_EXCEPTION = define(-50, "业务异常");
    public static final ErrorCode UNKNOWN_EXCEPTION = define(-100, "未知异常");
    private int code;
    private String msg;

    protected ErrorCode() {
        this.code = 0;
        this.msg = null;
    }

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

    public static ErrorCode define(int code, String msg) {
        return new ErrorCode(code, msg);
    }

    public static ErrorCode define(int code) {
        return define(code, (String)null);
    }

    public int getCode() {
        return this.code;
    }

    public String getMsg() {
        return this.msg;
    }

    public boolean equals(Object o) {
        if (this == o) {
            return true;
        } else if (o != null && this.getClass() == o.getClass()) {
            ErrorCode errorCode = (ErrorCode)o;
            return this.code == errorCode.code;
        } else {
            return false;
        }
    }
}

2.4测试

controller中添加测试方式

    @GetMapping("test1/{id}")
    public Response getUser(@PathVariable("id") Integer id){
        if(id != 1){
            throw new BizException(ErrorCode.PARAM_INVALID);
        }
        log.info("成功");
        return Response.ok();
    }

以上代码的逻辑是:当我们的入参id!=1的时候抛出我们的自定义异常BizException,并通过全局异常类GlobalExceptionConfig捕获类进行捕获,捕获异常后,进行对程序员比较友好的日志打印,最后通过统一返回类Response进行接口结果返回

2.5扩展

如果业务上有别的异常需要单独处理,则可以在GlobalExceptionConfig类中使@ExceptionHandler注解进行新增。例如下面的空指针异常

    //空指针异常
    @ExceptionHandler(NullPointerException.class)
    public Response nullPointerHandleException(NullPointerException e, HttpServletRequest request) {
        log.error("空指针异常:接口:{},信息:{}",request.getRequestURI(),e.getMessage());
        return Response.of(new BizException(ErrorCode.BUSINESS_EXCEPTION));
    }

你可能感兴趣的:(springboot实战,spring,boot,java,spring)