Классы, описанные на рис. 3.2, построены в соответствии со структурой каталогов Maven и должны находиться в следующих папках и файлах:
• src/main/java — папка для компонентов Customer, Address и ограничений ZipCode и Email;
Рис. 3.2. Все вместе
• src/main/resources — содержит файл beans.xml, поэтому мы можем использовать как CDI, так и файл ValidationMessages.properties для сообщений об ошибках, связанных с нарушением ограничений;
• src/test/java — папка для интеграционных тестов AddressIT и CustomerIT;
• pom.xml — объектная модель проекта Maven (POM), описывающая проект и его зависимости.
Написание компонента Customer
В приложении CD-Book Store клиент покупает товары, заказанные онлайн, и эти товары доставляются на его почтовый адрес. Для обеспечения такой доставки приложению нужна верная информация об имени клиента, адрес электронной почты и адрес доставки. Поскольку у нас есть дата рождения клиента, программа может ежегодно присылать ему соответствующее поздравление. В листинге 3.22 показан компонент Customer, включающий в себя несколько встроенных ограничений, налагаемых на атрибуты (firstname не может быть нулевым, а дата dateOfBirth должна относиться к прошлому). Здесь также есть ограничение @Email, которое мы разработаем. Код проверяет, является ли строка String валидным адресом электронной почты.
public class Customer {
··@NotNull @Size(min = 2)
··private String firstName;
··private String lastName;
··@Email
··private String email;
··private String phoneNumber;
··@Past
··private Date dateOfBirth;
··private Address deliveryAddress;
··// Конструкторы, геттеры, сеттеры
}
Написание компонента Address
У Customer может быть ноль или один адрес доставки. Address — это компонент, включающий всю информацию, необходимую для доставки товара по указанному адресу: улица, город, штат, ZIP-код и страна. В листинге 3.23 показан компонент Address с ограничением @NotNull, налагаемым на важнейшие атрибуты (street1, city и zipcode), а также с ограничением @ZipCode, проверяющим валидность ZIP-кода (это ограничение будет разработано позже).
public class Address {
··@NotNull
··private String street1;
··private String street2;
··@NotNull
··private String city;
··private String state;
··@NotNull @ZipCode
··private String zipcode;
··private String country;
··// Конструкторы, геттеры, сеттеры
}
Написание ограничения @Email
Ограничение @Email не встроено в систему валидации компонентов, поэтому нам самим придется его разработать. Нам не понадобится класс реализации (@Constraint(validatedBy = {})), так как вполне работоспособным будет обычная ограничивающая аннотация с регулярным выражением (@Pattern) и заданным размером. В листинге 3.24 показана ограничивающая аннотация @Email.
@Size(min = 7)
@Pattern(regexp = "[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\."
····+ "[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*"
····+ "@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?")
@ReportAsSingleViolation
@Constraint(validatedBy = {})
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
public @interface Email {
··String message() default " {org.agoncal.book.javaee7.chapter03.Email.message}";
··Class<?>[] groups() default {};
··Class<? extends Payload>[] payload() default {};
··@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
··@Retention(RUNTIME)
··@interface List {
····Email[] value();
··}
}
Обратите внимание: в листинге 3.24 сообщение об ошибке представляет собой ключ пакета, определяемый в файле META-INF/ValidationMessages.properties.
org.agoncal.book.javaee7.chapter03.Email.message=invalid email address
Написание ограничения @ZipCode
Ограничение @ZipCode написать сложнее, чем @Email. ZIP-код имеет определенный формат (например, в США он состоит из пяти цифр), который не составляет труда проверить с помощью регулярного выражения. Но чтобы гарантировать, что ZIP-код не только синтаксически верен, но и валиден, необходимо прибегнуть к внешней службе, которая будет проверять, существует ли конкретный ZIP-код в базе данных. Именно поэтому ограничивающая аннотация ZipCode в листинге 3.25 требует класса реализации (ZipCodeValidator).