SpringBoot 如何使用 @ControllerAdvice 注解处理异常消息
在 Web 开发中,异常处理是非常重要的一环。在 SpringBoot 框架中,我们通常使用 @ExceptionHandler 注解来处理 Controller 层的异常。但是,如果想要处理全局异常消息,我们需要使用 @ControllerAdvice 注解。本文将介绍如何在 SpringBoot 中使用 @ControllerAdvice 注解处理异常消息。
什么是 @ControllerAdvice
@ControllerAdvice 注解是 Spring Framework 3.2 引入的一个新特性,它用于定义全局异常处理器。使用 @ControllerAdvice 注解,我们可以集中处理所有 Controller 层抛出的异常,而不必在每个 Controller 中单独处理。
@ControllerAdvice 注解通常与 @ExceptionHandler 注解一起使用,@ExceptionHandler 注解用于定义具体的异常处理方法,@ControllerAdvice 注解用于定义全局异常处理器。
如何使用 @ControllerAdvice 进行全局异常处理
使用 @ControllerAdvice 进行全局异常处理的步骤如下:
创建一个全局异常处理类
我们可以创建一个类并使用 @ControllerAdvice 注解进行标注,例如:
@ControllerAdvice public class GlobalExceptionHandler { // 异常处理方法
在上述代码中,我们使用 @ControllerAdvice 注解标注了一个类,并命名为 GlobalExceptionHandler。接下来,我们可以在 GlobalExceptionHandler 类中定义具体的异常处理方法。
定义异常处理方法
在 GlobalExceptionHandler 类中定义具体的异常处理方法,例如:
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) @ResponseBody public ErrorResponse handleException(Exception e) { // 返回 ErrorResponse 对象 } }
在上述代码中,我们使用 @ExceptionHandler 注解定义了一个处理 Exception 类型异常的方法,并返回一个 ErrorResponse 对象。在处理方法中,我们可以根据具体的业务需求对异常进行相应的处理,并返回相应的结果。
定义异常返回对象
在异常处理方法中,我们需要返回一个异常返回对象,例如:
@Data @NoArgsConstructor @AllArgsConstructor public class ErrorResponse { private int code; private String message; }
在上述代码中,我们定义了一个 ErrorResponse 对象,用于存储异常返回信息。
处理其他类型的异常
除了处理 Exception 类型的异常外,我们还可以根据具体的业务需求,处理其他类型的异常。例如,如果我们想要处理参数校验失败的异常,可以在 GlobalExceptionHandler 类中定义一个处理 MethodArgumentNotValidException 类型异常的方法。
@ControllerAdvice public class GlobalExceptionHandler { // 处理 Exception 类型异常的方法 @ExceptionHandler(MethodArgumentNotValidException.class) @ResponseBody public ErrorResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { BindingResult bindingResult = e.getBindingResult(); List<ObjectError> allErrors = bindingResult.getAllErrors(); List<String> errorMessages = new ArrayList<>(); for (ObjectError error : allErrors) { errorMessages.add(error.getDefaultMessage()); } String errorMessage = String.join(",", errorMessages); return new ErrorResponse(HttpStatus.BAD_REQUEST.value(), errorMessage); } }
在上述代码中,我们使用 @ExceptionHandler 注解定义了一个处理 MethodArgumentNotValidException 类型异常的方法。在处理方法中,我们首先获取 BindingResult 对象,并遍历其中的所有错误信息,将它们合并为一个错误消息,并返回一个 ErrorResponse 对象。
完整代码示例
下面是一个完整的使用 @ControllerAdvice 进行全局异常处理的示例代码:
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) @ResponseBody public ErrorResponse handleException(Exception e) { return new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage()); } @ExceptionHandler(MethodArgumentNotValidException.class) @ResponseBody public ErrorResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { BindingResult bindingResult = e.getBindingResult(); List<ObjectError> allErrors = bindingResult.getAllErrors(); List<String> errorMessages = new ArrayList<>(); for (ObjectError error : allErrors) { errorMessages.add(error.getDefaultMessage()); } String errorMessage = String.join(",", errorMessages); return new ErrorResponse(HttpStatus.BAD_REQUEST.value(), errorMessage); } } @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @PostMapping("/add") public Result addUser(@Validated @RequestBody User user) { userService.addUser(user); return Result.success(); } @GetMapping("/{id}") public Result getUserById(@PathVariable("id") Long id) { User user = userService.getUserById(id); if (user == null) { return Result.error("用户不存在"); } return Result.success(user); } } @Service public class UserService { @Autowired private UserDao userDao; public void addUser(User user) { userDao.save(user); } public User getUserById(Long id) { return userDao.findById(id).orElse(null); } } @Data @NoArgsConstructor @AllArgsConstructor public class User { @NotNull(message = "用户名不能为空") private String username; @NotNull(message = "密码不能为空") @Size(min = 6, message ="密码长度不能小于6") private String password; } @Data @NoArgsConstructor @AllArgsConstructor public class Result { private int code; private String message; private Object data; public static Result success() { return new Result(HttpStatus.OK.value(), "操作成功", null); } public static Result success(Object data) { return new Result(HttpStatus.OK.value(), "操作成功", data); } public static Result error(String message) { return new Result(HttpStatus.BAD_REQUEST.value(), message, null); } }
在上述代码中,我们定义了一个 GlobalExceptionHandler 类,使用 @ControllerAdvice 注解标注,并在其中定义了处理 Exception 和 MethodArgumentNotValidException 类型异常的方法。
我们还定义了一个 UserController 类和一个 UserService 类,用于处理用户相关的业务逻辑。在 UserController 类中,我们使用 @Validated 注解对 User 对象进行参数校验,并在 User 类中使用了 javax.validation.constraints 包中的注解对 username 和 password 属性进行了校验。如果参数校验失败,会触发 MethodArgumentNotValidException 异常,在 GlobalExceptionHandler 类中的 handleMethodArgumentNotValidException 方法中进行处理。
在 UserController 类中,我们使用 Result 类作为接口返回值对象,用于封装接口返回结果。在 Result 类中,我们定义了一个静态方法 success 和 error,用于生成成功和失败的返回结果,并定义了 code、message 和 data 三个属性,用于封装返回结果的状态码、消息和数据。
总结
在本文中,我们介绍了如何在 SpringBoot 中使用 @ControllerAdvice 注解处理异常消息。通过使用 @ControllerAdvice 注解,我们可以集中处理所有 Controller 层抛出的异常,而不必在每个 Controller 中单独处理。在 GlobalExceptionHandler 类中定义异常处理方法,并根据具体的业务需求对异常进行相应的处理,可以大大提高代码的可维护性和可读性。