← Назад к вопросам
Что такое @ExceptionHandler?
1.7 Middle🔥 201 комментариев
#REST API и микросервисы#Spring Framework
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
@ExceptionHandler: обработка исключений в Spring
@ExceptionHandler — это аннотация в Spring Framework, которая определяет метод для обработки определённого типа исключений в контроллерах. Она позволяет централизованно обрабатывать ошибки и возвращать понятные ответы клиентам.
Основное назначение
@ExceptionHandler решает следующие задачи:
- Централизованная обработка ошибок — вместо try-catch в каждом методе
- Единообразный формат ошибок — все ошибки возвращаются в одинаковом формате
- Правильные HTTP статусы — 400, 404, 500 в зависимости от типа ошибки
- Логирование ошибок — все исключения логируются в одном месте
- Безопасность — скрывает внутренние детали ошибок от клиента
Простой пример
// Кастомное исключение
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
// DTO для ответа об ошибке
public class ErrorResponse {
private int status;
private String message;
private LocalDateTime timestamp;
public ErrorResponse(int status, String message) {
this.status = status;
this.message = message;
this.timestamp = LocalDateTime.now();
}
// getters
}
// Контроллер с @ExceptionHandler
@RestController
@RequestMapping("/api/products")
public class ProductController {
@GetMapping("/{id}")
public ResponseEntity<ProductDTO> getProduct(@PathVariable Long id) {
return productService.findById(id)
.map(ResponseEntity::ok)
.orElseThrow(() -> new ResourceNotFoundException(
"Товар с ID " + id + " не найден"
));
}
// Обработчик для ResourceNotFoundException
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleResourceNotFound(
ResourceNotFoundException ex) {
ErrorResponse error = new ErrorResponse(404, ex.getMessage());
return ResponseEntity.status(404).body(error);
}
// Обработчик для других исключений
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<ErrorResponse> handleIllegalArgument(
IllegalArgumentException ex) {
ErrorResponse error = new ErrorResponse(400, ex.getMessage());
return ResponseEntity.status(400).body(error);
}
}
Иерархия исключений
@ExceptionHandler автоматически выбирает обработчик на основе иерархии исключений:
@RestControllerAdvice // Глобальная обработка для всех контроллеров
public class GlobalExceptionHandler {
// Самый специфичный обработчик
@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<ErrorResponse> handleEntityNotFound(
EntityNotFoundException ex) {
return ResponseEntity.status(404)
.body(new ErrorResponse(404, ex.getMessage()));
}
// Более общий обработчик (родительский класс)
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<ErrorResponse> handleRuntimeException(
RuntimeException ex) {
return ResponseEntity.status(500)
.body(new ErrorResponse(500, "Внутренняя ошибка сервера"));
}
// Самый общий обработчик
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGenericException(
Exception ex) {
return ResponseEntity.status(500)
.body(new ErrorResponse(500, "Неизвестная ошибка"));
}
}
@RestControllerAdvice vs локальный @ExceptionHandler
Локальный @ExceptionHandler (в контроллере)
@RestController
public class ProductController {
@GetMapping("/products/{id}")
public ProductDTO getProduct(@PathVariable Long id) {
return productService.findById(id);
}
// Обработчик только для этого контроллера
@ExceptionHandler(ProductNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(ProductNotFoundException ex) {
return ResponseEntity.status(404)
.body(new ErrorResponse(404, ex.getMessage()));
}
}
Плюсы: специфичная обработка для одного контроллера Минусы: дублирование кода, нет централизации
Глобальный @RestControllerAdvice
@RestControllerAdvice // Работает для всех контроллеров
public class GlobalExceptionHandler {
@ExceptionHandler(ProductNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(ProductNotFoundException ex) {
return ResponseEntity.status(404)
.body(new ErrorResponse(404, ex.getMessage()));
}
}
Плюсы: централизованная обработка, нет дублирования Минусы: менее специфична
Практический пример с валидацией
@RestController
@RequestMapping("/api/users")
public class UserController {
@PostMapping
public ResponseEntity<UserDTO> createUser(@Valid @RequestBody CreateUserRequest req) {
return ResponseEntity.status(201)
.body(userService.create(req));
}
}
@RestControllerAdvice
public class GlobalExceptionHandler {
// Обработка ошибок валидации
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ValidationErrorResponse> handleValidationException(
MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(error ->
errors.put(error.getField(), error.getDefaultMessage())
);
ValidationErrorResponse response = new ValidationErrorResponse(
400,
"Ошибка валидации",
errors
);
return ResponseEntity.status(400).body(response);
}
// Обработка бизнес-ошибок
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException ex) {
return ResponseEntity.status(ex.getStatusCode())
.body(new ErrorResponse(ex.getStatusCode(), ex.getMessage()));
}
// Обработка любых неожиданных ошибок
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleUnexpectedException(Exception ex) {
// Логирование для отладки
logger.error("Неожиданная ошибка", ex);
return ResponseEntity.status(500)
.body(new ErrorResponse(500, "Внутренняя ошибка сервера"));
}
}
Важные моменты
- Порядок выполнения — Spring выбирает самый специфичный обработчик
- ResponseEntity — позволяет контролировать статус код и заголовки
- Логирование — всегда логируй исключения для отладки
- Безопасность — не отправляй стек-трейсы клиентам в продакшене
- HTTP статусы — используй правильные коды (400, 404, 500 и т.д.)
Рекомендации
- Используй @RestControllerAdvice для централизованной обработки
- Создавай кастомные исключения для разных типов ошибок
- Возвращай единообразный формат ошибок
- Логируй все исключения
- Не передавай чувствительную информацию в ответах клиентам