文章目录
- 1. 全局异常处理
- 2. 项目异常处理方案
- 2.1 异常分类
- 2.2 异常解决方案
- 2.3 异常解决方案具体实现
1. 全局异常处理
-
问题:当我们在SpingMVC代码中没有对异常进行处理时,三层架构的默认处理异常方案是将异常抛给上级调用者。也就是说Mapper层报错会将异常上抛给Service层,Service层报错会将异常上抛给Controller层,最终抛给框架之后会把各种各样的错误信息直接返回给前端,前端往往难以解析这些五花八门的异常。
-
解决方案:SpingMVC提供了全局异常处理器,捕获不同的异常进行特定的处理。
-
实现方法:
-
在类上加
@RestControllerAdvice
注解,加上这个注解就代表我们定义了一个全局异常处理器,同时需要确保该类能够被Spring容器扫描到。@RestControllerAdvice
=@ControllerAdvice
+@ResponseBody
处理异常的方法返回值会转换为Json后再响应给前端
-
在全局异常处理器当中,需要定义一个方法来捕获异常,在这个方法上需要加上注解
@ExceptionHandler
。通过@ExceptionHandler
注解当中的value属性来指定我们要捕获的是哪一类型的异常。@RestControllerAdvice public class GlobalExceptionHandler {//处理异常@ExceptionHandler(Exception.class) //指定能够处理的异常类型public Result ex(Exception e){e.printStackTrace(); //打印堆栈中的异常信息//捕获到异常之后,响应一个标准的Resultreturn Result.error("对不起,操作失败,请联系管理员");} }
-
2. 项目异常处理方案
2.1 异常分类
-
因为异常的种类有很多,如果每一个异常都对应一个
@ExceptionHandler
,那得写多少个方法来处理各自的异常,所以我们在处理异常之前,需要对异常进行一个分类:-
业务异常(BusinessException)
-
规范的用户行为产生的异常
-
用户在页面输入内容的时候未按照指定格式进行数据填写,如在年龄框输入的是字符串
-
-
不规范的用户行为操作产生的异常
-
如用户故意传递错误数据
-
-
-
系统异常(SystemException)
- 项目运行过程中可预计但无法避免的异常
- 比如数据库或服务器宕机
- 项目运行过程中可预计但无法避免的异常
-
其他异常(Exception)
-
编程人员未预期到的异常,如:用到的文件不存在
-
将异常分类以后,针对不同类型的异常,要提供具体的解决方案:
-
2.2 异常解决方案
- 业务异常(BusinessException)
- 发送对应消息传递给用户,提醒规范操作
- 大家常见的就是提示用户名已存在或密码格式不正确等
- 发送对应消息传递给用户,提醒规范操作
- 系统异常(SystemException)
- 发送固定消息传递给用户,安抚用户
- 系统繁忙,请稍后再试
- 系统正在维护升级,请稍后再试
- 系统出问题,请联系系统管理员等
- 发送特定消息给运维人员,提醒维护
- 可以发送短信、邮箱或者是公司内部通信软件
- 记录日志
- 发消息和记录日志对用户来说是不可见的,属于后台程序
- 发送固定消息传递给用户,安抚用户
- 其他异常(Exception)
- 发送固定消息传递给用户,安抚用户
- 发送特定消息给编程人员,提醒维护(纳入预期范围内)
- 一般是程序没有考虑全,比如未做非空校验等
- 记录日志
2.3 异常解决方案具体实现
-
自定义异常类:添加code属性以区分异常来自哪个业务。
//自定义异常处理器,用于封装异常信息,对异常进行分类 @Data public class SystemException extends RuntimeException{private Integer code;public SystemException(Integer code, String message) {super(message);this.code = code;}public SystemException(Integer code, String message, Throwable cause) {super(message, cause);this.code = code;} }//自定义异常处理器,用于封装异常信息,对异常进行分类 @Data public class BusinessException extends RuntimeException{private Integer code;public BusinessException(Integer code, String message) {super(message);this.code = code;}public BusinessException(Integer code, String message, Throwable cause) {super(message, cause);this.code = code;} }
//状态码 public class Code {public static final Integer SAVE_OK = 20011;public static final Integer DELETE_OK = 20021;public static final Integer UPDATE_OK = 20031;public static final Integer GET_OK = 20041;public static final Integer SAVE_ERR = 20010;public static final Integer DELETE_ERR = 20020;public static final Integer UPDATE_ERR = 20030;public static final Integer GET_ERR = 20040;public static final Integer SYSTEM_ERR = 50001;public static final Integer SYSTEM_TIMEOUT_ERR = 50002;public static final Integer SYSTEM_UNKNOW_ERR = 59999;public static final Integer BUSINESS_ERR = 60002; }
-
将其他异常换成自定义异常:
public Book getById(Integer id) {//模拟业务异常,包装成自定义异常if(id == 1){throw new BusinessException(Code.BUSINESS_ERR,"业务异常,用户注意相关格式");}//模拟系统异常,将可能出现的异常进行包装,转换成自定义异常try{int i = 1/0;}catch (Exception e){throw new SystemException(Code.SYSTEM_TIMEOUT_ERR,"服务器访问超时,请重试!",e);}return bookDao.getById(id); }
-
处理器类中处理自定义异常:
//@RestControllerAdvice用于标识当前类为REST风格对应的异常处理器 @RestControllerAdvice public class ProjectExceptionAdvice {@ExceptionHandler(SystemException.class)public Result doSystemException(SystemException ex){//记录日志//发送消息给运维//发送邮件给开发人员,ex对象发送给开发人员return new Result(ex.getCode(),null,ex.getMessage());}@ExceptionHandler(BusinessException.class)public Result doBusinessException(BusinessException ex){return new Result(ex.getCode(),null,ex.getMessage());}//除了自定义的异常处理器,保留对Exception类型的异常处理,用于处理非预期的异常@ExceptionHandler(Exception.class)public Result doOtherException(Exception ex){//记录日志//发送消息给运维//发送邮件给开发人员,ex对象发送给开发人员return new Result(Code.SYSTEM_UNKNOW_ERR,null,"系统繁忙,请稍后再试!");} }