Spring Boot Thymeleaf Form Validation Example

Validating the user inputs is one of the common tasks that the developer should implement during web application development. Validation may include checking the correct mobile number format, the minimum size of an input, etc.

In this post, we will learn how to validate the form data using spring boot thymeleaf and Bean validation API.

Version details:

  • Spring Boot version : 2.2.6.RELEASE
  • Java version 1.8

Table of Contents

Create Spring Boot application with required dependencies

Create a spring boot application with the required dependencies. Add spring-boot-starter-web, spring-boot-starter-thymeleaf, and the Lombok maven dependencies. We will use the Thymeleaf template engine in this example.

The spring-boot-starter-web dependency also contains the spring-boot-starter-validation starter dependency. This dependency contains the Bean validation API, we can use that for form validation in our example.

Below is the complete pom.xml file with the required dependencies.

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.asbnotebook</groupId>
    <artifactId>spring-boot-form-validation-thymeleaf</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-boot-form-validation-thymeleaf</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
        <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Add the Bean validation

Create a DTO class called Student. This class will hold the data entered on the thymeleaf form.

package com.asbnotebook.dto;

import java.time.LocalDate;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import org.springframework.format.annotation.DateTimeFormat;
import lombok.Data;

@Data
public class Student {

    @NotNull(message = "LastName can not be null!!")
    @NotEmpty(message = "LastName can not be empty!!")
    private String name;

    @NotNull(message = "Choose the subject count you are going to study!")
    @Min(value = 4, message = "Student should enroll to minimum 4 subjects!!")
    @Max(value = 8, message = "Student can enroll to maximum 8 subjects!!")
    private int subjectCount;

    @NotNull
    @Min(1)
    @Max(12)
    private int grade;

    @NotNull
    @Size(max = 10, min = 10, message = "Mobile number should be of 10 digits")
    @Pattern(regexp = "[7-9][0-9]{9}", message = "Mobile number is invalid!!")
    private String mobileNo;

    @NotNull(message = "Please enter birth date")
    @Past(message = "Birth date should be less than current date!!")
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
    private LocalDate birthDate;
}

We have used the javax.validation library to validate the fields. A few of the validation annotations used here are:

  • @NotNull: Ensures that the input field is not null.
  • @NotEmpty: Ensures that the field is not empty. It can be applied to fields of type String, collections, etc.
  • @Min: The entered number should be equal to or greater than the defined minimum value.
  • @Max: The entered number should be equal to or less than the defined maximum value.
  • @Pattern: This validation annotation can be used to match the input with the specified regex expression. We have used the phone number field to match the specified regex expression in our example.
  • @Size: To validate the size of the input character sequence, map, list, etc.
  • @Past: Makes sure that the input date/time is of the past.

Create a StudentController.java class. Add the following code to the created file.

package com.asbnotebook.controller;

import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import com.asbnotebook.dto.Student;

@Controller
public class StudentController {

    @GetMapping("/")
    public String getForm(Student student) {
        return "index";
    }

    @PostMapping("/save-student")
    public String submitStudentDetails(@Valid Student student, Errors errors, Model model) {
        if (null != errors && errors.getErrorCount() > 0) {
            return "index";
        } else {
            model.addAttribute("successMsg", "Details saved successfully!!");
            return "success";
        }
    }
}

Here, we have set index.html as the default landing page. As the thymeleaf starter dependency is available on the classpath, we need to make sure that all the template files are available under the src/main/resources/templates directory.

Also, The thymeleaf form will submit to the URL path /save-student. The user form data is submitted to this HTTP Post URL path.

The @Valid annotation denotes that the parameter should be validated.

We also have the Errors object that holds the validation error details, and if the error count is zero, we are redirecting the page to success.html and display the success message.

Create the Thymeleaf template pages

Create the index.html page under the directory /src/main/resources/templates/ of the project. We have used the bootstrap library to give a little nice look and feel to the page.

<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html xmlns:th="http://www.thymeleaf.org" >
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>Registration page</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
</head>
    <body>
        <div align="center" class="col-md-12">
            <h2>Welcome to Student registration page</h2>
            <div class="col-md-6">
                <form action="#" th:action="@{/save-student}" th:object="${student}" method="post">
                    <div class="form-group">
                        <label for="name">Name:</label> 
                        <input type="text" class="form-control" id="name" th:field="*{name}">
                        <p class="alert alert-danger" th:if="${#fields.hasErrors('name')}" th:errors="*{name}">
                    </div>
                    <div class="form-group">
                        <label for="subjectCount">Subjects Count:</label> 
                        <input type="number" class="form-control" id="subjectCount" th:field="*{subjectCount}">
                        <p class="alert alert-danger" th:if="${#fields.hasErrors('subjectCount')}" th:errors="*{subjectCount}" />
                    </div>
                    <div class="form-group">
                        <label for="grade">Grade:</label> 
                        <input type="number" class="form-control" id="grade" th:field="*{grade}" />
                        <p class="alert alert-danger" th:if="${#fields.hasErrors('grade')}" th:errors="*{grade}" />
                    </div>
                    <div class="form-group">
                        <label for="mobile">Mobile Number:</label> 
                        <input type="number" class="form-control" id="mobile" th:field="*{mobileNo}" />
                        <p class="alert alert-danger" th:if="${#fields.hasErrors('mobileNo')}" th:errors="*{mobileNo}" />
                    </div>
                    <div class="form-group">
                        <label for="bd">Birth Date:</label> 
                        <input type="date" class="form-control" id="bd" th:field="*{birthDate}" />
                        <p class="alert alert-danger" th:if="${#fields.hasErrors('birthDate')}" th:errors="*{birthDate}" />
                    </div>
                    <div class="form-group">
                        <button type="submit" class="btn btn-primary">Submit</button>
                    </div>
                </form>
            </div>
        </div>
    </body>
</html>

Create another success.html template page to display the success message.

<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html xmlns:th="http://www.thymeleaf.org" >
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>Registration page</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
</head>
<body>
    <div class="col-md-12" align="center">
        <br />
        <div class="alert alert-success col-md-8" role="alert">
            <p th:text="${successMsg}" />
        </div>
    </div>
</body>
</html>

Run the application

Start the spring boot application. We should be able to get the student registration form page at http://localhost:8080.

Click on the Submit button. We should be able to get the validation error messages, as shown below.

Spring boot thymeleaf validation example

Also, few more validation error for invalid data is shown below.

Spring boot thymeleaf validation example

Finally, Enter the valid data for all the fields.

Now we can submit the form successfully with a success message as shown below.

validation example spring boot thymeleaf

Conclusion

In conclusion, we learned the basic thymeleaf template form validation example with the spring boot. I hope you have enjoyed the post.

The example code is available on Github.

Spring Boot Thymeleaf Form Validation Example

2 thoughts on “Spring Boot Thymeleaf Form Validation Example

  1. Hello Sir,

    Thank you for posting the tutorial.
    I tried to use your code for understanding the validation and it worked as per your output except for @notnull and @notempty validation. These two do not work when submit button is clicked.

    Thus, please suggest some ways to resolve the issue.

    1. Hi Taruchit,

      Try using @NotBlank instead of @NotNull for String input fields to validate Null and blank space inputs.

Comments are closed.

Scroll to top

Discover more from ASB Notebook

Subscribe now to keep reading and get access to the full archive.

Continue reading