Spring Validation — custom constraint validator

Если вы используете Spring Validation, то вы скоро поймёте, что аннотаций @Size, @NotNull и прочих вам не хватает. Вы, разумеется, можете написать свой наследник класса org.springframework.validation.Validator, но так не хочется терять красоту и лаконичность аннотаций.

К счастью, Spring Framework позволяет расширять имеющиеся аннотации для проверки значений своими собственными, самописными. В этой статье я приведу пример создания подобной аннотации. Более того, наша аннотация будет обращаться к бину из слоя сервисов при проверке значения. Подобную технику можно использовать, например, для проверки уникальности введённых пользователем значений по какому-нибудь полю.

Предположим, что нам нужно проверить следующий класс:

Большую часть проверок мы уже сделали аннотациями, но осталось ещё кое-что. Вполне ожидаемо, что заказчик захочет сделать проверку уникальности ИНН. В данном случае существующими стандартными аннотациями из javax.validation не обойдёшься, более того, нам нужно обращаться к базе данных для проверки существования записи с введённым ИНН. В таком случае нам нужно написать свою аннотацию. Делается это так:

Обратить внимание нужно на следующее:

  • @Constraint(validatedBy = здесь указывается сам класс, который будет осуществлять проверку в соответствии с нашей новой аннотацией.
  • String message() — здесь мы указываем сообщение об ошибке по умолчанию.
  • groups() и  payload() в данном случае не пригодятся, поэтому они пустые.

В классе UniqueItnConstraintValidator осуществляется сама проверка:

На что обратить внимание:

  • Наследуемся от javax.validation.ConstraintValidator 
  • Внедряем свой бин PersonService, к которому обращаемся для проверки существования записи с таким ИНН.
  • Отключаем обработку по умолчанию с помощью disableDefaultConstraintViolation().
  • Формируем свою информацию об ошибке валидации с указанием поля “itn” и кода сообщения об ошибке в фигурных скобках "{ru.urvanov.javaexamples.customconstraintvalidator.validation.unique.itn}".
  • Возвращаем false.
  • Если бы мы просто вернули false без отключения стандартного поведения и создания своей ошибки с указанием поля, то ошибка относилась бы ко всему типу Person, а не к конкретному его полю.

Само сообщение для кода ru.urvanov.javaexamples.customconstraintvalidator.validation.unique.itn хранится в файле “src/main/resources/ValidationMessages.properties” (а локализованные версии в файлах “src/main/resources/ValidationMessages_ru_RU.properties” и аналогичных):

Созданную аннотацию указываем для всего класса Person:

Наш контекст Spring-а:

Главный класс приложения, в котором мы инициализируем контекст Spring-а и запускаем проверку для экземпляра Person:

В нашем примере мы получаем множество Set<ConstraintViolation<Person>>, но при ошибках маппинга в контроллерах Spring MVC мы будем получать результат BindingResult!

Файл “pom.xml” с зависимостями:

При запуске метода  main из “App.java” в консоль будет выведено следующее:

Ссылки:

ZIP-архив с исходными кодами проекта

Репозиторий на GitHub

Буду рад любым комментариям!

 


Поделиться:

Добавить комментарий

Ваш e-mail не будет опубликован.

*