Spring MVC form validation with custom validator

In the previous post, we have seen the form validation using java validations by annotating model class with constraint validation annotations.

Good part of it is, we can just add annotations on the fields of the model class and if any errors in the form as per the annotations , Binding Result will get the errors.

But bad part of it is , we will not get annotations for all our business validations on the form fields.

Example : If we want to Validate age field to be greater than 18 and less than 60 to be allowed then we need to define our own validator.

So lets see how we can write our custom validator
We need to do following things to define our custom validator

1)Create the custom validator class for model class on which we validate and implement the validator interface, make custom validator class as spring bean.
2)Override supports(Class clazz) method
3)Override validate(Object target,Errors errors) method
4)After this we need to inject this custom validator in the controller class and call its validate() method
5)Then check the binding result for any errors and return the appropriate view.

Project structure

First will define the model class as below

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.kb.model;
 
import javax.validation.constraints.Size;
 
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
 
public class Customer {
    
    @NotEmpty
    @Email
    private String emailId;
    
    @Size(min=8,max=15)
    private String password;
    
    
    @Size(min=8,max=15)
    private String confPassword;
    
    private int age;
 
    public String getEmailId() {
        return emailId;
    }
 
    public void setEmailId(String emailId) {
        this.emailId = emailId;
    }
 
    public String getPassword() {
        return password;
    }
 
    public void setPassword(String password) {
        this.password = password;
    }
 
    public String getConfPassword() {
        return confPassword;
    }
 
    public void setConfPassword(String confPassword) {
        this.confPassword = confPassword;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
}
package com.kb.model;

import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;

public class Customer {
	
	@NotEmpty
	@Email
	private String emailId;
	
	@Size(min=8,max=15)
	private String password;
	
	
	@Size(min=8,max=15)
	private String confPassword;
	
	private int age;

	public String getEmailId() {
		return emailId;
	}

	public void setEmailId(String emailId) {
		this.emailId = emailId;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getConfPassword() {
		return confPassword;
	}

	public void setConfPassword(String confPassword) {
		this.confPassword = confPassword;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

}

We will have the basic validation annotations to validate each field and we will use custom validator for business validation.

Note : age field is not having basic annotation @NotEmpty as I demonstrate the same inside custom validator.

Now will define custom validator as below

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.kb.validator;
 
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
 
import com.kb.model.Customer;
 
@Component
public class CustomerValidator implements Validator {
 
    public boolean supports(Class<?> clazz) {
        return Customer.class.isAssignableFrom(clazz);
    }
 
    public void validate(Object target, Errors errors) {
        Customer customer = (Customer)target;
        int age = customer.getAge();
        String password = customer.getPassword();
        String confPassword = customer.getConfPassword();
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "age", "customer.age.empty");
        
        //Business validation
        if(!password.equals(confPassword)){
            errors.rejectValue("password","customer.password.missMatch");
        }
        if(age < 18 || age > 60){
            errors.rejectValue("age", "customer.age.range.invalid");
        }
    
    }
}
package com.kb.validator;

import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

import com.kb.model.Customer;

@Component
public class CustomerValidator implements Validator {

	public boolean supports(Class<?> clazz) {
		return Customer.class.isAssignableFrom(clazz);
	}

	public void validate(Object target, Errors errors) {
		Customer customer = (Customer)target;
		int age = customer.getAge();
		String password = customer.getPassword();
		String confPassword = customer.getConfPassword();
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "age", "customer.age.empty");
		
		//Business validation
		if(!password.equals(confPassword)){
			errors.rejectValue("password","customer.password.missMatch");
		}
		if(age < 18 || age > 60){
			errors.rejectValue("age", "customer.age.range.invalid");
		}
	
	}
}

Observe the age validation for empty or whitespace is achieved using ValidationUtils method, so we didn’t add @NotEmpty annotatin on age field in model class.

We can completely remove all the annotations on the model class and validate the fields using ValidationUtils methods and our custom validation.

Finally errors are getting added to the Binding result object.

Define the controller class as below

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.kb.controller;
 
import javax.validation.Valid;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
 
import com.kb.model.Customer;
import com.kb.validator.CustomerValidator;
 
@Controller
public class RegistrationController {
    
