2.3.1 Khai báo các quy tắc xác thực
Đối với lớp Taco, bạn muốn đảm bảo rằng thuộc tính name không được rỗng hoặc null và danh sách các nguyên liệu được chọn phải có ít nhất một phần tử. Đoạn mã sau đây cho thấy một lớp Taco đã được cập nhật, sử dụng @NotNull và @Size để khai báo các quy tắc xác thực đó.
Listing 2.11 Thêm xác thực vào lớp domain Taco
package tacos;
import java.util.List;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import lombok.Data;
@Data
public class Taco {
@NotNull
@Size(min=5, message="Name must be at least 5 characters long")
private String name;
@NotNull
@Size(min=1, message="You must choose at least 1 ingredient")
private List<Ingredient> ingredients;
}Bạn sẽ thấy rằng ngoài việc yêu cầu thuộc tính name không được là null, bạn còn khai báo rằng nó phải có giá trị dài ít nhất năm ký tự.
Khi nói đến việc khai báo xác thực cho các đơn taco được gửi, bạn cần áp dụng các annotation vào lớp TacoOrder. Đối với các thuộc tính địa chỉ, bạn muốn đảm bảo rằng người dùng không để trống bất kỳ trường nào. Để làm điều đó, bạn sẽ sử dụng annotation @NotBlank.
Tuy nhiên, việc xác thực các trường thanh toán thì phức tạp hơn một chút. Bạn cần đảm bảo không chỉ rằng thuộc tính ccNumber không bị bỏ trống mà còn rằng nó chứa một giá trị có thể là số thẻ tín dụng hợp lệ. Thuộc tính ccExpiration phải tuân theo định dạng MM/YY (tháng và năm hai chữ số), và thuộc tính ccCVV cần phải là một số có đúng ba chữ số. Để đạt được các yêu cầu xác thực này, bạn sẽ cần sử dụng một vài annotation khác từ JavaBean Validation API và mượn thêm một annotation xác thực từ bộ sưu tập annotation của Hibernate Validator. Đoạn mã sau đây cho thấy các thay đổi cần thiết để xác thực lớp TacoOrder.
Listing 2.12 Xác thực các trường của đơn hàng
package tacos;
import javax.validation.constraints.Digits;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import org.hibernate.validator.constraints.CreditCardNumber;
import java.util.List;
import java.util.ArrayList;
import lombok.Data;
@Data
public class TacoOrder {
@NotBlank(message="Delivery name is required")
private String deliveryName;
@NotBlank(message="Street is required")
private String deliveryStreet;
@NotBlank(message="City is required")
private String deliveryCity;
@NotBlank(message="State is required")
private String deliveryState;
@NotBlank(message="Zip code is required")
private String deliveryZip;
@CreditCardNumber(message="Not a valid credit card number")
private String ccNumber;
@Pattern(regexp="^(0[1-9]|1[0-2])([\\/])([1-9][0-9])$",
message="Must be formatted MM/YY")
private String ccExpiration;
@Digits(integer=3, fraction=0, message="Invalid CVV")
private String ccCVV;
private List<Taco> tacos = new ArrayList<>();
public void addTaco(Taco taco) {
this.tacos.add(taco);
}
}Như bạn có thể thấy, thuộc tính ccNumber được chú thích bằng @CreditCardNumber. Annotation này khai báo rằng giá trị của thuộc tính phải là một số thẻ tín dụng hợp lệ, vượt qua được kiểm tra thuật toán Luhn (https://en.wikipedia.org/wiki/Luhn_algorithm). Điều này giúp ngăn ngừa lỗi người dùng và dữ liệu sai lệch cố ý, nhưng không đảm bảo rằng số thẻ tín dụng đó thực sự đã được cấp phát cho một tài khoản hoặc tài khoản đó có thể được sử dụng để thanh toán.
Thật không may, không có annotation sẵn có nào để xác thực định dạng MM/YY cho thuộc tính ccExpiration. Ở đây, tôi đã sử dụng annotation @Pattern, truyền vào một biểu thức chính quy (regex) để đảm bảo rằng giá trị của thuộc tính tuân theo định dạng mong muốn. Nếu bạn đang thắc mắc cách hiểu biểu thức chính quy đó, tôi khuyên bạn nên xem qua các hướng dẫn trực tuyến về biểu thức chính quy, chẳng hạn như http://www.regularexpressions.info/. Cú pháp regex khá phức tạp và chắc chắn nằm ngoài phạm vi của cuốn sách này.
Cuối cùng, chúng ta chú thích thuộc tính ccCVV bằng @Digits để đảm bảo rằng giá trị có đúng ba chữ số.
Tất cả các annotation xác thực đều có thuộc tính message để định nghĩa thông báo sẽ hiển thị cho người dùng nếu thông tin họ nhập không đáp ứng yêu cầu của các quy tắc xác thực đã khai báo.
