- 程序开发过程中不可避免会遇到异常
- 出现异常现象的常见位置与常见诱因如下:
- 框架内部抛出的异常:因使用不合规导致
- 数据层抛出的异常:因外部服务器故障导致(例如:服务器访问超时)
- 业务层抛出的异常:因业务逻辑书写错误导致(例如:遍历业务书写操作,导致索弓|异常等)
- 表现层抛出的异常:因数据收集、校验等规则导致(例如:不匹配的数据类型间导致异常)
- 工具类抛出的异常:因工具类书写不严谨不够健壮导致(例如:必要释放的连接长期未释放等)
问题:
1、各个层级均出现异常,异常处理代码书写在哪一层??
所有异常均抛出到表现层进行处理
2、表现层处理异常,每个方法中单独书写,代码书写量巨大且意义不强,如何解决??
AOP思想
异常处理器
集中的、统一的处理项目中出现的异常
1、使用注解@RestControllerAdvice声明这个类作为异常处理器类
此注解自带@ResponseBody注解与@Component注解,具备对应的功能
/**
* 异常处理器
*/
@RestControllerAdvice
public class ProjectExceptionAdvice {
@ExceptionHandler(Exception.class)
public Result doException(Exception ex){
var msg = "异常,你来啦!";
System.out.println(msg);
return new Result(msg,400,ex.getMessage());
}
}
2、使用注解@ExceptionHandler ,用于定义异常处理的控制器方法上方
作用:设置指定异常的处理方案,功能等同于控制器方法,出现异常后终止原始控制器执行,并转入当前方法执行
此类方法可以根据处理的异常不同,制作多个方法分别处理对应的异常。
效果:
项目异常处理方案
项目异常分类
- 业务异常(BusinessException)
- 规范的用户行为产生的异常
- 不规范的用户行为操作产生的异常
- 系统异常(SystemException)
- 项目运行过程中可预计且无法避免的异常
- 其他异常(Exception)
- 编程人员未预期到的异常
项目异常处理方案
- 业务异常(BusinessException)
- 发送对应消息传递给用户, 提醒规范操作
- 系统异常(SystemException)
- 发送固定消息传递给用户,安抚用户
- 发送特定消息给运维人员, 提醒维护
- 记录日志
- 其他异常(Exception)
- 发送固定消息传递给用户, 安抚用户
- 发送特定消息给编程人员, 提醒维护(纳入预期范围内)
- 记录日志
1、自定义项目系统级异常
public class SystemException extends RuntimeException{
private Integer code;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public SystemException(Integer code) {
this.code = code;
}
public SystemException(String message, Throwable cause) {
super(message, cause);
}
public SystemException(String message, Throwable cause, Integer code) {
super(message, cause);
this.code = code;
}
public SystemException(String message, Integer code) {
super(message);
this.code = code;
}
}
2、自定义项目业务级异常
public class BusinessException extends RuntimeException {
private Integer code;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public BusinessException(Integer code) {
this.code = code;
}
public BusinessException(String message, Throwable cause, Integer code) {
super(message, cause);
this.code = code;
}
public BusinessException(String message, Integer code) {
super(message);
this.code = code;
}
}
3、自定义异常编码
public class Code {
......
//未知错误
public static final Integer SYSTEM_UNKNOW_ERR=40010;
//超时错误
public static final Integer SYSTEM_TIMEOUT_ERR=40020;
public static final Integer PROJECT_VALIDATE_ERR=40020;
public static final Integer PROJECT_BUSINESS_ERR=40020;
}
4、触发自定义异常
@GetMapping("/{id}")
public Result findById(@PathVariable int id) {
if (id < 0) {
throw new BusinessException("请勿进行非法操作!", Code.PROJECT_BUSINESS_ERR);
}
var data = userService.findById(id);
boolean flag = false;
if (data != null) {
flag = true;
}
var code = flag ? Code.GET_OK : Code.GET_ERR;
var msg = flag ? "数据查询成功" : "数据查询失败";
Result result = new Result(data, code, msg);
return result;
}
5、拦截并处理异常
/**
* 异常处理器
*/
@RestControllerAdvice
public class ProjectExceptionAdvice {
@ExceptionHandler(BusinessException.class)
public Result doBusinessException(BusinessException ex){
return new Result(ex.getMessage(),ex.getCode(),ex.getMessage());
}
@ExceptionHandler(SystemException.class)
public Result doSystemException(SystemException ex){
//记录日志(错误堆栈)todo
//发送邮件给开发人员 todo
//发送短信给运维人员 todo
return new Result(ex.getMessage(),ex.getCode(),ex.getMessage());
}
@ExceptionHandler(Exception.class)
public Result doException(Exception ex){
//记录日志(错误堆栈)todo
//发送邮件给开发人员 todo
//发送短信给运维人员 todo
var msg = "系统繁忙,请联系管理员!";
return new Result(msg,Code.SYSTEM_UNKNOW_ERR,ex.getMessage());
}
}
6、异常处理器效果对比