    @Autowired
    CustomerValidator customerValidator;
    
    
     @RequestMapping(value = "/register", method = RequestMethod.GET)
        public String viewRegistrationPage(Model model) {
          Customer customer = new Customer();
            model.addAttribute("customer", customer);
            return "register";
        }
    
     @RequestMapping(value = "/doRegister", method = RequestMethod.POST)
        public String doLogin(@Valid Customer customer, BindingResult result,Model model) {
         model.addAttribute("customer",customer);
         customerValidator.validate(customer, result);
          if(result.hasErrors()){
              return "register";
          }
          
          return "home";
        }
 
    public CustomerValidator getCustomerValidator() {
        return customerValidator;
    }
 
    public void setCustomerValidator(CustomerValidator customerValidator) {
        this.customerValidator = customerValidator;
    }
 
}
package com.kb.controller;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.kb.model.Customer;
import com.kb.validator.CustomerValidator;

@Controller
public class RegistrationController {
	
	@Autowired
	CustomerValidator customerValidator;
	
	
	 @RequestMapping(value = "/register", method = RequestMethod.GET)
	    public String viewRegistrationPage(Model model) {
	      Customer customer = new Customer();
	        model.addAttribute("customer", customer);
	        return "register";
	    }
	
	 @RequestMapping(value = "/doRegister", method = RequestMethod.POST)
	    public String doLogin(@Valid Customer customer, BindingResult result,Model model) {
		 model.addAttribute("customer",customer);
		 customerValidator.validate(customer, result);
	      if(result.hasErrors()){
	    	  return "register";
	      }
	      
	      return "home";
	    }

	public CustomerValidator getCustomerValidator() {
		return customerValidator;
	}

	public void setCustomerValidator(CustomerValidator customerValidator) {
		this.customerValidator = customerValidator;
	}

}

In the above controller , we have autowired the customerValidator and called validate() method by passing model object and BindingResult object, which will validate the fields.

Create messages.properties file under WEB-INF directory

1
2
3
4
5
6
7
NotEmpty.customer.emailId=Email Id is required. 
Email.customer.emailId=valid email id is required.
Size.customer.password=Password should be minimum of 8 and maximum of 15 characters.
Size.customer.confPassword=Password should be minimum of 8 and maximum of 15 characters.
customer.age.empty = Age is required
customer.age.range.invalid = Age should be between 18 to 60
customer.password.missMatch = password and confirm password do not match
NotEmpty.customer.emailId=Email Id is required. 
Email.customer.emailId=valid email id is required.
Size.customer.password=Password should be minimum of 8 and maximum of 15 characters.
Size.customer.confPassword=Password should be minimum of 8 and maximum of 15 characters.
customer.age.empty = Age is required
customer.age.range.invalid = Age should be between 18 to 60
customer.password.missMatch = password and confirm password do not match

Create spring configuration file as below

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
 
    <context:component-scan base-package="com.kb.*" />
    <mvc:annotation-driven />
 
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/" />
        <property name="suffix" value=".jsp" />
    </bean>
 
    <bean id="messageSource"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
 
        <property name="basename" value="/WEB-INF/messages" />
    </bean>
</beans>
<?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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">

	<context:component-scan base-package="com.kb.*" />
	<mvc:annotation-driven />

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

	<bean id="messageSource"
		class="org.springframework.context.support.ReloadableResourceBundleMessageSource">

		<property name="basename" value="/WEB-INF/messages" />
	</bean>
</beans>

Create web.xml as below

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    version="3.1">
 
    <display-name>Spring MVC custom validator</display-name>
 
    <!-- Spring MVC dispatcher servlet -->
    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
            /WEB-INF/spring-mvc.xml,
        </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
 
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	version="3.1">

	<display-name>Spring MVC custom validator</display-name>

