注解

从无到有,我们已经写过无数个 try - catch 代码块,繁杂的异常处理片段导致我们的代码可读性变弱,而且 try - catch 代码重复性很高,耗时耗力。以下通过两个注解来创建全局统一异常处理类,抛砖引玉,使代码更美观,提高代码复用性。

下面创建异常处理类,通过这两个注解来实现全局异常处理,示例:

  1. @RestControllerAdvice
  2. public class CustomExceptionHandler {
  3. @ExceptionHandler({Exception.class})
  4. public R otherExceptionHandler(Exception e) {
  5. log.error("Error:[{}]", e.getMessage());
  6. return R.error(e.getMessage());
  7. }
  8. }

以上代码展示了如何处理顶层异常,当有异常未捕获时将会执行此处理器,返回统一的错误结果。其中还使用到了日志字符串替换。

从两个方面进行统一,一个是通过一个异常处理类处理异常,几乎所有异常都可以在该类(或者创建多个 @RestControllerAdvice 注解的类)中捕获并处理;另一个是统一返回数据格式,通过自定义的R响应类来返回结果。

常用的异常处理

针对 hibernate-validator 参数校验出现的异常,我们可以统一一下:

  1. /*
  2. * RequestBody 请求体对象参数
  3. */
  4. @ExceptionHandler({MethodArgumentNotValidException.class})
  5. public R methodArgumentNotValid(MethodArgumentNotValidException e)
  6. {
  7. String message = e.getBindingResult().getFieldError().getDefaultMessage();
  8. log.error("请求参数未通过校验,提示:[{}]", message);
  9. return R.error(e.getMessage());
  10. }
  11. /*
  12. * GET 请求参数绑定到对象参数
  13. */
  14. @ExceptionHandler({BindException.class})
  15. public R bindException(BindException e)
  16. {
  17. String message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
  18. log.error("请求参数未通过校验,提示:[{}]", message);
  19. return R.error(e.getMessage());
  20. }
  21. /*
  22. * 接口单个参数校验(没有绑定对象)
  23. */
  24. @ExceptionHandler(ConstraintViolationException.class)
  25. public Result otherValidException(ConstraintViolationException e) {
  26. return R.error(e.getMessage());
  27. }
  28. /*
  29. * 必填参数缺失,如声明为 @PathVariable,@RequestParam 等
  30. */
  31. @ExceptionHandler(ServletRequestBindingException.class)
  32. public Result servletRequestBinding(ServletRequestBindingException e) {
  33. return R.error(e.getMessage());
  34. }

其他常用的异常类:

  • IllegalArgumentException

自定义业务异常处理

除了特定异常,我们还可以定义业务异常类,创建符合自身业务的异常,然后使用上面的异常处理器捕获并处理。