Java API Specification (JSR303) định nghĩa các tiêu chuẩn kiểm tra Bean, nhưng không cung cấp triển khai. Hibernate Validation là một triển khai của tiêu chuẩn này và bổ sung các chú thích kiểm tra như @Email, @Length, v.v. Spring Validation là một lớp bọc thứ hai của Hibernate Validation, được sử dụng để hỗ trợ kiểm tra tự động các tham số trong Spring MVC.
Bắt đầu nhanh
Thêm phụ thuộc
Nếu phiên bản Spring Boot nhỏ hơn 2.3.x, spring-boot-starter-web sẽ tự động thêm phụ thuộc hibernate-validator. Nếu phiên bản Spring Boot lớn hơn 2.3.x, bạn cần thêm phụ thuộc thủ công:
Đối với dịch vụ web, để tránh ảnh hưởng của các tham số không hợp lệ đến kinh doanh, bạn nên luôn thực hiện kiểm tra tham số trong lớp Controller! Trong hầu hết các trường hợp, tham số yêu cầu có hai dạng như sau:
Yêu cầu POST, PUT, sử dụng requestBody để truyền tham số;
Yêu cầu GET, sử dụng requestParam/PathVariable để truyền tham số.
Thực tế, cho dù là kiểm tra tham số requestBody hay kiểm tra cấp độ phương thức, cuối cùng đều gọi Hibernate Validator để thực hiện kiểm tra, Spring Validation chỉ là một lớp bọc.
Ví dụ về kiểm tra
(1) Đánh dấu chú thích kiểm tra trên đối tượng
(2) Khai báo chú thích kiểm tra trên tham số phương thức
(3) Nếu tham số yêu cầu không đáp ứng các quy tắc kiểm tra, sẽ ném ra ngoại lệ ConstraintViolationException hoặc MethodArgumentNotValidException.
Xử lý ngoại lệ thống nhất
Trong quá trình phát triển dự án thực tế, thường sẽ sử dụng xử lý ngoại lệ thống nhất để trả về một thông báo thân thiện hơn.
Sử dụng nâng cao
Kiểm tra theo nhóm
Trong dự án thực tế, có thể có nhiều phương thức sử dụng cùng một lớp DTO để nhận tham số, nhưng các quy tắc kiểm tra có thể khác nhau. Trong trường hợp này, việc đơn giản chỉ thêm chú thích kiểm tra trên trường của lớp DTO không thể giải quyết vấn đề này. Do đó, spring-validation hỗ trợ tính năng kiểm tra theo nhóm, được sử dụng đặc biệt để giải quyết vấn đề này.
(1) Định nghĩa các nhóm
(2) Đánh dấu chú thích kiểm tra trên đối tượng
(3) Kiểm tra theo nhóm trong phương thức
Kiểm tra lồng nhau
Trong các ví dụ trước, các trường trong lớp DTO đều là kiểu dữ liệu cơ bản và kiểu String. Tuy nhiên, trong thực tế, có thể có một trường là một đối tượng, trong trường hợp này, chúng ta có thể sử dụng kiểm tra lồng nhau.
Ví dụ, khi lưu thông tin User, cùng với đó còn có thông tin Job. Lưu ý rằng trường tương ứng trong lớp DTO phải được đánh dấu bằng chú thích @Valid.
Kiểm tra lồng nhau có thể kết hợp với kiểm tra theo nhóm. Ngoài ra, kiểm tra lồng nhau cũng sẽ kiểm tra từng phần tử trong tập hợp, ví dụ như trường List<Job> sẽ kiểm tra từng đối tượng Job trong danh sách.
Tạo chú thích kiểm tra tùy chỉnh
(1) Tạo chú thích kiểm tra tùy chỉnh @IsMobile
(2) Triển khai giao diện ConstraintValidator, viết trình phân tích cho chú thích kiểm tra @IsMobile
Tùy chỉnh kiểm tra
Có thể tạo kiểm tra tùy chỉnh bằng cách triển khai giao diện org.springframework.validation.Validator.
Có các điểm sau:
Triển khai phương thức supports
Triển khai phương thức validate
Sử dụng đối tượng Errors để thu thập lỗi
ObjectError: Lỗi của đối tượng (Bean)
FieldError: Lỗi của thuộc tính (Property) của đối tượng (Bean)
Sử dụng ObjectError và FieldError để liên kết với MessageSource để lấy thông báo lỗi cuối cùng
Chế độ thất bại nhanh (Fail Fast)
Mặc định, Spring Validation sẽ kiểm tra tất cả các trường và sau đó mới ném ra ngoại lệ. Bạn có thể bật chế độ Fail Fast bằng cách cấu hình đơn giản, trong đó nếu kiểm tra thất bại, nó sẽ ngay lập tức trả về kết quả.
Nguyên lý của Spring Validation
Các tình huống sử dụng Spring Validation
Kiểm tra thông thường của Spring (Validator)
Ràng buộc dữ liệu của Spring (DataBinder)
Ràng buộc tham số của Spring Web (WebDataBinder)
Kiểm tra tham số phương thức trong Spring WebMVC/WebFlux
Thiết kế giao diện Validator
Trách nhiệm giao diện
Giao diện kiểm tra nội bộ của Spring, kiểm tra đối tượng mục tiêu bằng cách lập trình
Phương thức chính
supports(Class): Kiểm tra xem lớp mục tiêu có thể được kiểm tra hay không
validate(Object, Errors): Kiểm tra đối tượng mục tiêu và đưa ra thông báo lỗi vào đối tượng Errors
Các thành phần đi kèm
Bộ thu thập lỗi: org.springframework.validation.Errors
Mô tả lỗi thuộc tính Java Bean: org.springframework.validation.FieldError
Nguồn thông tin lỗi của Errors
Các bước tạo thông tin lỗi
Chọn giao diện Errors (ví dụ: org.springframework.validation.BeanPropertyBindingResult)
Gọi phương thức reject hoặc rejectValue
Lấy đối tượng ObjectError hoặc FieldError từ đối tượng Errors
Liên kết code và args trong ObjectError hoặc FieldError với giao diện MessageSource (ví dụ: ResourceBundleMessageSource)
Nguyên lý thực hiện kiểm tra trong Spring Web
Cơ chế thực hiện kiểm tra tham số RequestBody
Trong Spring MVC, RequestResponseBodyMethodProcessor được sử dụng để phân tích các tham số được đánh dấu bằng @RequestBody và xử lý giá trị trả về của các phương thức được đánh dấu bằng @ResponseBody. Trong đó, logic thực hiện kiểm tra tham số nằm trong phương thức resolveArgument():
Có thể thấy, resolveArgument() gọi hàm validateIfApplicable() để thực hiện kiểm tra tham số.
Đoạn mã trên giải thích lý do tại sao Spring có thể hỗ trợ cùng lúc hai chú thích @Validated và @Valid.
Tiếp theo, xem xét cài đặt của WebDataBinder.validate():
Từ đoạn mã trên, có thể thấy rằng Spring thực tế là đóng gói dựa trên Hibernate Validator để thực hiện kiểm tra.
Cơ chế thực hiện kiểm tra tham số cấp phương thức
Spring hỗ trợ việc chặn và kiểm tra dựa trên phương thức bằng cách sử dụng công nghệ AOP. Cụ thể, nó sử dụng MethodValidationPostProcessor để đăng ký động một khía cạnh AOP, sau đó sử dụng MethodValidationInterceptor để tăng cường các phương thức điểm cắt.
Tiếp theo, xem xét MethodValidationInterceptor:
Thực tế, cho dù là kiểm tra tham số RequestBody hay kiểm tra cấp phương thức, cuối cùng đều sử dụng Hibernate Validator để thực hiện kiểm tra, và Spring Validation chỉ là một lớp bao bọc.
Câu hỏi
Spring có những thành phần chính nào trong việc kiểm tra dữ liệu?