	<!-- Spring MVC dispatcher servlet -->
	<servlet>
		<servlet-name>mvc-dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>
			/WEB-INF/spring-mvc.xml,
		</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>mvc-dispatcher</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
</web-app>

Add depndencies in pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<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>Spring</groupId>
  <artifactId>CustomValidation</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>CustomValidation Maven Webapp</name>
  <url>http://maven.apache.org</url>
 <properties>
        <org.springframework.version>4.2.0.RELEASE</org.springframework.version>
    </properties>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
 
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </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>
<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.0.1.Final</version>
 </dependency>
  </dependencies>
  <build>
    <finalName>SpringMVCCustomValidation</finalName>
    <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
  </build>
</project>
<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>Spring</groupId>
  <artifactId>CustomValidation</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>CustomValidation Maven Webapp</name>
  <url>http://maven.apache.org</url>
 <properties>
		<org.springframework.version>4.2.0.RELEASE</org.springframework.version>
	</properties>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${org.springframework.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework.version}</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</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>
<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.0.1.Final</version>
 </dependency>
  </dependencies>
  <build>
    <finalName>SpringMVCCustomValidation</finalName>
    <plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.5.1</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
		</plugins>
  </build>
</project>

Build the project and deploy the war file in Tomcat

Access below url

http://localhost:8080/SpringMVCCustomValidation/register

Don’t enter anything, just click on Register

Enter valid details but enter miss match password to check that validation

Enter valid details to register and click on Register

Now we will see how InitBinder can be injected to controller for custom validation.

When we use initBinder for our custom validator , default spring validator will no be called hence, we need to add all the validations in the custom validator.

Annotations on the Model class will not do any validation so just remove them.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.kb.model;
 
import javax.validation.constraints.Size;
 
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
 
public class Customer {
    
    
    private String emailId;
    
    
    private String password;
    
    
    
    private String confPassword;
    
    private int age;
 
    public String getEmailId() {
        return emailId;
    }
 
    public void setEmailId(String emailId) {
        this.emailId = emailId;
    }
 
    public String getPassword() {
        return password;
    }
 
    public void setPassword(String password) {
        this.password = password;
    }
 
    public String getConfPassword() {
        return confPassword;
    }
 
    public void setConfPassword(String confPassword) {
        this.confPassword = confPassword;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
}
package com.kb.model;

import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;

public class Customer {
	
	
	private String emailId;
	
	
	private String password;
	
	
	
	private String confPassword;
	
	private int age;

	public String getEmailId() {
		return emailId;
	}

	public void setEmailId(String emailId) {
		this.emailId = emailId;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getConfPassword() {
		return confPassword;
	}

	public void setConfPassword(String confPassword) {
		this.confPassword = confPassword;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

}

Modify our custom validator to validate each field .

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.kb.validator;
 
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
 
import com.kb.model.Customer;
 
@Component
public class CustomerValidator implements Validator {
 
    public boolean supports(Class<?> clazz) {
        return Customer.class.isAssignableFrom(clazz);
    }
 
    public void validate(Object target, Errors errors) {
        Customer customer = (Customer)target;
        int age = customer.getAge();
        String password = customer.getPassword();
        String confPassword = customer.getConfPassword();
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "emailId", "customer.emailId.empty");
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "age", "customer.age.empty");
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "customer.password.empty");
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "confPassword", "customer.confPassword.empty");
        
        //Business validation
        if(!password.equals(confPassword)){
            errors.rejectValue("password","customer.password.missMatch");
        }
        if(age < 18 || age > 60){
            errors.rejectValue("age", "customer.age.range.invalid");
        }
        
        if(!customer.getEmailId().matches("^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@" + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$")){
            errors.rejectValue("emailId", "customer.emailId.invalid");
        }
    }
 
}
package com.kb.validator;

import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

import com.kb.model.Customer;

@Component
public class CustomerValidator implements Validator {

	public boolean supports(Class<?> clazz) {
		return Customer.class.isAssignableFrom(clazz);
	}

	public void validate(Object target, Errors errors) {
		Customer customer = (Customer)target;
		int age = customer.getAge();
		String password = customer.getPassword();
		String confPassword = customer.getConfPassword();
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "emailId", "customer.emailId.empty");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "age", "customer.age.empty");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "customer.password.empty");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "confPassword", "customer.confPassword.empty");
		
		//Business validation
		if(!password.equals(confPassword)){
			errors.rejectValue("password","customer.password.missMatch");
		}
		if(age < 18 || age > 60){
			errors.rejectValue("age", "customer.age.range.invalid");
		}
		
		if(!customer.getEmailId().matches("^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@" + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$")){
			errors.rejectValue("emailId", "customer.emailId.invalid");
		}
	}

}

