文章目录
- 一、粗谈统一异常处理
- 二、细谈统一异常处理:结合统一结果返回类
- 为什么使用统一异常处理?
- 怎么做?如何处理?代码实现?
一、粗谈统一异常处理
先看个案例:
1、写了一个接口:
实体类如下:
@Data
public class Emp {@NotNull(message = "id 不能为 null")private Integer id;@NotNull(message = "name 不能为 null")private String name;
}
接口如下:
@RestController
public class EmpController {@PostMapping("/emp")public String createEmp(@Valid @RequestBody Emp emp) {return "ok";}
}
测试时,假如不传 id、name,会抛出 MethodArgumentNotValidException 异常。使用 BindingResult 可以处理异常信息,但 通常使用统一异常处理。
① 使用 BindingResult:
@RestController
public class EmpController {@PostMapping("/emp")public Map createEmp(@Valid @RequestBody Emp emp, BindingResult result) {if (result.hasErrors()) {Map<String, String> map = new HashMap<>();// 获取校验结果,遍历获取捕获到的每个校验结果result.getFieldErrors().forEach(item -> {// 获取校验的信息String message = item.getDefaultMessage(); // 也获取message的值String field = item.getField(); //获取属性名// 存储得到的校验结果map.put(field, message);});return map;}return "ok";}
}
问题:通过上面的步骤,已经可以捕获异常、处理异常,但是每次都是在业务方法中手动处理逻辑,这样的实现,代码肯定会冗余。可以将其抽出,使用 统一异常处理,每次异常发生时,将其捕获。
② 全局统一异常处理:@RestControllerAdvice、@ExceptionHandler
@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(MethodArgumentNotValidException.class)public Map handlerValidException(MethodArgumentNotValidException e) {BindingResult result = e.getBindingResult();Map<String, String> map = new HashMap<>();// 获取校验结果,遍历获取捕获到的每个校验结果result.getFieldErrors().forEach(item ->{// 存储得到的校验结果map.put(item.getField(), item.getDefaultMessage());});return map;}
}
Controller 中不需要再用 BindingResult 去处理数据了。
二、细谈统一异常处理:结合统一结果返回类
提示:统一结果返回类,可查看这篇文章:点击查看
为什么使用统一异常处理?
使用统一结果处理时,有些异常我们可以提前预知并处理,但是一个运行时异常,我们不一定能预知并处理,这时可以使用统一异常处理,当异常发生时,触发该处理操作,从而保证程序的健壮性。
怎么做?如何处理?代码实现?
-
使用 @ControllerAdvice 或者 @RestControllerAdvice 注解作为统一异常处理的核心。
这两个注解都是 Spring MVC 提供的
@ControllerAdvice 和 **@RestControllerAdvice **的区别:
@RestControllerAdvice 注解包含了 @ControllerAdvice 与 @ResponseBody 注解。类似于 @Controller 与 @RestController 的区别。
步骤: 使用 @ControllerAdvice 或者 @RestControllerAdvice 注解标记一个 全局异常处理类。全局异常处理类内部使用 @ExceptionHandler 注解去捕获异常。
可选操作:可以自定义一个异常信息收集类,用于处理项目中的异常,并收集异常信息。
代码实现:
1、可选操作:自定义一个异常类,用于处理项目中的异常,并收集异常信息。
/*** 自定义异常类* 可以自定义 异常信息message、响应状态码 code(默认为500)*/
@Data
public class GlobalException extends RuntimeException {// 保存异常信息private String message;// 保存响应状态码(默认为500)private Integer code = HttpStatus.SC_INTERNAL_SERVER_ERROR;// 默认构造方法,根据异常信息 构建一个异常实例对象public GlobalException(String message) {super(message);this.message = message;}// 根据异常信息、响应状态码 构建一个异常实例对象public GlobalException(String message, Integer code) {super(message);this.message = message;this.code = code;}// 根据异常信息、异常对象 构建一个异常实例对象public GlobalException(String message, Throwable e) {super(message, e);this.message = message;}// 根据异常信息、响应状态码、异常对象 构建一个异常实例对象public GlobalException(String message, Integer code, Throwable e) {super(message, e);this.message = message;this.code = code;}
}
2、全局异常处理类:
- 定义一个全局的异常处理类 GlobalExceptionHandler。使用 @RestControllerAdvice 注解标记这个类。
- 内部使用 @ExceptionHandler 注解去捕获异常。
// 使用统一结果返回类:Result
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {// 处理 Exception 异常@ExceptionHandler(Exception.class)public Result handlerException(Exception e) {log.error(e.getMessage(), e);return Result.error().message("系统异常");}// 处理空指针异常@ExceptionHandler(NullPointerException.class)public Result handlerNullPointerException(NullPointerException e) {log.error(e.getMessage(), e);return Result.error().message("空指针异常");}// 处理自定义异常@ExceptionHandler(GlobalException.class)public Result handlerGlobalException(GlobalException e) {log.error(e.getMessage(), e);return Result.error().message(e.getMessage()).code(e.getCode());}
}
3、使用:修改某个 controller 如下所示:
@GetMapping("/test")
public Result test(Integer id) { if (id == 0) {throw new NullPointerException();}if (id == -1) {throw new GlobalException("参数异常", 400);}if (id == 1) {throw new GlobalException("未查询到结果,请确认输入是否正确");}return Result.ok().data("items", 123456).message("查询成功");
}
参数为 0 时,抛出 空指针异常。
{"success": false,"code": 500,"message": "空指针异常","data": {}
}
参数为 -1 时,抛出自定义异常并处理。
{"success": false,"code": 400,"message": "参数异常","data": {}
}
参数为 1 时,抛出自定义异常并处理。
{"success": false,"code": 500,"message": "未查询到结果,请确认输入是否正确","data": {}
}
查询成功时,正确处理并返回。
至此,文章结束!!!记得关注哦!!!!