Spring MVC Form Validation using Annotations - Hibernate Validator


In this tutorial, we're going to learn how to perform form validation in the Spring MVC web application using Java bean validation annotations.
Note that we don't use Spring boot, we use plain Spring MVC libraries in this tutorial. If you want to use Spring boot then check out Spring boot tutorials at https://www.javaguides.net/p/spring-boot-tutorial.html
So, what's the need for validation? Well, you may have a form and you may want to validate the fields to make sure you have required fields, numbers in a given range, validate the format, for example, for a postal code or you may want to add your own custom business rule for validation, etc.
In this tutorial, we will use Hibernate validator library which is the implementation of Java's standard Bean Validation API.
Before you get started, check out Spring Data JPA Tutorial and Spring MVC Tutorial

    Spring MVC Tutorials and Articles

Now, let's talk about Spring support for validation. So, Spring version 4 and higher supports the Bean Validation API which is a good thing. So, it's actually the preferred method for validation when building Spring apps.

Important Java bean validations

  • @NotNull validates that the annotated property value is not null.
  • @Size validates that the annotated property value has a size between the attributes min and max; can be applied to String, Collection, Map, and array properties.
  • @Min validates that the annotated property has a value not smaller than the value attribute.
  • @Max validates that the annotated property has a value no larger than the value attribute.
  • @Email validates that the annotated property is a valid email address.
  • @NotEmpty validates that the property is not null or empty; can be applied to String, Collection, Map, or Array values.
  • @NotBlank can be applied only to text values and validates that the property is not null or whitespace.
These all are built-in validation rules but we can also create our own custom validation rule along with our own custom Java annotation.
In this example, we will use a Java-based configuration that is we configure the Spring Dispatcher Servlet and spring beans configuration using all Java Code (no XML).

Tools and technologies used

  • Spring MVC - 5.1.0 RELEASE
  • JDK - 1.8 or later
  • Maven - 3.5.1
  • Apache Tomcat - 8.5
  • IDE - STS/Eclipse Neon.3
  • JSTL - 1.2.1
  • JSP - 2.3.1
Follow below 10 development steps to develop a complete end-to-end Spring MVC form validation application.

Development Steps

  1. Create Maven Web Application
  2. Add Dependencies - pom.xml File
  3. Project Structure
  4. Spring Configuration - MVCConfig.java
  5. Servlet Container Initialization - SpringMvcDispatcherServletInitializer.java
  6. Model Class - Customer.java
  7. Controller Class - CustomerController.java
  8. Views - customer-form.jsp and customer-confirmation.jsp
  9. Build and Run an application
  10. Demo

1. Create Maven Web Application

Let's create a Maven-based web application either using a command line or from Eclipse IDE.
1.  Use the Guide to Create Maven Web Application link to create a maven project using a command line. 
2. Use Create Maven Web Application using Eclipse IDE link to create a maven web application using IDE Eclipse.
Once you created a maven web application, refer to the pom.xml file jar dependencies.

2. Add Dependencies - pom.xml File

Refer to the following pom.xml file and add dependencies to your pom.xml.
<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.javaguides.springmvc</groupId>
    <artifactId>springmvc5-form-validation</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>springmvc5-form-validation Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <properties>
        <failOnMissingWebXml>false</failOnMissingWebXml>
    </properties>
    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.0.RELEASE</version>
        </dependency>
        <!-- Hibernate Validator -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.4.1.Final</version>
        </dependency>
        <!-- JSTL Dependency -->
        <dependency>
            <groupId>javax.servlet.jsp.jstl</groupId>
            <artifactId>javax.servlet.jsp.jstl-api</artifactId>
            <version>1.2.1</version>
        </dependency>
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
        <!-- Servlet Dependency -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <!-- JSP Dependency -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <sourceDirectory>src/main/java</sourceDirectory>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

3. Project Structure

Standard project structure for your reference -
As the name suggests Spring MVC, look at the above diagram we are using the Model-View-Controller approach.
Model - Customer.java
Views - customer-form.jsp and customer-confirmation.jsp 
Controller - CustomerController.java 
Next step, we will configure Spring beans using Java-based configuration.

4. Spring Configuration - MVCConfig.java

Create an MVCConfig class and annotated it with @Configuration, @EnableWebMvc, and @ComponentScan annotations.
package net.javaguides.springmvc.form.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

/**
 * @author Ramesh Fadatare
 */

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {
    "net.javaguides.springmvc.form"
})
public class MVCConfig implements WebMvcConfigurer {

    @Bean
    public InternalResourceViewResolver resolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setViewClass(JstlView.class);
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        return resolver;
    }
}
Let's look at few important annotations from the above file.
  • The @Configuration is a class-level annotation indicating that an object is a source of bean definitions.
  • The @EnableWebMvc enables default Spring MVC configuration and provides the functionality equivalent to mvc:annotation-driven/ element in XML based configuration.
  • The @ComponentScan scans the stereotype annotations (@Controller, @Service etc...) in a package specified by basePackages attribute.

5. Servlet Container Initialization - SpringMvcDispatcherServletInitializer.java

In Spring MVC, the DispatcherServlet needs to be declared and mapped for processing all requests either using java or web.xml configuration.
In a Servlet 3.0+ environment, you can use AbstractAnnotationConfigDispatcherServletInitializer class to register and initialize the DispatcherServlet programmatically as follows.
package net.javaguides.springmvc.form.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

/**
 * @author Ramesh Fadatare
 */
public class SpringMvcDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class << ? > [] getRootConfigClasses() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    protected Class << ? > [] getServletConfigClasses() {
        return new Class[] {
            MVCConfig.class
        };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] {
            "/"
        };
    }
}
Next step, we will create a Customer class Model.

6. Model Class - Customer.java

Let's create a Customer model class, whose field names are annotated with Hibernate Validator constraint annotations.
We will use this class for binding form data to the model and exposing model data to views.
package net.javaguides.springmvc.form.model;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.Email;

public class Customer {

    private String firstName;

    @NotNull(message = "is required")
    @Size(min = 1, message = "is required")
    private String lastName;

    @NotNull(message = "is required")
    @Min(value = 0, message = "must be greater than or equal to zero")
    @Max(value = 10, message = "must be less than or equal to 10")
    private Integer freePasses;

    @Pattern(regexp = "^[a-zA-Z0-9]{5}", message = "only 5 chars/digits")
    private String postalCode;

    @NotNull(message = "is required")
    @Email(message = "Invalid email! Please enter valid email")
    private String email;

    public String getPostalCode() {
        return postalCode;
    }

    public void setPostalCode(String postalCode) {
        this.postalCode = postalCode;
    }

    public Integer getFreePasses() {
        return freePasses;
    }

    public void setFreePasses(Integer freePasses) {
        this.freePasses = freePasses;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}
Note that we have use Validation annotations such as @NotNull, @Size, @Min, @Max, @Email@Pattern, and @NotEmpty.

7. Controller Class - CustomerController.java

Let's create CustomerController controller class annotated with @Controller annotation as follows:
package net.javaguides.springmvc.form.controller;

import javax.validation.Valid;

import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

import net.javaguides.springmvc.form.model.Customer;

@Controller
@RequestMapping("/customer")
public class CustomerController {

    // add an initbinder ... to convert trim input strings
    // remove leading and trailing whitespace
    // resolve issue for our validation

    @InitBinder
    public void initBinder(WebDataBinder dataBinder) {

        StringTrimmerEditor stringTrimmerEditor = new StringTrimmerEditor(true);

        dataBinder.registerCustomEditor(String.class, stringTrimmerEditor);
    }


    @RequestMapping("/showForm")
    public String showForm(Model theModel) {

        theModel.addAttribute("customer", new Customer());

        return "customer-form";
    }

    @RequestMapping("/processForm")
    public String processForm(
        @Valid @ModelAttribute("customer") Customer theCustomer,
        BindingResult theBindingResult) {

        if (theBindingResult.hasErrors()) {
            return "customer-form";
        } else {
            return "customer-confirmation";
        }
    }
}

8. Views - customer-form.jsp and customer-confirmation.jsp

customer-form.jsp

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

    <html>

    <head>
        <title>Customer Registration Form</title>

        <style>
            .error {
                color: red
            }
        </style>
    </head>

    <body>
        <h1> Spring MVC 5 - Form Validation Example</h1>
        <i>Fill out the form. Asterisk (*) means required.</i>
        <br><br>

        <form:form action="processForm" modelAttribute="customer">

            First name:
            <form:input path="firstName" />

            <br><br> Last name (*):
            <form:input path="lastName" />
            <form:errors path="lastName" cssClass="error" />

            <br><br> Free passes (*):
            <form:input path="freePasses" />
            <form:errors path="freePasses" cssClass="error" />

            <br><br> Email (*):
            <form:input path="email" />
            <form:errors path="email" cssClass="error" />

            <br><br> Postal Code:
            <form:input path="postalCode" />
            <form:errors path="postalCode" cssClass="error" />

            <br><br>

            <input type="submit" value="Submit" />

        </form:form>

    </body>

    </html>

customer-confirmation.jsp

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

    <!DOCTYPE html>

    <html>

    <head>
        <title>Customer Confirmation</title>
    </head>

    <body>

        The customer is confirmed: ${customer.firstName} ${customer.lastName}

        <br><br> Free passes: ${customer.freePasses}

        <br><br> Email: ${customer.email}

        <br><br> Postal Code: ${customer.postalCode}

    </body>

    </html>

9. Build and Run an application

As we are using the maven build tool so first, we will need to build this application using the following maven command:
clean install
Once build success, then we will run this application on tomcat server 8.5 in IDE or we can also deploy war file on external tomcat webapps folder and run the application.

10. Demo

Once an application is up and running in tomcat server then hit this link into browser: http://localhost:8080/springmvc5-form-validation/customer/processForm
On entering the URL, you will see the following page.
Fill the above form with proper input and hit submit button will navigate to the customer confirmation success page as shown below:

Source Code on GitHub

The source code of this tutorial available on my GitHub repository at https://github.com/RameshMF/spring-mvc-tutorial/tree/master/springmvc5-form-validation

What's next?

In next tutorial, we will learn how to create a Spring MVC web application and integrate it with Hibernate using Java-based configuration.

Comments