Данные, которые приходят из запроса, могут быть чем угодно. Bean Validation — стандарт Jakarta EE, который позволяет описать правила прямо в классе DTO и не засорять бизнес-логику проверками if (name == null || name.isBlank()).
Зачем это нужно
Без валидации каждый контроллер или сервис вынужден сам проверять входные данные. Получается повторяющийся, хрупкий код. Bean Validation решает задачу иначе: правила объявляются один раз — в классе-объекте передачи данных (DTO) — и Spring применяет их автоматически до того, как управление попадёт в метод контроллера.
Зависимость уже включена в spring-boot-starter-web, ничего отдельно подключать не нужно.
Аннотации: что ставить на поля DTO
Все аннотации из пакета jakarta.validation.constraints.*:
public record CreateUserRequest(
@NotBlank String username,
@Email @NotBlank String email,
@Size(min = 8, max = 72) String password,
@Min(0) @Max(150) int age,
@Pattern(regexp = "\\+\\d{7,15}") String phone
) {}
Короткая формула: @NotNull — значение не null; @NotBlank — строка не null и не пустая (включая пробелы); @Size — длина строки или коллекции; @Min / @Max — диапазон числа; @Email — формат электронной почты; @Pattern — произвольное регулярное выражение.
Каждая аннотация принимает атрибут message для переопределения текста ошибки — подробнее о кастомных сообщениях в статье про собственные аннотации и сообщения.
@Valid в контроллере запускает проверку
Одна аннотация @Valid перед параметром — и Spring проверяет всё DTO перед вызовом метода:
@RestController
@RequestMapping("/users")
public class UserController {
@PostMapping
public ResponseEntity<Void> create(@Valid @RequestBody CreateUserRequest request) {
// сюда код попадает только если все проверки прошли
return ResponseEntity.status(HttpStatus.CREATED).build();
}
}
Без @Valid аннотации на полях DTO ни на что не влияют — Spring просто не запустит проверку.
Вложенные объекты и каскад
Если DTO содержит другой объект, аннотации на его полях не сработают автоматически. Нужно поставить @Valid на само поле — тогда Spring проверит вложенный объект каскадно:
public record CreateOrderRequest(
@NotNull @Valid AddressRequest address,
@Size(min = 1) List<@Valid OrderItemRequest> items
) {}
public record AddressRequest(
@NotBlank String city,
@NotBlank String street
) {}
Без @Valid на поле address проверка остановится на уровне CreateOrderRequest и не зайдёт внутрь AddressRequest.
Группы валидации
Иногда одно поле нужно проверять по-разному в зависимости от операции. Для этого Bean Validation поддерживает группы:
public interface OnCreate {}
public interface OnUpdate {}
public record UserRequest(
@NotNull(groups = OnCreate.class) String username,
@NotBlank(groups = {OnCreate.class, OnUpdate.class}) String email
) {}
В контроллере вместо @Valid используется @Validated с указанием группы:
@PostMapping
public ResponseEntity<Void> create(@Validated(OnCreate.class) @RequestBody UserRequest request) { ... }
@PutMapping("/{id}")
public ResponseEntity<Void> update(@PathVariable Long id,
@Validated(OnUpdate.class) @RequestBody UserRequest request) { ... }
На практике группы нужны редко — чаще достаточно отдельных DTO для создания и обновления.
Что происходит при ошибке
Если хотя бы одно ограничение нарушено, Spring выбрасывает MethodArgumentNotValidException. По умолчанию это 400 Bad Request с объёмным телом ответа, не очень удобным для клиента.
Чтобы вернуть понятную ошибку в едином формате, нужен глобальный обработчик — @RestControllerAdvice с методом на MethodArgumentNotValidException. Как его написать, описано в статье Обработка ошибок REST API в Java.
Глубокие правила оформления валидации (какой слой отвечает за что, когда @Validated на сервисе, а когда нет) — в стайл-гайде по валидации.
Коротко
@NotBlank,@Size,@Email,@Min/@Max,@Pattern— аннотации изjakarta.validation.constraints.*описывают правила прямо в DTO.@Validперед параметром метода запускает проверку; без него аннотации не работают.- Для вложенных объектов нужен
@Validна самом поле — иначе проверка не уйдёт глубже. - При нарушении Spring выбрасывает
MethodArgumentNotValidException— обрабатывается в@RestControllerAdvice. - Группы валидации (
@Validated(Group.class)) нужны редко; в большинстве случаев лучше использовать отдельные DTO.
Что почитать дальше
- Где проводить валидацию в Spring-приложении — какой слой за что отвечает.
- Собственные аннотации и сообщения об ошибках — как выйти за рамки стандартных ограничений.
- Обработка ошибок REST API в Java — как красиво вернуть
400с деталями нарушений.