Bộ sưu tập

i18n trong Java Bean Validation


https://codersontrang.com/2014/04/19/i18n-trong-java-bean-validation/

Như trong bài viết “Giới thiệu về Java Bean Validation” ta đã biết cách để tạo ra và kiểm tra các ràng buộc về mặt dữ liệu cho một đối tượng trong java. Khi có những ràng buộc bị vi phạm, thì Bean Validation ném ra cho ta một tập các vi phạm này cùng với lời nhắn tương ứng. Từ đây xuất phát ra nhu cầu về khả năng hiển thị những lời nhắn trong những ngôn ngữ khác nhau. Bài viết này sẽ hướng dẫn cách thức để thực hiện đa ngôn ngữ trong Bean Validation.

Ví dụ của bài viết này sẽ là sự phát triển tiếp theo của ví dụ trong bài viết “Giới thiệu về Java Bean Validation“. Với ví dụ sẵn có, ta thêm một java package mới là validation.messageinterpolators, thêm một lớp có tên là LocaleAwareMessageInterpolator.java bên trong package này. Tiếp đến tạo một source folder có tên i18n và tạo hai file .propertiesValidationMessages.propertiesValidationMessages_vi_VN.properties bên trong.

Như vậy cấu trúc của Project sẽ giống như dưới đây trong cửa sổ của Eclipse IDE

codersontrang_beanvalidation_i18n_1

Student.java

 package validation.beans;  
 import java.util.Date;  
 import javax.validation.constraints.Min;  
 import javax.validation.constraints.NotNull;  
 import javax.validation.constraints.Past;  
 import javax.validation.constraints.Pattern;  
 import javax.validation.constraints.Size;  

 public class Student {  
      @NotNull(message="{name.is.notnull}")  
      @Size(min=3, max=20, message="{name.length.invalid}")  
      private String name;  

      @Min(value=18, message="{age.min.invalid}")  
      private int age;  

      @Pattern(regexp="^[0-9]{10,11}$", message="{phone.length.invalid}")  
      private String phone;  

      @Past(message="{firstday.past.invalid}")  
      private Date firstDayInSchool;   

      public Student(String name, int age, String phone, Date firstDayInSchool){  
           this.name = name;  
           this.age = age;  
           this.phone = phone;  
           this.firstDayInSchool = firstDayInSchool;  
      }  
 }  

Trong lớp Student.java, các lời nhắn trong ví dụ trước giờ đây được thay thế bằng các key. Việc ánh xạ từ các key này ra các lời nhắn sẽ được khai báo ở trong các file .properties. Mặc định, Java Bean Validation sẽ nhận các file có tên là ValidationMessages*.properties bên trong classpath để làm nơi thực hiện việc ánh xa nói trên. Phần "*" trong tên file ở trên để chỉ ra một ngôn ngữ cụ thể nào đó, và tùy thuộc vào loại ngôn ngữ mà chúng ta muốn hiển thị lời nhắn, Bean Validation sẽ lấy lời nhắn từ các file ánh xạ tương ứng.

Trong ví dụ, lời nhắn sẽ được lấy ra từ file ánh xạ ValidationMessages.properties là file ánh xạ mặc định khi mà ta không chỉ ra một ngôn ngữ cụ thể để hiển thị. Còn file ValidationMessages_vi_VN.properties là file ánh xạ được sử dụng khi mà ngôn ngữ chúng ta muốn hiển thị là “vi_VN“. Sự ánh xạ từ các key sang các lời nhắn sẽ thể hiện trong nội dung của hai file này như dưới đây:

ValidationMessages.properties

 name.is.notnull = Name is not null  
 name.length.invalid = Name length must be b/w 3 and 20  
 age.min.invalid = Age must be over 18  
 phone.length.invalid = Phone must be sequence of 10-11 digits  
 firstday.past.invalid = The first day in school must be in the past  

ValidationMessages_vi_VN.properties

 name.is.notnull = Ten khong duoc null  
 name.length.invalid = Do dai cua ten phai nam trong khoang 3 den 20  
 age.min.invalid = Tuoi phai it nhat la 18   
 phone.length.invalid = So dien thoai phai la mot chuoi co do dai tu 10-11 chu so  
 firstday.past.invalid = Ngay dau tien di hoc phai la ngay trong qua khu  

Việc chọn ra file ánh xạ .properties tương ứng với ngôn ngữ hiển thị được thực hiện qua một message interpolator như dưới đây:

LocaleAwareMessageInterpolator.java

 package validation.messageinterpolators;  
 import java.util.Locale;  
 import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;  

 public class LocaleAwareMessageInterpolator extends ResourceBundleMessageInterpolator{  
      private Locale locale = Locale.getDefault();  
      public void setLocale(Locale locale){  
           this.locale = locale;  
      }  

      @Override  
      public String interpolate(String message, Context context) {  
           return super.interpolate(message, context, locale);  
      }  
 }  

