Spring MVC4 – Form Validation

In the previous 2 posts we have seen how to build a spring mvc project without any xml files and a simple registration form. In this post we will be validating form fields on the server side. There are many ways of doing it. One of the spring way that we saw in the spring mvc3 was to implement a validator interface and bind it with result. We will be using Bean validation (JSR 303 ) here. We already have our registration form setup. Lets add the following 2 dependencies in our pom


<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.3.Final</version>
</dependency>
<dependency>

These 2 provides some of the basic validation implementation for some fields. We are just using the hibernate validator jar and not the hibernate framework. Lets annotate our RegistrationModel.java


package com.mynotes.spring.mvc4.model;

import javax.validation.constraints.Size;

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

public class RegistrationModel {

@Size(min=2, max=30)
private String fname;

@Size(min=2, max=30)
private String lname;

@NotEmpty @Email
private String email;
private String phone;

public String getFname() {
return fname;
}

public void setFname(String fname) {
this.fname = fname;
}

public String getLname() {
return lname;
}

public void setLname(String lname) {
this.lname = lname;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public String getPhone() {
return phone;
}

public void setPhone(String phone) {
this.phone = phone;
}

@Override
public String toString() {
return "RegistrationModel [fname=" + fname + ", lname=" + lname + ", email=" + email + ", phone=" + phone + "]";
}

}

There are many other annotation provided which you may use or combine few of them. Lets change RegistrationController.java in the POST controller.


package com.mynotes.spring.mvc4.controllers;

import javax.validation.Valid;

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

import com.mynotes.spring.mvc4.model.RegistrationModel;

@Controller
public class RegistrationController {

@RequestMapping(value="/register", method = RequestMethod.GET)
public String displayRegistrationPage(Model model) {

RegistrationModel form = new RegistrationModel();
model.addAttribute("registrationModel", form);
return "registration";
}

@RequestMapping(value="/register", method = RequestMethod.POST)
public String processRegistrationPage(@Valid RegistrationModel form, BindingResult errors, Model model) {

System.out.println(form);
if(errors.hasErrors()){
return "registration";
}
return "success";
}

}

Above in the processRegistrationPage method we accept a valid RegistrationModel using @Valid annotation with BindingResult  and Model as other parameters (Model if we want to change something). If there is error we go back to our registration page. Lets add the error tags in our jsp. There are 2 ways, error against their respective field or showing a combine errors in one area. changing registration.jsp


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

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Registration</title>
<link rel="stylesheet" href="resources/css/style.css" type="text/css"/>
</head>
<body>
<form:form method="post" action="register" commandName="registrationModel">
<h2>Registration</h2>
<a href="?language=en">
English
</a>
<a href="?language=es">
Spanish
</a>

<form:errors path="*" cssClass="errorblock" element="div"/>
<table>
<tr>
<td><form:label path="fname"><spring:message code="label.fname"/></form:label></td>
<td><form:input path="fname" /><form:errors path="fname" cssClass="error" /></td>
</tr>
<tr>
<td><form:label path="lname"><spring:message code="label.lname"/></form:label></td>
<td><form:input path="lname" /><form:errors path="lname" cssClass="error" /></td>
</tr>
<tr>
<td><form:label path="email"><spring:message code="label.email"/></form:label></td>
<td><form:input path="email" /><form:errors path="email" cssClass="error" /></td>
</tr>
<tr>
<td><form:label path="phone"><spring:message code="label.phone"/></form:label></td>
<td><form:input path="phone" /></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="<spring:message code="label.register"/>"/>
</td>
</tr>
</table>

</form:form>
</body>
</html>

Submitting form without any invalid inputs

springmvc4-validation

springmvc4validation2

springmvc4validation3

Note the 2 different errors on the email field, since we used 2 annotation and also notice the erros message are coming in other language to.

Now What if we want to have our own custom error message instead of the defaults ones. Add the following in your messages_en.properties file


Size.registrationModel.fname=First name must be between {2} and {1} characters
Size.registrationModel.lname=Last name must be between {2} and {1} characters

Email= Not a valid email
NotEmpty= Required field

Here the first word is the annotation name. The second is the commnadName used in your form and the third word is your attribute name in your model class. Do the same in your other language files to.

springmvc4validation4

What if we want to have our own constraint validation. Lets do the same on the Phone field. We will create a custom validator which can be used using annotation just like Email, NotEmpty etc.

Lets create a Phone interface, so as it could be used in annotation to fields.


package com.mynotes.spring.mvc4.utils;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

@Documented
@Constraint(validatedBy=PhoneValidator.class)
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Phone {

String message() default "{Phone}";

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

Class<? extends Payload>[] payload() default{};
}

The above is validated by PhoneValidator.java. Lets create that


package com.mynotes.spring.mvc4.utils;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class PhoneValidator implements ConstraintValidator<Phone, String> {

@Override
public void initialize(Phone phone) {

}

@Override
public boolean isValid(String phoneField, ConstraintValidatorContext cxt) {
if(phoneField == null) {
return false;
}

return phoneField.matches("[\\d{10}]*");
}
}

As you can see you can validate stuffs in the isValid method using regex or DB validations etc.

Lets use it in our RegistrationModel class


.
.
@NotEmpty @Phone
private String phone;
.

Add the corresponding error message in the properties file

Phone = Not a valid phone

Submitting invalid phone input

springmvc4validation5

%d bloggers like this: