Form Validation in Spring Boot Web Application

Introduction

In this example we will see an example on how to validate form in web application using Spring Boot framework. We will use Thymeleaf as a template for UI (user interface) or front-end. We will perform almost all kinds of validations available through Hibernate validator framework.

This example just validates the input values and once validated successfully it just sends a success response to the end user or client. It does not perform any business on the server side.

We will build our application both on gradle and maven build tools.

Prerequisites

Spring Boot 2.2.2, Gradle 5.6, Maven 3.6.1, Eclipse 4.12, Java at least 8

Create Project

You can create either gradle based or maven based project in Eclipse. The name of the project is spring-boot-web-app-form-validation.

If you are creating gradle based project then you can use below build.gradle script:

buildscript {
	ext {
		springBootVersion = '2.2.2.RELEASE'
	}
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

plugins {
    id 'java-library'
    id 'org.springframework.boot' version '2.2.2.RELEASE'
}

sourceCompatibility = 12
targetCompatibility = 12

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
    implementation("org.springframework.boot:spring-boot-starter-thymeleaf:${springBootVersion}")
    implementation('org.hibernate:hibernate-validator:6.1.0.Final')
    implementation('org.apache.tomcat.embed:tomcat-embed-el:9.0.30')
}

If you are creating maven based project then you can use below pom.xml file:

<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>com.roytuts</groupId>
	<artifactId>spring-boot-web-app-form-validation</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.2.RELEASE</version>
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<version>6.1.0.Final</version>
		</dependency>
		
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-el</artifactId>
			<version>9.0.30</version>
		</dependency>
	</dependencies>

    <build>
        <plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.1</version>
				<configuration>
					<source>at least 8</source>
					<target>at least 8</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Hibernate Validator Annotations

@Digits(integer=, fraction=): annotated value is a number having up to integer digits and fractional digits upto fraction.

@Email: specified character sequence is a valid email address.

@Max(value=): annotated value is less than or equal to the specified maximum.

@Min(value=): annotated value is higher than or equal to the specified minimum

@NotBlank: annotated character sequence is not null and the trimmed length is greater than 0.

@NotEmpty: annotated element is not null nor empty.

@Null: annotated value is null

@NotNull: annotated value is not null

@Pattern(regex=, flags=): annotated string matches the regular expression regex considering the given flag match

@Size(min=, max=): annotated element’s size is between min and max (inclusive)

@Negative: element is strictly negative. Zero values are considered invalid.

@NegativeOrZero: element is negative or zero.

@Future: annotated date is in the future.

@FutureOrPresent: annotated date is in the present or in the future.

@PastOrPresent: annotated date is in the past or in the present.

VO or DTO Class

This is the Java class that will bind the input fields in a form on UI or front-end. We will apply different types of validations using hibernate validator framework.

package spring.boot.web.app.form.validation.dto;

import java.time.LocalDate;

import javax.validation.constraints.Digits;
import javax.validation.constraints.Email;
import javax.validation.constraints.Future;
import javax.validation.constraints.FutureOrPresent;
import javax.validation.constraints.Min;
import javax.validation.constraints.Negative;
import javax.validation.constraints.NegativeOrZero;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.PastOrPresent;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

import org.springframework.format.annotation.DateTimeFormat;

public class User {

	@Min(1)
	private int id;

	@Min(1)
	@Digits(integer = 2, fraction = 2)
	private double height;

	@NotEmpty
	@Size(min = 3, max = 45)
	private String name;

	@Email
	@NotBlank
	@Size(max = 150)
	private String email;

	@NotNull
	private String msg;

	@Pattern(regexp = "[a-zA-Z]")
	private String regex;

	@FutureOrPresent
	@DateTimeFormat(pattern = "yyyy-MM-dd")
	private LocalDate localDate;

	@PastOrPresent
	@DateTimeFormat(pattern = "yyyy-MM-dd")
	private LocalDate pastDate;

	@Future
	@DateTimeFormat(pattern = "yyyy-MM-dd")
	private LocalDate futureDate;

	@Negative
	private int negative;

	@NegativeOrZero
	private int negativeOrZero;

	// getters and setters

}

Web Controller

The Spring controller that handles request and response for the clients or end users.

We have http GET method to show the form to the clients.

We have http POST method for submitting the form values to the server and any validation failure will show next to the input field.

On success we return the success message as a response body.

package spring.boot.web.app.form.validation.controller;

import javax.validation.Valid;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import spring.boot.web.app.form.validation.dto.User;

@Controller
public class WebAppController {

	@GetMapping("/")
	public String showPage(User user) {
		return "form";
	}

	@PostMapping("/")
	public String validateUser(@Valid User user, BindingResult bindingResult) {
		if (bindingResult.hasErrors()) {
			return "form";
		}

		return "redirect:/success";
	}

	@ResponseBody
	@GetMapping("/success")
	public String success() {
		return "Your form was successfully validated!";
	}

}

UI – View File

Look at the below form how we bind the fields to the Java class attributes. We also show errors next to the input fields on validation failures.

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Spring Boot Web App Form Validation</title>
<style type="text/css">
#form {
	width: 500px;
	padding: 20px;
	margin: 50px auto;
	background: #fff;
	-webkit-border-radius: 2px;
	-moz-border-radius: 2px;
	border: 1px solid #000;
}
</style>
</head>
<body>
	<div id="form">
		<h2>Validate Form</h2>
		<form name='formValidation' th:action="@{/}" th:object="${user}"
			method='POST'>
			<table>
				<tr>
					<td>Id</td>
					<td><input type='text' th:field="*{id}"></td>
					<td th:if="${#fields.hasErrors('id')}" th:errors="*{id}">Id
						Error</td>
				</tr>
				<tr>
					<td>Height</td>
					<td><input type='text' th:field="*{height}"></td>
					<td th:if="${#fields.hasErrors('height')}" th:errors="*{height}">Height
						Error</td>
				</tr>
				<tr>
					<td>Name</td>
					<td><input type='text' th:field="*{name}" /></td>
					<td th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Name
						Error</td>
				</tr>
				<tr>
					<td>Email</td>
					<td><input type='text' th:field="*{email}" /></td>
					<td th:if="${#fields.hasErrors('email')}" th:errors="*{email}">Email
						Error</td>
				</tr>
				<tr>
					<td>Message</td>
					<td><input type='text' th:field="*{msg}" /></td>
					<td th:if="${#fields.hasErrors('msg')}" th:errors="*{msg}">Message
						Error</td>
				</tr>
				<tr>
					<td>Regular Expression</td>
					<td><input type='text' th:field="*{regex}" /></td>
					<td th:if="${#fields.hasErrors('regex')}" th:errors="*{regex}">Regex
						Error</td>
				</tr>
				<tr>
					<td>Future or Present Date</td>
					<td><input type='date' th:field="*{localDate}" /></td>
					<td th:if="${#fields.hasErrors('localDate')}"
						th:errors="*{localDate}">Future or Present Date Error</td>
				</tr>
				<tr>
					<td>Past or Present Date</td>
					<td><input type='date' th:field="*{pastDate}" /></td>
					<td th:if="${#fields.hasErrors('pastDate')}"
						th:errors="*{pastDate}">Past or Present Date Error</td>
				</tr>
				<tr>
					<td>Future Date</td>
					<td><input type='date' th:field="*{futureDate}" /></td>
					<td th:if="${#fields.hasErrors('futureDate')}"
						th:errors="*{futureDate}">Future Date Error</td>
				</tr>
				<tr>
					<td>Negative</td>
					<td><input type='text' th:field="*{negative}" /></td>
					<td th:if="${#fields.hasErrors('negative')}"
						th:errors="*{negative}">Negative Error</td>
				</tr>
				<tr>
					<td>Negative or Zero</td>
					<td><input type='text' th:field="*{negativeOrZero}" /></td>
					<td th:if="${#fields.hasErrors('negativeOrZero')}"
						th:errors="*{negativeOrZero}">Negative or Zero Error</td>
				</tr>
				<tr>
					<td colspan='11'><input name="submit" type="submit"
						value="Submit" /></td>
				</tr>
			</table>
		</form>
	</div>
</body>
</html>

Main Class

In spring boot applications a class with main method and @SpringBootApplication annotation are enough to deploy the application into embedded tomcat server.

package spring.boot.web.app.form.validation;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(scanBasePackages = "spring.boot.web.app.form.validation")
public class SpringBootWebAppFormValidationApp {

	public static void main(String[] args) {
		SpringApplication.run(SpringBootWebAppFormValidationApp.class, args);
	}

}

Testing the Application

Now executing the above main class will deploy the application into tomcat server and you can hit the URL http://local host:8080/ in the browser. The following page appears:

form validation in spring boot web application

If there is no validation failure then submitting the form will give you the following success message:

form validation in spring boot web application

Source Code

Download

Thanks for reading.

Leave a Reply

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