Spring MVC – Phần 7: Form validation, Code ví dụ validate form trong Spring MVC

Spring MVC – Phần 7: Form validation, Code ví dụ validate form trong Spring MVC

Spring hỗ trợ validate các field/thuộc tính khi submit form bằng cách sử dụng các annotation validate của hibernate-validator, javax-validation.

Trong bài này mình sẽ hướng dẫn thực hiện một ví dụ validate 1 form submit với các thuộc tính có nhiều kiểu dữ liệu khác nhau, cách tạo 1 annotation validate.

Form validation, Code ví dụ validate form trong Spring MVC

1. Cấu trúc Project ví dụ:

Spring MVC - Phần 7: Form validation, Code ví dụ validate form trong Spring MVC

2. Code ví dụ

Thư viện sử dụng:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>stackjava.com</groupId>
  <artifactId>SpringFormValidation</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>

  <properties>
    <spring.version>5.0.2.RELEASE</spring.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>javax.validation</groupId>
      <artifactId>validation-api</artifactId>
      <version>1.1.0.Final</version>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>5.4.2.Final</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
  </dependencies>
</project>

Hai thư viện validation-api và hibernate-validator cung cấp các annotation định nghĩa cho việc validate

File Spring Config

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
  xmlns:mvc="http://www.springframework.org/schema/mvc"
  xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

  <!-- Enables the Spring MVC @Controller programming model -->
  <mvc:annotation-driven />
  <context:component-scan base-package="stackjava.com.springmvchello" />

  <bean
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix">
      <value>/WEB-INF/views/jsp/</value>
    </property>
    <property name="suffix">
      <value>.jsp</value>
    </property>
  </bean>

  <bean id="messageSource"
    class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basename" value="/i18n/message" />
  </bean>

</beans>

(*Lưu ý: bắt buộc dùng <mvc:annotation-driven /> để xử lý các annotation @Valid, @Validate cho controller)

File entity:

public class User {

  @NotNull(message = "Id may not be null")
  private Integer id;

  @NotBlank
  @Length(min = 5, max = 10)
  private String name;

  @NotBlank
  @Email
  private String email;

  @NotNull
  @DateTimeFormat(pattern = "dd/MM/yyyy")
  @Past
  private Date dateOfBirth;

  @Phone(message = "Phone Number is invalid")
  private String phoneNumber;

  // getter/setter
}

Các annotation khai báo trước các field sẽ định nghĩa ràng buộc cho các field đó.

Mặc định các message lỗi sẽ được lấy từ file .properties, nếu không tìm thấy thì nó sẽ thấy theo các message khai báo bên cạnh annotation, nếu không tìm thấy cả 2 chỗ trên thì nó sẽ thấy message mặc định của hibernate-validator và validation-api.

Ví dụ:

  • field name không được để trống và chiều dài từ 5-10 ký tự
  • field dateOfBirth: không được null, có định dạng là dd/MM/yyyy và phải trước ngày hiện tại

Một số annotation validate khác hay dùng như @Size, @Future, @Pattern… Annotation @Phone là do mình tự định nghĩa:

Ở đây mình định nghĩa số điện thoại có định dạng là số và chiều dài là 10 ký tự.

@Documented
@Constraint(validatedBy = PhoneValidator.class)
@Retention(RUNTIME)
@Target({ FIELD, METHOD })
public @interface Phone {
  String message() default "{Phone}";

  Class<?>[] groups() default {};

  Class<? extends Payload>[] payload() default {};
}
public class PhoneValidator implements ConstraintValidator<Phone, String> {

  public void initialize(Phone paramA) {
  }

  public boolean isValid(String phoneNo, ConstraintValidatorContext ctx) {
    if (phoneNo == null) {
      return false;
    }
    return phoneNo.matches("\\d{10}");
  }

}

Controller:

@Controller
public class UserController {

  @RequestMapping(value = "/addUser", method = RequestMethod.GET)
  public String doGetAddUser(Model model) {
    if (!model.containsAttribute("user")) {
      model.addAttribute("user", new User());
    }
    return "add-user";
  }

  @RequestMapping(value = "/addUser", method = RequestMethod.POST)
  public String doPostAddUser(@ModelAttribute("user") @Valid User user, BindingResult result) {
    if (result.hasErrors()) {
      return "add-user";
    }
    return "view-user";
  }

}

*Lưu ý: Trong method của controller, BindingResult phải nằm ngay sau đối tượng được validate.

Bạn có thể dùng annotation @Valid (javax.validation.valid) hoặc @Validate (org.springframework.validation.annotation.validate) đều được.

File jsp hiển thị:

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<style>
  .error {
    color: red;
  }
</style>
</head>

<body>
  <h2>add-user.jsp</h2>
  <form:form action="addUser" method="POST" modelAttribute="user">
    Id: <form:input path="id"/> <form:errors path="id" cssClass="error"/> <br/><br/>
    Name: <form:input path="name"/> <form:errors path="name" cssClass="error"/> <br/><br/>
    Email: <form:input path="email"/> <form:errors path="email" cssClass="error"/> <br/><br/>
    Phone Number: <form:input path="phoneNumber"/> <form:errors path="phoneNumber" cssClass="error"/> <br/><br/>
    Date Of Birth: <form:input path="dateOfBirth"/> <form:errors path="dateOfBirth" cssClass="error"/> <br/>
     <button type="submit">Submit</button>
  </form:form>
</body>
</html>
<%@ taglib prefix = "fmt" uri = "http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
<title>Spring MVC Form Validation</title>
</head>

<body>
  <h2>add-user.jsp</h2>
    Id: ${user.id} <br/>
    Name: ${user.name}<br/>
    Email: ${user.email }<br/>
    Phone Number: ${user.phoneNumber }<br/>
    Date Of Birth: <fmt:formatDate pattern = "dd/MM/yyyy" value = "${user.dateOfBirth}"/>
</body>
</html>

File message:

## Chỉ rõ message lỗi cho đối tượng
NotNull.user.id=Id can not be null
NotBlank.user.name=Name can not be empty
NotBlank.user.email=Email can not be null
NotNull.user.dateOfBirth=Date of birth can not be null
Past.user.dateOfBirth=Must be in the past
Email.user.email=Email is wrong format

## Message lỗi chung cho Annotation
##NotNull=Not null
##NotBlank=Not Blank
##Email=Email is wrong format
##Past=Must be in the Past

# Message lỗi cho customer annotation
Phone=Phone number is not valid

Form validation, Code ví dụ validate form trong Spring MVC

Demo:

Trường hợp các giá trị nhập vào sai định dạng/ để trống

Trường hợp các field nhập vào hợp lệ

 

Okay Done!

Download code ví dụ trên tại đây

References:

https://spring.io/guides/gs/validating-form-input/

https://docs.spring.io/spring/docs/4.1.x/spring-framework-reference/html/validation.html

stackjava.com