23 января 2025
Тэги: Java, json, maven, rest, Spring.
Spring позволяет проверять входящие запросы в декларативном стиле при помощи специальных аннотаций из пакета jakarta.validation.
Создадим простой проект на Java и добавим в pom.xml следующие зависимости:
Компонент spring-boot-starter-web добавляет базовый функционал по работе с rest-контроллерами, а spring-boot-starter-validation – сам механизм валидации.
Теперь создадим rest-контроллер для работы с пользователями. В нём есть метод, создающий нового пользователя. Согласно restful-соглашениям, это будет POST-запрос:
На вход метод принимает CreateUserRequest, который мы будем передавать в формате json. Этот параметр метода снабжён аннотациями @RequestBody (говорит, что параметры будут именно в теле запроса) и @Valid (аннотация, которая активирует механизм валидации для данного бина). Если не указать аннотацию @Valid, то валидация работать не будет!
Поскольку сама логика добавления пользователя в БД нас сейчас не интересует, метод в случае успеха просто возвращает строку «Пользователь создан успешно!».
Класс, представляющий тело запроса, выглядит так:
Тип record означает, что компилятор автоматически создаст для каждого поля get-методы, конструктор с параметрами и ряд вспомогательных методов, таких как equals(), hashCode() и toString(). Вы также можете использовать обычный class, но тогда придётся написать чуть больше шаблонного кода или использовать Lombok.
Здесь представлены основные аннотации, используемые для валидации входных данных.
Аннотация @NotNull указывает на обязательность параметра. Если мы такую аннотацию вешаем на числовые типы, то следует использовать именно ссылочные типы, а не примитивные, иначе смысл аннотации теряется. Например, тип int всегда имеет значение по умолчанию, а потому проверка не сработает даже если в теле запроса этот параметр не будет указан. Чтобы отловить эту ситуацию, используйте ссылочный Integer.
Аннотация @NotBlank проверяет, что строка не состоит из одних пробелов. Это особенно актуально для ключевых полей, которые должны содержать какую-то информацию.
Аннотация @Past применительно к датам проверяет, что указана уже прошедшая дата. Очевидно, что дата рождения пользователя всегда меньше текущей даты.
Аннотация @Positive указывает, что число должно быть положительным. В нашем случае это поле friendsCount, ведь количественные характеристики не могут быть отрицательными.
Аннотация @Size применительно к спискам позволяет задать минимальное и максимальное количество элементов. Если эту аннотацию поставить на строку, то мы будем проверять минимальное и максимальное количество символов в строке.
Если проверка не прошла, мы получим какое-то стандартное сообщение об ошибке. Но вы всегда можете задать своё сообщение, используя параметр message в соответствующей аннотации.
Давайте проверим работу валидации и отправим POST-запрос с пустым телом на эндпоинт /users.
В ответ получим http-статус 400 Bad Request и стандартный json:
Такой ответ приходит по умолчанию и он не очень информативный. Только с помощью логов мы сможем узнать, что возникло исключение MethodArgumentNotValidException и в чём была причина его возникновения. Возможно, с точки зрения безопасности иногда это оправдано, но чаще требуется явно указать пользователю, какие именно поля не прошли валидацию. Поэтому давайте изменим стандартный ответ при ошибке.
Это можно сделать с помощью аннотации @ExceptionHandler. В самом простом случае достаточно добавить в контроллер следующий метод:
Здесь с помощью аннотации @ResponseStatus мы явно указываем, какой http-статус будем отдавать в случае ошибки. Аннотация @ExceptionHandler обрабатывает только исключение MethodArgumentNotValidException. Благодаря этому мы можем получать исключение в случае его возникновения как параметр метода. Внутри просто строим мапу, где ключом будет имя поля, из-за которого возникла ошибка, а значением – текстовое сообщение об ошибке.
Тогда формат ответа при пустом теле запроса будет таким:
Как видите, собственные сообщения об ошибке выглядят более информативно.
Теперь отправим json, удовлетворяющий всем этим проверкам:
В ответ получим http-статус 200 и сообщение «Пользователь создан успешно!».
Мы убедились, что компонент spring-boot-starter-validation позволяет легко производить валидацию входящих запросов в декларативном стиле с помощью набора базовых проверок. Если проверка не пройдена – возникает исключение MethodArgumentNotValidException.
Также мы рассмотрели, как с помощью @ExceptionHandler сделать стандартный ответ при ошибке валидации более информативным для клиента.
Kotlin, Java, Spring, Spring Boot, Spring Data, SQL, PostgreSQL, Oracle, H2, Linux, Hibernate, Collections, Stream API, многопоточность, чат-боты, нейросети, файлы, devops, Docker, Nginx, Apache, maven, gradle, JUnit, YouTube, новости, руководство, ООП, алгоритмы, головоломки, rest, GraphQL, Excel, XML, json, yaml.
18.11.2024 23:52 devmark
Актуализировал статью про валидацию бинов в Spring Boot. Также для этой статьи создал репозиторий с примерами на github.
24.01.2025 12:46 Роман
Спасибо за материал