В прошлом уроке я показал, как проверять форму с помощью аннотаций . Это прекрасно работает для простых проверок, но в конечном итоге вам нужно будет проверить некоторые пользовательские правила, которые недоступны в готовых аннотациях. Например, что если вам нужно подтвердить, что пользователю более 21 года, рассчитано на основе его входной даты рождения, или, возможно, вам нужно подтвердить, что код телефонного номера пользователя находится в штате Небраска, США. Этот учебник с полным исходным кодом покажет, как создавать пользовательские аннотации проверки, которые вы можете использовать вместе с аннотациями JSR-303 и Hibernate Validator, которые мы исследовали в предыдущем уроке.
Вы можете взять код для этого урока на GitHub, если хотите следовать.
Для этого примера, скажем, у нас есть форма с полем номера телефона и полем даты рождения, и мы хотим проверить, действителен ли номер телефона (простая проверка формата) и что пользователь родился в 1989 году. встроенные аннотации (насколько я знаю), поэтому мы напишем пользовательские аннотации проверки, которые затем сможем использовать, как и встроенные JSR-303.
Когда мы закончим, мы применим наши аннотации к нашему объекту формы, например так:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
public class Subscriber { ... @Phone private String phone; @Year ( 1989 ) private Date birthday; // getters setters ... } |
Давайте начнем с аннотации @Phone. Мы будем создавать два класса: Phone
, который является аннотацией, и PhoneConstraintValidator
который содержит логику проверки. Первым шагом является создание класса аннотации Phone
:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
@Documented @Constraint (validatedBy = PhoneConstraintValidator. class ) @Target ( { ElementType.METHOD, ElementType.FIELD }) @Retention (RetentionPolicy.RUNTIME) public @interface Phone { String message() default "{Phone}" ; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; } |
Приведенный выше код в основном просто котельная. Три метода в аннотации требуются спецификацией JSR-303. Если бы наша аннотация принимала какие-либо аргументы, мы бы определили их там как методы. Мы увидим это в нашей следующей аннотации позже в этом уроке. Самая важная часть класса выше — это аннотация @Constraint
для класса, которая указывает, что мы будем использовать наш класс PhoneConstraintValidator
для логики проверки. Метод message()
определяет способ разрешения сообщения. Указав «{Phone}», мы можем переопределить сообщение в комплекте ресурсов Spring с помощью клавиши « Phone
(подробности о сообщениях см. В моем другом учебнике по проверке ).
Теперь мы определим валидатор ограничения:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
public class PhoneConstraintValidator implements ConstraintValidator<Phone, String> { @Override public void initialize(Phone phone) { } @Override public boolean isValid(String phoneField, ConstraintValidatorContext cxt) { if (phoneField == null ) { return false ; } return phoneField.matches( "[0-9()-\.]*" ); } } |
Давайте посмотрим на приведенный выше код. Шаблонный тип суперкласса принимает два типа: тип аннотации, которую он поддерживает, и тип проверяемого свойства (в этом примере Phone, String).
Метод «initialize» здесь пуст, но его можно использовать для сохранения данных из аннотации, как мы увидим ниже, когда мы определим нашу другую аннотацию.
Наконец, фактическая логика происходит в методе «isValid». Значение поля передается в качестве первого аргумента, и мы делаем нашу проверку здесь. Как видите, я только проверяю, что номер телефона содержит только цифры, скобки или тире.
Вот именно для этой аннотации! Теперь аннотацию можно использовать для поля, как показано выше для нашего объекта формы.
Теперь давайте сделаем нашу вторую аннотацию. Это немного надумано — мы проверим, что дата рождения пользователя — 1989. В будущем нам может понадобиться проверить даты в других годах, но вместо того, чтобы создавать аннотацию, которая подтверждает год 1989, мы позволит ему принять аргумент, чтобы указать год для проверки. Пример использования:
1
2
|
@Year ( 1989 ) private Date birthDate; |
Теперь аннотация:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
@Documented @Constraint (validatedBy = YearConstraintValidator. class ) @Target ( { ElementType.METHOD, ElementType.FIELD }) @Retention (RetentionPolicy.RUNTIME) public @interface Year { int value(); String message() default "{Year}" ; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; } |
Обратите внимание на метод value (). Это раскрывает аргумент «значение» аннотации, который мы будем использовать для прохождения года, в котором аннотация должна проверяться. Остальная часть кода в основном шаблонная
Теперь валидатор ограничений:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
public class YearConstraintValidator implements ConstraintValidator<Year, Date> { private int annotationYear; @Override public void initialize(Year year) { this .annotationYear = year.value(); } @Override public boolean isValid(Date target, ConstraintValidatorContext cxt) { if (target == null ) { return true ; } Calendar c = Calendar.getInstance(); c.setTime(target); int fieldYear = c.get(Calendar.YEAR); return fieldYear == annotationYear; } } |
Первое, на что нужно обратить внимание, это то, что на этот раз мы сохраняем год, переданный в аннотацию, как переменную-член класса валидатора ограничений. Это позволяет нам получить доступ к значению в нашем методе «isValid».
Метод isValid довольно прост для борьбы с отвратительным API Date / Calendar, чтобы проверить, что значение аннотированного поля совпадает с годом, в котором указана аннотация проверки (я могу опубликовать пример, используя JodaTime, когда-нибудь, когда смогу обойти это). И теперь, если мы запустим наше веб-приложение, наши две проверки уже готовы и будут использованы!
Это все. Я что-то пропустил? Есть вопросы? Дай мне знать в комментариях.
Полный источник: ZIP , GitHub
Чтобы запустить код из этого руководства: необходимо установить Gradle . Клонируйте репозиторий GitHub или загрузите ZIP-архив и распакуйте его. Откройте командную строку для определения местоположения кода. Запустите gradle jettyRunWar. Перейдите в браузере по адресу http: // localhost: 8080.