SpringBoot实现全局的异常处理
不要捕获任何异常
对的, 不要在业务代码中进行捕获异常, 即 dao、service、controller 层的所以异常都全部抛出到上层. 这样不会导致业务代码中的一堆 try-catch
会混乱业务代码.
统一返回结果集
不要使用 Map 来返回结果, Map 不易控制且容易犯错, 应该定义一个 Java 实体类. 来表示统一结果来返回,
public class ResultBean<T> {
private int code;
private String message;
private Collection<T> data;
private ResultBean() {
}
public static ResultBean error(int code, String message) {
ResultBean resultBean = new ResultBean();
resultBean.setCode(code);
resultBean.setMessage(message);
return resultBean;
}
public static ResultBean success() {
ResultBean resultBean = new ResultBean();
resultBean.setCode(0);
resultBean.setMessage("success");
return resultBean;
}
public static <V> ResultBean<V> success(Collection<V> data) {
ResultBean resultBean = new ResultBean();
resultBean.setCode(0);
resultBean.setMessage("success");
resultBean.setData(data);
return resultBean;
}
// getter / setter 略
}
因为没有捕获,所有的异常都跑到了Controller层 我们只需要用 AOP 对 Controller 层的所有方法处理即可.
@ControllerAdvice
@ResponseBody
public class WebExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(WebExceptionHandler.class);
@ExceptionHandler
public ResultBean unknownAccount(UnknownAccountException e) {
log.error("账号不存在", e);
return ResultBean.error(1, "账号不存在");
}
@ExceptionHandler
public ResultBean incorrectCredentials(IncorrectCredentialsException e) {
log.error("密码错误", e);
return ResultBean.error(-2, "密码错误");
}
@ExceptionHandler
public ResultBean unknownException(Exception e) {
log.error("发生了未知异常", e);
// 发送邮件通知技术人员.
return ResultBean.error(-99, "系统出现错误, 请联系网站管理员!");
}
}
下面是我的一些实现的代码
result类,返回的标准格式数据
@Data
@Builder
public class Result implements Serializable {
private Integer code;
private String messgae;
private Object data;
}
ResultUtil类,定义一些静态函数快速返回Result
public class ResultUtil {
public static Result success(Object data){
Result result = Result.builder().code(ResultEnum.SUCCESS.getCode()).messgae(ResultEnum.SUCCESS.getMessage()).data(data).build();
return result;
}
public static Result success(){
Result result = Result.builder().code(ResultEnum.SUCCESS.getCode()).messgae(ResultEnum.SUCCESS.getMessage()).build();
return result;
}
public static Result error(){
Result result = Result.builder().code(ResultEnum.ERROR.getCode()).messgae(ResultEnum.ERROR.getMessage()).build();
return result;
}
public static Result error(String message){
Result result = Result.builder().code(ResultEnum.UNKNOWN_ERROR.getCode()).messgae(message).build();
return result;
}
}
ResultEnum
@Getter
@AllArgsConstructor
public enum ResultEnum {
// 对异常Code和Message返回值的统一
UNKNOWN_ERROR(500,"未知错误"),
SUCCESS(200,"操作成功"),
ERROR(-2,"操作有误"),
UNAUTHORIZED(300,"权限不够,无法访问"),
SYS_CLOSED(-200,"系统关闭,无法登录")
;
private Integer code;
private String message;
}
配合ResultUtil,定义code【突然觉得没必要加上message字段,因为从捕获的异常Exception可以getMessage而不能getCode】
然后在Controller里面测试
@RestController
public class HelloController {
@GetMapping("/")
public String hello() throws InterruptedException {
Thread.sleep(20);
int a = 10/0;
return "hello";
}
@GetMapping("/111")
public String hello2() throws Exception {
throw new Exception("我的异常");
}
}
返回的都是标准格式
收工!