这是我参与8月更文挑战的第26天,活动详情查看:8月更文挑战
SpringBoot项目的接口服务中,我们在上一讲中定义了统一的返回结果,但是有些运行时产生的异常信息是不能够很好的预估到的,在返回结果数据之前就会报出异常,最终不能完成数据的返回。这种情况就会导致我们的统一结果出现了问题,因此针对接口中出现的异常信息,我们同样需要定义统一的规范来捕获程序运行过程中出现的异常。
至此,SpringBoot开发中三个基础且重要的统一规范就要完成了,之前两篇在这:
- SpringBoot统一日志输出
- # SpringBoot统一返回结果 今天就再来学习一下统一异常的捕获。
SpringBoot统一异常捕获
自定义统一异常类
Java程序中异常分为可查异常和不可查异常,其中可查异常要求必须进行捕获或者抛出;不可查异常又叫做运行时异常,则需要我们进行全局处理来维护接口服务的稳定和数据的正常返回。
在进行异常处理之前,需要定义一个全局的统一的异常类,来涵盖我们需要进行处理的异常类型,代码如下
@Data
public class MyException extends RuntimeException{
private Integer code;
public MyException(Integer code, String message) {
super(message);
this.code = code;
}
public MyException(ResultCodeEnum resultCodeEnum) {
super(resultCodeEnum.getDesc());
this.code = resultCodeEnum.getCode();
}
@Override
public String toString() {
return "MyException{" + "code=" + code + ", message=" + this.getMessage() + '}';
}
}
统一异常处理器
@ControllerAdvice注解
@ControllerAdvice注解是一种作用于控制层的切面通知(Advice),该注解能够将通用的@ExceptionHandler、@InitBinder和@ModelAttributes方法收集到一个类型,并应用到所有控制器上。@ControllerAdvice注解是SpringBoot项目中统一异常处理的核心。
对于异常捕获的流程可分析为:
- 使用@ControllerAdvice注解标注异常处理器类
- 定义一个通用的异常捕获方法,并使用@ExceptionHandler注解标注异常处理器类中的方法来统一捕获指定的异常信息
- 自定义一个异常类,捕获针对项目或业务的异常;
- 异常的对象信息补充到统一结果枚举中;
统一异常处理器
定义一个异常处理类并使用@ControllerAdvice注解标注,标识当前类用来做异常的处理。 在异常处理类中分别定义了通用的异常处理方法、具体异常类型的处理方法以及自定义异常类的处理方法,SpringBoot中异常处理的流程是异常范围从小到达依次进行的。
@ControllerAdvice
public class GlobalExceptionHandler {
/**
* 通用异常处理方法
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public Result error(Exception e){
e.printStackTrace();;
return Result.error();
}
/**
* 指定具体异常处理方法
*/
@ExceptionHandler(NullPointerException.class)
@ResponseBody
public Result error(NullPointerException e){
e.printStackTrace();
return Result.setResult(ResultCodeEnum.NULL_POINT_ERROR);
}
/**
* 返回自定义异常处理方法
*/
@ExceptionHandler(MyException.class)
@ResponseBody
public Result error(MyException e){
e.printStackTrace();
return Result.error().code(e.getCode()).desc(e.getMessage());
}
}
如代码所示,当异常是NullPointerException空指针异常时,会优先执行该异常类型为参数的方法并返回结果;自定义异常也是相同,只有当异常不属于这两类时,会调用通用异常处理方法来处理当前异常信息。
控制层捕获异常并返回
定义了全局异常类,并使用@ControllerAdvice注解定义了异常处理器以及相应异常处理方法后,便可以在controller控制层中定义相应的接口服务,并测试我们定义的全局异常是否发挥作用。 如下是自定义的接口信息,其内部调用了null,会产生一个NullPointerException
@RequestMapping(value = "/null")
public String nullException(){
List<String> list = null;
Integer count = list.size();
return "success";
}
在对该接口进行请求后,返回结果为:
{"success":false,"code":20003,"desc":"空指针异常","data":null}
说明我们定义的异常处理器已经发生了作用。
最后
我们自定义的异常在服务接口中已经发挥作用,并且会根据异常的类型寻找对应方法来进行处理,最终把异常信息加入到统一的结果类中,作为服务接口的返回数据提供给调用者,这样我们就保证了服务接口的规范统一和结果稳定。