Ответ
Spring MVC предлагает несколько механизмов для глобальной и контроллер-специфичной обработки исключений:
-
Аннотация
@ExceptionHandlerна уровне контроллера.- Что делает: Позволяет обрабатывать исключения, выброшенные в методах одного контроллера.
- Пример:
@RestController @RequestMapping("/api/users") public class UserController { @ExceptionHandler(UserNotFoundException.class) public ResponseEntity<String> handleUserNotFound(UserNotFoundException ex) { return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage()); } @GetMapping("/{id}") public User getUser(@PathVariable Long id) { // Может выбросить UserNotFoundException return userService.findById(id); } }
-
@ControllerAdvice(или@RestControllerAdvice) — глобальный обработчик.- Что делает: Класс, методы которого (
@ExceptionHandler,@InitBinder,@ModelAttribute) применяются ко всем контроллерам. Это основной способ глобальной обработки. - Пример:
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(ResourceNotFoundException.class) @ResponseStatus(HttpStatus.NOT_FOUND) public ErrorResponse handleNotFound(ResourceNotFoundException ex) { return new ErrorResponse("NOT_FOUND", ex.getMessage()); } @ExceptionHandler(MethodArgumentNotValidException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public ErrorResponse handleValidation(MethodArgumentNotValidException ex) { // Обработка ошибок валидации @Valid List<String> errors = ex.getBindingResult() .getFieldErrors() .stream() .map(FieldError::getDefaultMessage) .collect(Collectors.toList()); return new ErrorResponse("VALIDATION_ERROR", errors.toString()); } @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ErrorResponse handleAll(Exception ex) { return new ErrorResponse("INTERNAL_ERROR", "Произошла внутренняя ошибка"); } }
- Что делает: Класс, методы которого (
-
ResponseStatusException(с Spring 5).- Что делает: Программный способ выброса исключения с нужным HTTP-статусом и сообщением без создания кастомных классов исключений.
- Пример:
@GetMapping("/{id}") public User getUser(@PathVariable Long id) { return userRepository.findById(id) .orElseThrow(() -> new ResponseStatusException( HttpStatus.NOT_FOUND, "User not found" )); }
Best Practice: Используйте @RestControllerAdvice для единой точки обработки всех бизнес- и системных исключений в REST API, возвращая структурированные объекты ошибок (ErrorResponse).