JavaRush /Курсы /Модуль 5. Spring /Использование аннотации @Valid для валидации запросов

Использование аннотации @Valid для валидации запросов

Модуль 5. Spring
9 уровень , 2 лекция
Открыта

Валидация "без участия человека" — это как иметь добросовестного робота, который проверяет вашу почту перед тем, как вы её читаете: мусор отбрасывает, важные письма отмечает. Аналогично, аннотация @Valid позволяет автоматизировать проверку входящих данных в ваших контроллерах и сервисах.

Основные аспекты @Valid

  • Она является частью спецификации Bean Validation API.
  • Автоматически проверяет, соответствуют ли входящие данные аннотациям валидации, объявленным в DTO (Data Transfer Object) или других объектах.
  • Помогает упростить и централизовать валидацию данных, сохраняя ваш код чистым и читаемым.

Простейший пример: вы принимаете JSON как тело POST-запроса, и вам нужно, чтобы поле "email" было обязательным и соответствовало формату email. Вместо ручной проверки (например, через if) с помощью @Valid и нескольких аннотаций валидации всё это обрабатывается автоматически.


Как использовать @Valid в контроллерах?

Шаг 1. Объявление DTO

Начнём с создания DTO-класса. DTO (Data Transfer Object) — это объект, который используется для передачи данных, например, от клиента к серверу.


import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

public class UserDTO {

    @NotNull(message = "Имя пользователя не может быть пустым.")
    @Size(min = 2, max = 30, message = "Имя пользователя должно содержать от 2 до 30 символов.")
    private String username;

    @NotNull(message = "Email обязателен.")
    @Email(message = "Некорректный формат email.")
    private String email;

    public UserDTO() {}

    public UserDTO(String username, String email) {
        this.username = username;
        this.email = email;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

Здесь мы используем:

  • @NotNull — чтобы убедиться, что поле не пустое.
  • @Size — чтобы ограничить длину строки.
  • @Email — чтобы проверить, что email корректен.

С полем разобрались! Переходим к следующему шагу.

Шаг 2. Создание REST-контроллера

Теперь используем аннотацию @Valid в контроллере для автоматической проверки входящих данных.


import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;

@RestController
@RequestMapping("/api/users")
@Validated
public class UserController {

    @PostMapping
    public ResponseEntity<String> createUser(@Valid @RequestBody UserDTO userDTO) {
        // Если данные валидны, выполнение доходит сюда.
        return new ResponseEntity<>("Пользователь успешно создан", HttpStatus.CREATED);
    }
}
  • @RestController указывает, что этот класс — REST-контроллер.
  • @RequestBody — преобразует JSON в объект UserDTO.
  • @Valid — запускает валидацию, которая проверяет поля UserDTO.

Если входящие данные валидны, тело запроса успешно преобразуется в объект, и сервер возвращает HTTP 201 (Created). Если валидация не прошла, Spring автоматически выбросит исключение MethodArgumentNotValidException.

Шаг 3. Добавление пользовательских сообщений

Каждая аннотация валидации в UserDTO содержит параметр message, который указывает текст ошибки. Например, если поле email не соответствует формату, клиент получит сообщение "Некорректный формат email.".


Пример приложения с использованием @Valid

Скомпонуем всё в одно небольшое приложение.

Основной код приложения

DTO:


public class UserDTO {
    @NotNull(message = "Имя пользователя не может быть пустым.")
    @Size(min = 2, max = 30, message = "Имя пользователя должно содержать от 2 до 30 символов.")
    private String username;

    @NotNull(message = "Email обязателен.")
    @Email(message = "Некорректный формат email.")
    private String email;

    // Геттеры, сеттеры и конструктор
}

Controller:


@RestController
@RequestMapping("/api/users")
@Validated
public class UserController {

    @PostMapping
    public ResponseEntity<String> createUser(@Valid @RequestBody UserDTO userDTO) {
        return new ResponseEntity<>("Пользователь успешно создан", HttpStatus.CREATED);
    }
}

application.properties:


server.port=8080

Что, если данные не валидны?

При отправке некорректных данных Spring автоматически вернёт HTTP 400 (Bad Request) с сообщением об ошибке в формате JSON:


{
    "timestamp": "2023-10-01T12:34:56.789+00:00",
    "status": 400,
    "error": "Bad Request",
    "message": "Некорректный формат email.",
    "path": "/api/users"
}

Часто встречающиеся ошибки

  1. Отсутствие зависимости Bean Validation в pom.xml. В проекте может отсутствовать необходимая зависимость. Убедитесь, что в вашем pom.xml добавлен модуль Bean Validation:
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    
  2. Тело запроса не преобразуется в DTO. Если вы забыли указать @RequestBody, JSON просто не будет распознан. Всегда помните об этой аннотации.
  3. Неправильный импорт аннотации @Valid. Убедитесь, что используете jakarta.validation.Valid (или javax.validation.Valid в старых версиях), а не что-то из сторонних библиотек.
  4. Забыта обработка исключений. Spring может выбросить исключение MethodArgumentNotValidException, которое, если не обработано, приведёт к некрасивым и запутанным сообщениям для пользователя.

Практическое применение

Валидация через @Valid широко используется в реальных проектах для:

  • Автоматической проверки данных, поступающих от клиентов.
  • Предотвращения ошибок на раннем этапе, до попадания данных в бизнес-логику или базу.
  • Улучшения читаемости и поддержки кода.

На собеседованиях вас могут попросить описать, как вы реализуете валидацию в Spring, а ещё лучше — написать простую REST-операцию с @Valid. Знание этого инструмента даст вам серьёзное преимущество.

Комментарии (2)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Никита Уровень 96
5 марта 2026
Странно, что ничего не упомянули про каскадную валидацию, если коротко: Каскадная валидация позволяет проверять не только поля текущего объекта, но и вложенные объекты. Для этого на поле вложенного объекта ставится аннотация @Valid. Без неё валидатор проверяет только текущий класс и не переходит внутрь вложенных объектов. Например, если UserDTO содержит AddressDTO address, то ограничения внутри AddressDTO будут проверяться только если поле объявлено как: @Valid private AddressDTO address. Тот же принцип действует для коллекций: @Valid private List<AddressDTO> addresses
Никита Уровень 96
5 марта 2026
Непонятно зачем сначала ставится @Validated на класс, а потом еще и @Valid в параметры метода. Одну из аннотаций стоит убрать