Trong ví dụ, ta tạo một lớp LocaleAwareMessageInterpolator kế thừa từ lớp ResourceBundleMessageInterpolator. Sau đó override lại phương thức interpolate() để lúc nào cũng đảm bảo rằng các lời nhắn được lấy ra từ đúng file ánh xạ tương ứng với locale mà ta truyền từ bên ngoài vào.

FieldValidationMain.java

 package validation.mains;  
 import java.text.ParseException;  
 import java.text.SimpleDateFormat;  
 import java.util.Locale;  
 import java.util.Set;  
 import javax.validation.Configuration;  
 import javax.validation.ConstraintViolation;  
 import javax.validation.Validation;  
 import javax.validation.Validator;  
 import javax.validation.ValidatorFactory;  
 import validation.beans.Student;  
 import validation.messageinterpolators.LocaleAwareMessageInterpolator;  

 public class FieldValidationMain {  
      public static void main(String [] args) throws ParseException{  
           Configuration<?> config = Validation.byDefaultProvider().configure();  

           LocaleAwareMessageInterpolator msgInterpolator = new LocaleAwareMessageInterpolator();  
           msgInterpolator.setLocale(new Locale("vi_VN"));  
           config.messageInterpolator(msgInterpolator);
  
           ValidatorFactory factory = config.buildValidatorFactory();  
           Validator validator = factory.getValidator();  
           SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd");  
           
           System.out.print("Validate student 1 info : ");  
           Student student1 = new Student("A", 15, "012345", formater.parse("2100-04-05"));  
           displayViolationsIfAny(validator.validate(student1));  
           
           System.out.print("\nValidate student 2 info : ");  
           Student student2 = new Student("ABC", 18, "0123456789", formater.parse("2014-01-01"));  
           displayViolationsIfAny(validator.validate(student2));  
      }  
      public static <T> void displayViolationsIfAny(Set<ConstraintViolation<T>> violations){  
           if(violations.isEmpty()){  
                System.out.println("Student information is valid");  
                return;  
           }  
           System.out.println("Student information is invalid");  
           for(ConstraintViolation<T> violation : violations){  
                System.out.println(" --- "+violation.getMessage());  
           }  
      }  
 }  

Trong phương thức main(), trước khi tạo ra một validator, ta cấu hình để validator nhận một message interpolator là một đối tượng thuộc kiểu LocaleAwareMessageInterpolator mà ta đã tạo ra ở trên. Và ta cũng chỉ ra ngôn ngữ hiển thị cho validator là “vi_VN“. Như vậy khi chạy chương trình, các lời nhắn từ các ràng buộc bị vi phạm sẽ được lấy ra từ file ánh xạ ValidationMessages_vi_VN.properties và hiển thị như hình dưới đây:

codersontrang_beanvalidation_i8n_2

Ngoài ra, Bean Validation còn hỗ trợ EL (expression language) trong nội dung của các lời nhắn. Ta sửa lại file ValidationMessages_vi_VN.properties như dưới đây:

ValidationMessages_vi_VN.properties

 name.is.notnull = Ten khong duoc null  
 name.length.invalid = Do dai cua ten phai nam trong khoang {min} den {max}  
 age.min.invalid = Tuoi phai it nhat la {value}. Hien tai la ${validatedValue}  
 phone.length.invalid = So dien thoai phai la mot chuoi co do dai tu 10-11 chu so  
 firstday.past.invalid = Ngay dau tien di hoc phai la ngay trong qua khu. Hien tai la ${formatter.format('%1$tm %1$te,%1$tY', validatedValue)}  
  • {min}, {max}, {value}: lấy ra giá trị của các thuộc tính trong các annotation sử dụng khi định nghĩa các ràng buộc. Ví dụ min, max ở đây là lấy ra từ annotation @Size(min=3, max=20, message="{name.length.invalid}"), value là lấy ra từ annotation @Min(value=18, message="{age.min.invalid}")
  • ${validatedValue}: là giá trị đang được kiểm tra xem có hợp lệ hay không. Trong ví dụ đây là giá trị của trường age trong đối tượng student1 và giá trị của nó là 15.
  • ${formatter.format('%1$tm %1$te,%1$tY', validatedValue)}: Chiếu theo bên trên thì validatedValue ở đây sẽ là giá trị của trường firstDayInSchool trong đối tượng student1. Bean Validation cung cấp đối tượng formatter với phương thức format() dùng để định dạng các giá trị được hiển thị ra trong nội dung lời nhắn. Đối tượng formatter này có kiểu là java.util.Formatter.

Bây giờ chạy lại chương trình, ta sẽ thấy các lời nhắn được hiển thị ra cùng với các thông tin lấy từ việc sử dụng EL sẽ như hình dưới đây:

codersontrang_beanvalidation_i8n_3

Good luck!

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất /  Thay đổi )

Google photo

Bạn đang bình luận bằng tài khoản Google Đăng xuất /  Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Đăng xuất /  Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất /  Thay đổi )

Connecting to %s