post-image

[Thực hành] Custom Validation

8. Validation

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

Leave a Reply

Your email address will not be published. Required fields are marked *