Ответ
В Spring Boot глобальная обработка исключений реализуется с помощью аннотации @ControllerAdvice (или @RestControllerAdvice для REST API). Класс, помеченный этой аннотацией, перехватывает исключения, выброшенные в любом контроллере, и позволяет вернуть клиенту структурированный и безопасный ответ.
Базовая реализация:
-
DTO для ошибки:
@Data // Lombok аннотация для геттеров/сеттеров @AllArgsConstructor public class ErrorResponse { private String message; // Понятное сообщение для пользователя private String details; // Детали (например, ID ошибки, в dev-среде — сообщение исключения) private Instant timestamp; private String path; } -
Глобальный обработчик исключений (
@RestControllerAdvice):@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) // Перехватывает все неперехваченные исключения public ResponseEntity<ErrorResponse> handleAllUncaughtException( Exception ex, WebRequest request) { ErrorResponse error = new ErrorResponse( "Внутренняя ошибка сервера", // В продакшене здесь должен быть ID ошибки, а не сообщение исключения ex.getMessage(), Instant.now(), request.getDescription(false) // URI запроса ); return ResponseEntity .status(HttpStatus.INTERNAL_SERVER_ERROR) .body(error); } // Специфичная обработка для исключений валидации @Valid @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<ErrorResponse> handleValidationException( MethodArgumentNotValidException ex) { List<String> details = ex.getBindingResult() .getFieldErrors() .stream() .map(error -> error.getField() + ": " + error.getDefaultMessage()) .collect(Collectors.toList()); ErrorResponse error = new ErrorResponse( "Ошибка валидации", String.join(", ", details), Instant.now(), "" ); return ResponseEntity.badRequest().body(error); } // Обработка кастомных бизнес-исключений @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity<ErrorResponse> handleResourceNotFound( ResourceNotFoundException ex) { ErrorResponse error = new ErrorResponse( "Ресурс не найден", ex.getMessage(), Instant.now(), "" ); return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error); } }
Ключевые моменты:
@RestControllerAdvice— это специализация@ControllerAdvice, которая автоматически оборачивает возвращаемое значение в@ResponseBody(для REST).@ExceptionHandlerопределяет, какой тип исключения будет обработан данным методом.- Безопасность: В продакшенной среде никогда не следует возвращать клиенту stack trace или детальные сообщения об ошибках системы. Вместо этого используйте уникальные ID ошибок, которые можно сопоставить с логами на сервере.
- Порядок обработки: Spring выбирает наиболее специфичный обработчик. Если исключение не соответствует ни одному
@ExceptionHandler, оно будет перехвачено обработчиком дляException.class.