In the controller class , add below code

1
2
3
4
@InitBinder
    public void initBinder(WebDataBinder webDataBinder){
        webDataBinder.setValidator(customerValidator);
    }
@InitBinder
	public void initBinder(WebDataBinder webDataBinder){
		webDataBinder.setValidator(customerValidator);
	}

And remove the below code which we make an explicit call to validate

1
customerValidator.validate(customer, result);
customerValidator.validate(customer, result);

So InitBinder will call the custom validator automatically on form submit.

So your full controller should be as below

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.kb.controller;
 
import javax.validation.Valid;
 
import org.springframework.beans.factory.annotation.Autowired;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
 
import com.kb.model.Customer;
import com.kb.validator.CustomerValidator;
 
@Controller
public class RegistrationController {
    
    @Autowired
    CustomerValidator customerValidator;
    
    @InitBinder
    public void initBinder(WebDataBinder webDataBinder){
        webDataBinder.setValidator(customerValidator);
    }
    
    
     @RequestMapping(value = "/register", method = RequestMethod.GET)
        public String viewRegistrationPage(Model model) {
          Customer customer = new Customer();
            model.addAttribute("customer", customer);
            return "register";
        }
    
     @RequestMapping(value = "/doRegister", method = RequestMethod.POST)
        public String doLogin(@Valid Customer customer, BindingResult result,Model model) {
         model.addAttribute("customer",customer);
         //customerValidator.validate(customer, result);
          if(result.hasErrors()){
              return "register";
          }
          
          return "home";
        }
 
    public CustomerValidator getCustomerValidator() {
        return customerValidator;
    }
 
    public void setCustomerValidator(CustomerValidator customerValidator) {
        this.customerValidator = customerValidator;
    }
 
}
package com.kb.controller;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.kb.model.Customer;
import com.kb.validator.CustomerValidator;

@Controller
public class RegistrationController {
	
	@Autowired
	CustomerValidator customerValidator;
	
	@InitBinder
	public void initBinder(WebDataBinder webDataBinder){
		webDataBinder.setValidator(customerValidator);
	}
	
	
	 @RequestMapping(value = "/register", method = RequestMethod.GET)
	    public String viewRegistrationPage(Model model) {
	      Customer customer = new Customer();
	        model.addAttribute("customer", customer);
	        return "register";
	    }
	
	 @RequestMapping(value = "/doRegister", method = RequestMethod.POST)
	    public String doLogin(@Valid Customer customer, BindingResult result,Model model) {
		 model.addAttribute("customer",customer);
		 //customerValidator.validate(customer, result);
	      if(result.hasErrors()){
	    	  return "register";
	      }
	      
	      return "home";
	    }

	public CustomerValidator getCustomerValidator() {
		return customerValidator;
	}

	public void setCustomerValidator(CustomerValidator customerValidator) {
		this.customerValidator = customerValidator;
	}

}

Modify messages.properties as below

1
2
3
4
5
6
7
customer.emailId.empty=Email Id is required. 
customer.emailId.invalid=valid email id is required.
customer.password.empty=Password is required
customer.confPassword.empty=Confirm Password is required
customer.age.empty = Age is required
customer.age.range.invalid = Age should be between 18 to 60
customer.password.missMatch = password and confirm password do not match
customer.emailId.empty=Email Id is required. 
customer.emailId.invalid=valid email id is required.
customer.password.empty=Password is required
customer.confPassword.empty=Confirm Password is required
customer.age.empty = Age is required
customer.age.range.invalid = Age should be between 18 to 60
customer.password.missMatch = password and confirm password do not match

And run the project , we will get the validation messages as below again.

Download this project SpringMVCCustomValidation.zip

About the Author

Karibasappa G C (KB)
Founder of javainsimpleway.com
I love Java and open source technologies and very much passionate about software development.
I like to share my knowledge with others especially on technology 🙂
I have given all the examples as simple as possible to understand for the beginners.
All the code posted on my blog is developed,compiled and tested in my development environment.
If you find any mistakes or bugs, Please drop an email to kb.knowledge.sharing@gmail.com

Connect with me on Facebook for more updates

Share this article on