1、错误码枚举类
@Getter
@AllArgsConstructor
public enum ServiceExceptionEnum {
SUCCESS(0, "成功"),
SYSTEM_ERROR(1001, "服务端异常"),
CONSTRAINT_VIOLATION(1002, "数据完整性异常"),
// ========== 用户模块 ==========
USER_NOT_FOUND(2001002000, "用户不存在"),
// ========== 订单模块 ==========
// ========== 商品模块 ==========
;
private int code;
private String message;
}
2、自定义异常类
@Getter
public class ServiceException extends RuntimeException{
/**
* 错误码
*/
private final Integer code;
public ServiceException(ServiceExceptionEnum serviceExceptionEnum) {
// 使用父类的 message 字段
super(serviceExceptionEnum.getMessage());
// 设置错误码
this.code = serviceExceptionEnum.getCode();
}
}
3、全局异常处理
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理 ServiceException 异常
*/
@ResponseBody
@ExceptionHandler(value = ServiceException.class)
public Result serviceExceptionHandler(HttpServletRequest req, ServiceException ex) {
log.debug("[serviceExceptionHandler]", ex);
// 包装 Result 结果
return Result.error(ex.getCode(), ex.getMessage());
}
/**
* 处理其它 Exception 异常
*/
@ResponseBody
@ExceptionHandler(value = Exception.class)
public Result exceptionHandler(HttpServletRequest req, Exception e) {
// 记录异常日志
log.error("[exceptionHandler]", e);
// 返回 ERROR Result
return Result.error(ServiceExceptionEnum.SYSTEM_ERROR.getCode(),
ServiceExceptionEnum.SYSTEM_ERROR.getMessage());
}
}
测试在controller中抛出异常
@RequestMapping("test1")
public Result test1(){
throw new NullPointerException("测试空指针异常");
}
/**
* 测试 ServiceException异常
* @return
*/
@RequestMapping("test2")
public Result test2(){
throw new ServiceException(ServiceExceptionEnum.CONSTRAINT_VIOLATION);
}
{
"code": 1001,
"message": "服务端异常",
"data": null
}
{
"code": 1002,
"message": "数据完整性异常",
"data": null
}
5、统一封装返回
@Data
public class Result<T> {
public static Integer CODE_SUCCESS = 0;
private int code;
private String message;
private T data;
public static <T> Result<T> error(int code, String message){
Result result = new Result();
result.setCode(code);
result.setMessage(message);
return result;
}
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.code = CODE_SUCCESS;
result.data = data;
result.message = "";
return result;
}
}
4、处理业务异常返回Result 还是 throws 异常?
在处理Service层 逻辑异常的时候,通常可以选择返回两种方案:
- 封装统一的业务异常类 ServiceException ,里面有错误码和错误提示,然后进行
throws
抛出。 - 封装通用的返回类 Result ,里面有错误码和错误提示,然后进行
return
返回
一般选择抛出ServiceException ,原因
-
因为 Spring
@Transactional
声明式事务,是基于异常进行回滚的,如果使用Result 返回,则事务回滚会非常麻烦。 -
当调用别的方法时,如果别人返回的是Result 对象,还需要不断的进行判断,写起来挺麻烦的。