[Thực hành] Custom Validation
NỘI DUNG BÀI VIẾT
Mục tiêu
Luyện tập tạo các validator tuỳ biến.
Mô tả
Trong phần này, chúng ta phát triển một chức năng cho phép validate số điện thoại của người dùng.
Ứng dụng cho phép nhập vào số điện thoại và hiển thị thông báo tương ứng với giá trị của số điện thoại.
- Số điện thoại không được để trống
- Bắt đầu bằng số 0
- Có độ dài từ 10 -11 ký tự
- Chỉ bao gồm số
Để hoàn thành bài thực hành, học viên cần:
- Đưa mã nguồn lên GitHub
- Dán link của repository lên phần nộp bài trên CodeGymX
Hướng dẫn
Bước 1: Tạo project Gradle:

Bước 2: Thêm các depencies trong file buid.gradle:
compile group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0' compile group: 'org.springframework', name: 'spring-core', version: '4.3.17.RELEASE' compile group: 'org.springframework', name: 'spring-context', version: '4.3.17.RELEASE' compile group: 'org.springframework', name: 'spring-beans', version: '4.3.17.RELEASE' compile group: 'org.springframework', name: 'spring-web', version: '4.3.17.RELEASE' compile group: 'org.springframework', name: 'spring-webmvc', version: '4.3.17.RELEASE' compile group: 'org.thymeleaf', name: 'thymeleaf-spring4', version: '3.0.4.RELEASE' compile group: 'javax.validation', name: 'validation-api', version: '2.0.1.Final' compile group: 'org.hibernate', name: 'hibernate-validator', version: '6.0.10.Final'
Bước 3: Tạo cấu trúc thư mục trong thư mục src như sau:
Bước 4: Cấu hình cho Project:
4.1. Tạo class ApplicationInitializer trong thư mục com.codegym:
package com.codegym; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class ApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[]{ApplicationConfig.class}; } @Override protected Class<?>[] getServletConfigClasses() { return new Class[0]; } @Override protected String[] getServletMappings() { return new String[]{"/"}; } }
4.2. Tạo class ApplicationConfig để cấu hình Thymeleaf và view:
package com.codegym; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.ResourceBundleMessageSource; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.thymeleaf.TemplateEngine; import org.thymeleaf.spring4.SpringTemplateEngine; import org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver; import org.thymeleaf.spring4.view.ThymeleafViewResolver; import org.thymeleaf.templatemode.TemplateMode; @Configuration @EnableWebMvc @ComponentScan("com.codegym") public class ApplicationConfig extends WebMvcConfigurerAdapter implements ApplicationContextAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } //Thymeleaf Configuration @Bean public SpringResourceTemplateResolver templateResolver() { SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); templateResolver.setApplicationContext(applicationContext); templateResolver.setPrefix("/WEB-INF/views/"); templateResolver.setSuffix(".html"); templateResolver.setTemplateMode(TemplateMode.HTML); return templateResolver; } @Bean public TemplateEngine templateEngine() { TemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(templateResolver()); return templateEngine; } @Bean public ThymeleafViewResolver viewResolver() { ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); viewResolver.setTemplateEngine(templateEngine()); return viewResolver; } }
Bước 5: Tạo Class PhoneNumber với nội dung như sau:
Trong đó:
– supports là phương thức xác định class này được Validate
– validate(Object target, Errors errors) là phương thức dùng để xác minh cho đối tượng và trả về lỗi trong errors nếu có
package com.codegym.model; import org.springframework.stereotype.Component; import org.springframework.validation.Errors; import org.springframework.validation.ValidationUtils; import org.springframework.validation.Validator; @Component public class PhoneNumber implements Validator { private String number; public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } @Override public boolean supports(Class<?> clazz) { return PhoneNumber.class.isAssignableFrom(clazz); } @Override public void validate(Object target, Errors errors) { PhoneNumber phoneNumber = (PhoneNumber) target; String number = phoneNumber.getNumber(); ValidationUtils.rejectIfEmpty(errors, "number", "number.empty"); if (number.length()>11 || number.length()<10){ errors.rejectValue("number", "number.length"); } if (!number.startsWith("0")){ errors.rejectValue("number", "number.startsWith"); } if (!number.matches("(^$|[0-9]*$)")){ errors.rejectValue("number", "number.matches"); } } }
Bước 6: Thêm cấu hình file ghi lỗi cho class PhoneNumber trong file AppConfiguration
@Bean public MessageSource messageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); messageSource.setBasenames("ValidationMessages"); return messageSource; }
Bước 7: Thêm nội dung file ValidationMessages.properties
number.empty = phonemunber not empty. number.startsWith = phonenumber start with 0. number.length = length form 10 to 11. number.matches = phonenumber only include number.
Bước 8: Tạo Controller PhoneController với nội dung như sau:
package com.codegym.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; import com.codegym.model.PhoneNumber; import javax.validation.Valid; @Controller public class PhoneController { @GetMapping("/") public String showForm(Model model){ model.addAttribute("phonemunber", new PhoneNumber()); return "index"; } @PostMapping("/") public String checkValidation (@Valid @ModelAttribute("phonemunber")PhoneNumber phoneNumber, BindingResult bindingResult, Model model){ new PhoneNumber().validate(phoneNumber, bindingResult); if (bindingResult.hasFieldErrors()){ return "index"; } else { model.addAttribute("phoneNumber", phoneNumber.getNumber()); return "result"; } } }
Bước 9: Tạo view index
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>Input PhoneNumber</title> </head> <body> <form action="#" th:action="@{/}" th:object="${phonemunber}" method="POST"> <table> <tr> <td>PhoneNumber</td> <td><input type="text" th:field="*{number}"/></td> <td th:if="${#fields.hasErrors('number')}" th:errors="*{number}">Name Error</td> </tr> </table> <button type="submit">submit</button> </form> </body> </html>
Bước 10: Tạo view result
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>PhoneNumber</title> </head> <body> <h1>Your phone <span th:text="${phonemunber.number}"></span></h1> </body> </html>
Bước 11: Cấu hình Tomcat và artifacts và chạy ứng dụng
11.1. Không nhập SĐT nhấn submit

11.2. Nhập ký tự
Tương tự với các trường hợp nhập số điện thoại sai quy tắc khác.
Trong trường hợp nhập SĐT đúng

Tham khảo thêm tại đây: https://github.com/codegym-vn/java-spring-validate-phonenumber
Trả lời