这个例子将模仿抛出各种exception,并包装在CommonResult中进行统一的返回
我们先来给出项目中的错误码的枚举类,这里挖坑,后面填
//枚举项目中的错误码
public enum ServiceExceptionEnum {
//错误码设计的规则
/**
* 服务异常
*
* 参考 https://www.kancloud.cn/onebase/ob/484204 文章
*
* 一共 10 位,分成四段
*
* 第一段,1 位,类型
* 1 - 业务级别异常
* 2 - 系统级别异常
* 第二段,3 位,系统类型
* 001 - 用户系统
* 002 - 商品系统
* 003 - 订单系统
* 004 - 支付系统
* 005 - 优惠劵系统
* ... - ...
* 第三段,3 位,模块
* 不限制规则。
* 一般建议,每个系统里面,可能有多个模块,可以再去做分段。以用户系统为例子:
* 001 - OAuth2 模块
* 002 - User 模块
* 003 - MobileCode 模块
* 第四段,3 位,错误码
* 不限制规则。
* 一般建议,每个模块自增。
*/
//===========系统级别============
SUCCESS(0, "成功"),
SYS_ERROR(2001001000,"服务端发生异常"),
MISSING_REQUEST_PARAM_ERROR(2001001001,"参数缺失"),
//===========用户级别============
USER_NOT_FOUND(1001002000,"用户不存在"),
//===========订单级别============
//===========订单级别============
;
/**
* 错误码
*/
private int code;
/**
* 错误提示
*/
private String message;
ServiceExceptionEnum(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
}
这里的返回错误的返回格式也基本是错误码code+错误提示message,这里的错误码设计的原则卸载了注释里面
下面引入与Service逻辑异常有关的错误,这里选择的方式还是,封装通用的返回类
//service中的异常
public final class ServiceException extends RuntimeException{
/**
* 错误码
*/
private final Integer code;
public ServiceException(ServiceExceptionEnum serviceExceptionEnum) {
//使用父类的message字段
super(serviceExceptionEnum.getMessage());
//设置错误码
this.code = serviceExceptionEnum.getCode();
}
public Integer getCode() {
return code;
}
}
这里后续需要补充各种常见异常类这个坑。
这里的意思呢,显然异常类中是有一个message的信息的,然后加上我们自定义的错误码,这里的错误码呢,会引用我们定义的枚举类型中的错误码,说实话,写到这里,我觉得枚举类好像也挺好理解的了,就是封装一连串的final对象,然后就那几个给定的状态,比起普通类来说,多了一个枚举定义的过程。
下一步需要定义一个统一返回的处理器
@ControllerAdvice(basePackages = "com.zzaxg.springboot.controller")
public class GlobalExceptionHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
//使用该异常的code+message属性,构建CommonResult对象来返回
/**
* 处理ServiceException异常
*
* @param request
* @param ex
* @return
*/
@ResponseBody
@ExceptionHandler(value = ServiceException.class)
public CommonResult serviceExceptionHandler(HttpServletRequest request, ServiceException ex) {
logger.debug("[serviceException]", ex);
//包装CommonResult结果
return CommonResult.error(ex.getCode(), ex.getMessage());
}
/**
* 处理 MissingServletRequestParameterException 异常
*
* SpringMVC参数不正确
*/
@ResponseBody
@ExceptionHandler(value = MissingServletRequestParameterException.class)
public CommonResult MissingServletRequestParameterException(HttpServletRequest request, MissingServletRequestParameterException ex) {
logger.debug("[missingServletRequestParameterException]", ex);
//包装CommonResult结果
return CommonResult.error(ServiceExceptionEnum.MISSING_REQUEST_PARAM_ERROR.getCode(), ServiceExceptionEnum.MISSING_REQUEST_PARAM_ERROR.getMessage());
}
//兜底的异常处理
/**
* 处理其他 Exception 异常
*/
@ResponseBody
@ExceptionHandler(value = Exception.class)
public CommonResult exceptionHandler(HttpServletRequest request, Exception e) {
//记录异常日志
logger.debug("[exceptionHandler]", e);
//包装CommonResult结果
return CommonResult.error(ServiceExceptionEnum.SYS_ERROR.getCode(), ServiceExceptionEnum.SYS_ERROR.getMessage());
}
}
同样是定义了可一个切面,但这里不需要拦截接口返回结果,所以不需要定义ResponseBodyHandler接口
通过@ExceptionHandler注解定义每个方法对应处理的异常,@ResponseBody注解呢,标记直接使用返回结果作为API的响应
这里的logger.debug呢,打印了错误日志
下面写一个controller进行错误的throw
/**
* 测试抛出NullPointerException异常
*
* @return
*/
@GetMapping("/exception-01")
public UserVO exception01() {
throw new NullPointerException("周周不在呢");
}
/**
* 测试抛出ServiceException异常
*
*/
@GetMapping("/exception-02")
public UserVO exception02() {
throw new ServiceException(ServiceExceptionEnum.USER_NOT_FOUND);
}
返回的结果呢,分别是
{
"code": 2001001000,
"message": "服务端发生异常",
"data": null
}
{
"code": 1001002000,
"message": "用户不存在",
"data": null
}
原文参考芋道源码
谢谢观看