目录
1.生产环境中为了前后端更加友好的交互,我们需要对异常做标准化处理,向前端返回约定好的的状态码和异常信息
2.生产环境中为了更快的定位到程序异常,解决问题,我们需要对异常进行处理,处理成符合我们接受习惯的,更加友好的异常日志信息。
版本:spring boot:2.7.15
jdk:1.8
全局异常处理springboot项目给我们提供了增强类@RestControllerAdvice供我们使用
异常捕获通过注解@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);
- }
- }
- 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;
- }
- }
- }
- 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;
- }
- }
- }
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进行接口结果返回
如果业务上有别的异常需要单独处理,则可以在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));
- }