← Назад к вопросам

Что такое @ControllerAdvice?

2.0 Middle🔥 201 комментариев
#REST API и микросервисы#Spring Framework

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое @ControllerAdvice

@ControllerAdvice — это аннотация Spring Framework, которая позволяет определить глобальный обработчик исключений и другие кросс-функциональные компоненты для всех контроллеров приложения. Она предоставляет централизованный способ обработки ошибок и исключений в REST API.

Основное назначение

@ControllerAdvice используется для:

  • Глобальной обработки исключений — перехват исключений из всех контроллеров
  • Подготовки моделей данных — инициализация данных для всех представлений
  • Преобразования данных — конвертация между форматами
  • Валидации данных — применение кастомной валидации

Архитектура и использование

// Простой пример глобального обработчика
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ResponseEntity<ErrorResponse> handleResourceNotFound(
            ResourceNotFoundException ex) {
        ErrorResponse error = new ErrorResponse(
            "NOT_FOUND",
            ex.getMessage(),
            System.currentTimeMillis()
        );
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
    }

    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseEntity<ErrorResponse> handleIllegalArgument(
            IllegalArgumentException ex) {
        ErrorResponse error = new ErrorResponse(
            "BAD_REQUEST",
            ex.getMessage(),
            System.currentTimeMillis()
        );
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
    }

    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseEntity<ErrorResponse> handleGenericException(Exception ex) {
        ErrorResponse error = new ErrorResponse(
            "INTERNAL_SERVER_ERROR",
            "An unexpected error occurred",
            System.currentTimeMillis()
        );
        return ResponseEntity
            .status(HttpStatus.INTERNAL_SERVER_ERROR)
            .body(error);
    }
}

Класс для ответа об ошибке

public class ErrorResponse {
    private String code;
    private String message;
    private long timestamp;
    private List<FieldError> errors;

    public ErrorResponse(String code, String message, long timestamp) {
        this.code = code;
        this.message = message;
        this.timestamp = timestamp;
        this.errors = new ArrayList<>();
    }

    // getters и setters
    public String getCode() { return code; }
    public String getMessage() { return message; }
    public long getTimestamp() { return timestamp; }
    public List<FieldError> getErrors() { return errors; }
}

Обработка ошибок валидации

@ControllerAdvice
public class ValidationExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseEntity<ErrorResponse> handleValidationExceptions(
            MethodArgumentNotValidException ex) {
        ErrorResponse error = new ErrorResponse(
            "VALIDATION_ERROR",
            "Validation failed",
            System.currentTimeMillis()
        );

        // Собираем все ошибки валидации
        ex.getBindingResult().getAllErrors().forEach(err -> {
            String fieldName = ((FieldError) err).getField();
            String errorMessage = err.getDefaultMessage();
            error.getErrors().add(new FieldError(fieldName, errorMessage));
        });

        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
    }
}

Инициализация данных для всех представлений

@ControllerAdvice
public class GlobalControllerAdvice {

    @ModelAttribute("currentUser")
    public User currentUser(Principal principal) {
        if (principal != null) {
            return userService.findByUsername(principal.getName());
        }
        return null;
    }

    @ModelAttribute("siteName")
    public String siteName() {
        return "My Application";
    }
}

Преобразователь (Converter) для всех контроллеров

@ControllerAdvice
public class GlobalConverters {

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        // Регистрируем кастомный форматер для даты
        binder.registerCustomEditor(LocalDate.class, 
            new PropertyEditorSupport() {
                @Override
                public void setAsText(String text) {
                    setValue(LocalDate.parse(text, 
                        DateTimeFormatter.ofPattern("dd/MM/yyyy")));
                }
            });
    }
}

Ограничение области действия

Если нужно применить ControllerAdvice только к определённым контроллерам:

@ControllerAdvice(assignableTypes = {UserController.class, AdminController.class})
public class SpecificExceptionHandler {
    // Обработка только для указанных контроллеров
}

// Или по пакетам
@ControllerAdvice(basePackages = {"com.example.api", "com.example.admin"})
public class PackageBasedAdvice {
    // Обработка для контроллеров из указанных пакетов
}

Преимущества @ControllerAdvice

  • DRY принцип — не нужно писать обработку ошибок в каждом контроллере
  • Консистентность — все ошибки обрабатываются одинаково
  • Централизация — вся логика обработки в одном месте
  • Переиспользуемость — методы могут применяться к разным типам исключений
  • Улучшенная безопасность — можно скрывать внутренние детали ошибок от клиентов

Заключение

@ControllerAdvice — это мощный инструмент Spring Framework для создания чистой и поддерживаемой архитектуры обработки ошибок. Вместо разбросанной логики обработки исключений по всему коду, вы получаете централизованное, тестируемое и расширяемое решение, которое упрощает разработку REST API.