在Spring Boot中使用切面统一处理自定义的异常

最近我们将项目的一个单独模块提取了一个微服务,这个微服务主要负责其他系统的接入。目的是发布主项目的时候不会影响到其他系统接入。在提取出的微服务中,需要定义一个正常返回的报文和异常返回的报文。正常返回报文就是正常业务返回的数据报文,异常返回报文我这里定义为比如一些校验异常或是权限异常等等,这里不包括程序出现的异常,比如数据库出错这些。我暂时是这样定义的。大家有好的方式也可以一块讨论。

正常的报文:正常的报文比较松散,我指定为自己去定义报文格式。不过基本有这两个字段

{
          
   
  "requestId": "ed93f3cb-f35e-473f-b9f3-0d451b8b79c6",
  "data": {
          
   
      ...
  }
}

requestId是为了更容易跟踪程序错误

异常的报文:

{
          
   
  "requestId": "ed93f3cb-f35e-473f-b9f3-0d451b8b79c6",
  "error": {
          
   
      "code": "NotNullAndLengthErr.waybillNo",
      "msg": "运单号不为空且长度需为15位或12位"
  }
}

在程序中主要处理异常的报文,多为对权限的校验,业务的校验,我将这些校验出错的情况用异常的方式抛出,然后在切面中统一处理自定义的异常

public class OccpDdsRuntimeException extends RuntimeException {
          
   

    private ErrorCodeEnum errorCodeEnum;

    public ErrorCodeEnum getErrorCodeEnum() {
          
   
        return errorCodeEnum;
    }

    public OccpDdsRuntimeException(ErrorCodeEnum errorCodeEnum) {
          
   
        super(errorCodeEnum.getErrMsg());
        this.errorCodeEnum = errorCodeEnum;
    }
}

这里的ErrorCodeEnum是我自定义的Enum类,为的是定义一些错误,比如校验错误,权限错误等

public enum ErrorCodeEnum {
          
   
    NotNullAndLengthErrWaybillNo("NotNullAndLengthErr.waybillNo",
            "运单号不为空且长度需为15位或12位", 420);

    private String errCode;
    private String errMsg;
    private int httpStatus;

    ErrorCodeEnum(String errCode, String errMsg, int httpStatus) {
          
   
        this.errCode = errCode;
        this.errMsg = errMsg;
        this.httpStatus = httpStatus;
    }

    public String getErrCode() {
          
   
        return errCode;
    }

    public String getErrMsg() {
          
   
        return errMsg;
    }

    public int getHttpStatus() {
          
   
        return httpStatus;
    }
}

下面看一下真正的绝学,在切面中统一处理自定义的异常以达到返回异常的报文

/**
 * 全局异常处理
 */
@ControllerAdvice
public class OccpDdsExceptionHandler {
          
   
    private static Logger LOG = LoggerFactory.getLogger(OccpDdsExceptionHandler.class);

    @ExceptionHandler(OccpDdsRuntimeException.class)	//1
    @ResponseBody	//2
    public Map<String, Object> handleException(OccpDdsRuntimeException ex, HttpServletResponse response) {
          
   
        Map<String, Object> responseBody = new HashMap<>();
        String requestId = getRequestId();
        if (ex instanceof OccpDdsRuntimeException) {
          
   
           //这里进行组装报文的操作
        }
        //返回报文
        return responseBody;
    }

    private String getRequestId() {
          
   
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        return (String)request.getAttribute(REQUEST_ID);
    }

}

上面的代码中注释第一行完全可以自己去组装想要的报文,1处定义了捕获哪个异常,2表示返回的对象类型。

这样就可以测试一下项目当抛出自定义异常了

经验分享 程序员 微信小程序 职场和发展