Выбрать главу

Классы, описанные на рис. 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 валидным адресом электронной почты.

Листинг 3.22. Компонент Customer со встроенными ограничениями и ограничением для электронной почты

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-кода (это ограничение будет разработано позже).

Листинг 3.23. Компонент Address со встроенными ограничениями и ограничением @ZipCode

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.

Листинг 3.24. Ограничивающая аннотация электронной почты со встроенной агрегацией ограничений

@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).