Глобальная обработка исключений с @ControllerAdvice
Централизуйте обработку исключений во всех контроллерах с помощью @ExceptionHandler и @ControllerAdvice.
«Глобальная обработка исключений с @ControllerAdvice» — бесплатный урок Java Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.
Проблема отсутствия глобальной обработки
Без глобальной обработки исключений каждому методу контроллера нужны блоки обработки исключений, создание ответов с ошибками дублируется, а подробности исключений становятся доступны клиентам.
@ControllerAdvice и @RestControllerAdvice
@ControllerAdvice определяет класс глобального обработчика исключений. @RestControllerAdvice добавляет @ResponseBody, поэтому все методы обработчика автоматически возвращают JSON.
@RestControllerAdvice
public class GlobalExceptionHandler {
// @ExceptionHandler methods go here
}Методы @ExceptionHandler
Снабдите метод аннотацией @ExceptionHandler(ExceptionType.class). Spring направит исключения этого типа и его подтипов в данный метод. Возвращайте ResponseEntity с подходящим статусом.
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse("NOT_FOUND", ex.getMessage()));
}Обработка нескольких типов исключений
Перечислите несколько типов исключений в одном обработчике или используйте общий базовый класс. Spring выберет наиболее специализированный доступный обработчик.
@ExceptionHandler({IllegalArgumentException.class, IllegalStateException.class})
public ResponseEntity<ErrorResponse> handleBadRequest(RuntimeException ex) {
return ResponseEntity.badRequest()
.body(new ErrorResponse("BAD_REQUEST", ex.getMessage()));
}Обработка ошибок проверки
Перехватывайте MethodArgumentNotValidException, чтобы извлечь ошибки отдельных полей из тел запросов, проверенных с помощью @Valid.
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, Object>> handleValidation(MethodArgumentNotValidException ex) {
Map<String, String> fieldErrors = new LinkedHashMap<>();
ex.getBindingResult().getFieldErrors().forEach(e ->
fieldErrors.put(e.getField(), e.getDefaultMessage()));
return ResponseEntity.badRequest()
.body(Map.of("errors", fieldErrors, "status", 400));
}Обработка нарушений ограничений
ConstraintViolationException выбрасывается при проверке параметров методов с помощью @Validated на уровне сервиса. Обрабатывайте это исключение отдельно от ошибок проверки MVC.
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<Map<String, String>> handleConstraint(ConstraintViolationException ex) {
Map<String, String> errors = new LinkedHashMap<>();
ex.getConstraintViolations().forEach(v ->
errors.put(v.getPropertyPath().toString(), v.getMessage()));
return ResponseEntity.badRequest().body(errors);
}Доступ к HttpServletRequest
Добавьте HttpServletRequest в качестве параметра, чтобы получить сведения о запросе (URL, метод и заголовки) для ведения журнала или включения этих данных в ответ с ошибкой.
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAll(Exception ex, HttpServletRequest req) {
log.error("Unhandled error on {} {}", req.getMethod(), req.getRequestURI(), ex);
return ResponseEntity.internalServerError()
.body(new ErrorResponse("INTERNAL_ERROR", "Unexpected error"));
}@ResponseStatus в классах исключений
Снабдите пользовательские классы исключений аннотацией @ResponseStatus, чтобы автоматически задать статус HTTP без метода обработчика. Это проще для прямолинейных случаев.
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String msg) { super(msg); }
}Ограничение области действия @ControllerAdvice
Ограничьте обработчик определёнными пакетами, аннотациями или базовыми классами с помощью атрибутов @ControllerAdvice.
@RestControllerAdvice(basePackages = "com.example.api")
public class ApiExceptionHandler { ... }
@RestControllerAdvice(assignableTypes = {UserController.class, OrderController.class})
public class SpecificHandler { ... }Ведение журнала в обработчиках исключений
Записывайте исключения на подходящем уровне: ошибки пользователя (4xx) — на уровне WARN, непредвиденные ошибки (5xx) — на уровне ERROR с полной трассировкой стека.
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAll(Exception ex, HttpServletRequest req) {
if (ex instanceof BusinessException) log.warn("Business error: {}", ex.getMessage());
else log.error("Unexpected error on {}", req.getRequestURI(), ex);
return ...
}Приоритет обработчиков исключений
Spring выбирает наиболее конкретный обработчик. Если ResourceNotFoundException extends RuntimeException, обработчик для ResourceNotFoundException имеет приоритет над обработчиком для RuntimeException.
Быстрая проверка
Какая аннотация помечает метод для глобальной обработки исключений определенного типа?
Итоги
Используйте @RestControllerAdvice и @ExceptionHandler, чтобы централизовать обработку ошибок. Возвращайте ResponseEntity с единообразной структурой ошибок. Обрабатывайте проверку данных (MethodArgumentNotValidException) и ограничения (ConstraintViolationException) отдельно. Записывайте ошибки 4xx в журнал как WARN, а ошибки 5xx — как ERROR.
Часто задаваемые вопросы
Урок «Глобальная обработка исключений с @ControllerAdvice» бесплатный?
Да — полный текст урока «Глобальная обработка исключений с @ControllerAdvice» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.
Чему я научусь в уроке «Глобальная обработка исключений с @ControllerAdvice»?
Централизуйте обработку исключений во всех контроллерах с помощью @ExceptionHandler и @ControllerAdvice. Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Java Academy?
Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Глобальная обработка исключений с @ControllerAdvice»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Java Academy?
Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Проверка компонентов: @NotNull, @Size, @Pattern
- Пользовательские аннотации ограничений
- Глобальная обработка исключений с @ControllerAdvice
- Детали проблемы RFC 7807 и единообразные ответы с ошибками