In spring mvc form submit tutorial, we learned about displaying displaying a form and submitting form data, including validating inputs using BindingResult.rejectValue()
. In this example, we will learn to build a more robust validator for EmployeeVO
model object. This validator is custom implementation of Validator
interface. In this example, I am modifying the code used for form submit example we built in last tutorial.
Read More : Spring MVC Display, Validate and Submit Form Example
Custom Validator Implementation
Spring MVC supports validation by means of a validator object that implements the Validator
interface. You can write the following validator to check if the required form fields are filled.
package com.howtodoinjava.demo.validator; import org.springframework.stereotype.Component; import org.springframework.validation.Errors; import org.springframework.validation.ValidationUtils; import org.springframework.validation.Validator; import com.howtodoinjava.demo.model.EmployeeVO; @Component public class EmployeeValidator implements Validator { public boolean supports(Class clazz) { return EmployeeVO.class.isAssignableFrom(clazz); } public void validate(Object target, Errors errors) { ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "error.firstName", "First name is required."); ValidationUtils.rejectIfEmptyOrWhitespace(errors, "lastName", "error.lastName", "Last name is required."); ValidationUtils.rejectIfEmptyOrWhitespace(errors, "email", "error.email", "Email is required."); } }
In this validator, you use utility methods such as rejectIfEmptyOrWhitespace()
and rejectIfEmpty()
in the ValidationUtils
class to validate the required form fields. If any of these form fields is empty, these methods will create a field error and bind it to the field. The second argument of these methods is the property name, while the third and fourth are the error code and default error message.
Many times validation errors are not specific to fields. For example end date should be greater than start date. In this case, you can use the reject()
method to create an object error to be bound to the EmployeeVO
object, not to a field.
e.g. errors.reject(“invalid.dateDiff”, “End date should be greater than start date.”);
To activate this custom validator as a spring managed bean, you need to do one of following things:
1) Add @Component annotation to EmployeeValidator
class and activate annotation scanning on the package containing such declarations.
<context:component-scan base-package="com.howtodoinjava.demo" />
2) Alternatively, you can register the validator class bean directly in context file.
<bean id="employeeValidator" class="com.howtodoinjava.demo.validator.EmployeeValidator" />
Controller Changes
To apply this validator, you need to perform the following modification to your controller.
1) Include validator reference to controller class and mark it autowired to ensure it’s available when needed.
@Autowired EmployeeValidator validator;
2) Next change is in controller’s post method which is called when user submit the form.
@RequestMapping(method = RequestMethod.POST) public String submitForm(@ModelAttribute("employee") EmployeeVO employeeVO, BindingResult result, SessionStatus status) { //Validation code validator.validate(employeeVO, result); //Check validation errors if (result.hasErrors()) { return "addEmployee"; } //Store the employee information in database //manager.createNewRecord(employeeVO); //Mark Session Complete status.setComplete(); return "redirect:addNew/success"; }
Once the validate method returns, the result parameter i.e. BindingResult
contains the results for the validation process. You can check if there was any error in input using result.hasErrors()
method call. If any error is detected you can again render the form view to let user correct it’s input.
If there is no error found then result.hasErrors()
will return false, then you can simply process the input and redirect the user to next view.
Complete sourcecode foe controller used in this example is below:
package com.howtodoinjava.demo.controller; 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.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.SessionAttributes; import org.springframework.web.bind.support.SessionStatus; import com.howtodoinjava.demo.model.EmployeeVO; import com.howtodoinjava.demo.service.EmployeeManager; import com.howtodoinjava.demo.validator.EmployeeValidator; @Controller @RequestMapping("/employee-module/addNew") @SessionAttributes("employee") public class EmployeeController { @Autowired EmployeeManager manager; @Autowired EmployeeValidator validator; @RequestMapping(method = RequestMethod.GET) public String setupForm(Model model) { EmployeeVO employeeVO = new EmployeeVO(); model.addAttribute("employee", employeeVO); return "addEmployee"; } @RequestMapping(method = RequestMethod.POST) public String submitForm(@ModelAttribute("employee") EmployeeVO employeeVO, BindingResult result, SessionStatus status) { validator.validate(employeeVO, result); if (result.hasErrors()) { return "addEmployee"; } //Store the employee information in database //manager.createNewRecord(employeeVO); //Mark Session Complete status.setComplete(); return "redirect:addNew/success"; } @RequestMapping(value = "/success", method = RequestMethod.GET) public String success(Model model) { return "addSuccess"; } }
Drop me you questions into comments section.
Happy Learning !!
Kunta Kinte
What if we are taking about a nested Object? For instance, let’s say we have a UserDto with the following fields:
String name (which is simple)
String password (simple also)
Address address -> with the following fields in its class: StreetName, streetNumber.
How do you access the nested object’s fields from within UserValidator class?
Praveen Das
Can we perform validation on a List of RequestBody object?
Custom Collection Validator’s “supports()” method does not support the entities within the collection.
Sugam
Nice article.
i am getting problem in fetching value from database. I have create simple login page i am having problem in if we insert username and password it must check from database whether it is valid or not for multiple user. just like facebook first registered the login with that details. please provide me the code.
Medha Gupta
How do we display the spring validation errors on front end form using angular JS.
shamim
hi Lokesh,
how to use error code in ValidationUtils.rejectIfEmpty()? 3rd argument
kartik
How can we return list of errors using single handler?
Rajesh
Hi,
Instead of using “validator.validate(employeeVO, result);” can’t we just use @valid before the @ModelAttribute ?
Lokesh Gupta
For standard validations, you can use that. But when validations van not be expressed via annotations, then you will need to use this.
Asad
Hi,
Nice article. What is the purpose of status.setComplete(); ? when do we use sessionstatus class. please give some scenario.
Regards,Asad
Lokesh Gupta
You see “
@SessionAttributes("employee")
” at controller level, SessionStatus.setComplete(); clear all such attributes.When @SessionAttribute is not used, a new command object will be created on each request, even when rendering the form again due to binding errors. If this annotation is enabled, the command object will be stored in the session for subsequent uses, until you call setComplete() method.
If you do not call this method explicitly, then variable will be stored in session forever.
wilson
Hi Lokesh, nice publication. I have a question about this validations, suppose you have two classes (User and Address, this classes has a one-to-one cardinality ) and you have a user form registration in the view. What is the best practice to validate all fields (of both classes) at the same time when the user press the “save” button?
Thanks in advance buddy.
Lokesh Gupta
For me best way to validate is using “JSR-303 Annotations“. You can use respective annotations in all fields (User and Address) and it will validate all fields inside it.