17 ноября 2024
Тэги: 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, Linux, Hibernate, Collections, Stream API, многопоточность, файлы, Nginx, Apache, maven, gradle, JUnit, YouTube, новости, руководство, ООП, алгоритмы, головоломки, rest, GraphQL, Excel, XML, json, yaml.
18.11.2024 23:52 devmark
Актуализировал статью про валидацию бинов в Spring Boot. Также для этой статьи создал репозиторий с примерами на github.