Tuesday, July 10, 2012

Simple form validation with Spring MVC

While developing a web application it's always wise to provide users with feedback about form validation rather that present them the error.
Here, I want to show how to accomplich this task within a Spring MVC application.
First, write down the model against which validation will be performed. A model is nothing more than a POJO.

public class FormModel {
 
 private String name;
 private String surname;
 private Long years = 0L;

        // getters and settes omitted
}

The model has just two String members and a Long member. Let's suppose that the two strings cannot be empty (means, not null and containing at least one char) and that the Long must be greater than 0.
What we need to do now is to write down a validator for this object. I'm not going to implement the Spring Validator interface here to keep things as simple as possible.

public class FormModelValidator {
 
 public void validate(FormModel model, BindingResult bindingResult){
  if(model.getName()==null || model.getName().length()==0){
   bindingResult.rejectValue("name", "validation_form_model_name");
  }
  
  if(model.getSurname()==null || model.getSurname().length()==0){
   bindingResult.rejectValue("surname", "validation_form_model_surname");
  }
  
  if(model.getYears()<=0){
   bindingResult.rejectValue("years", "validation_form_model_years");
  }
 }

}

You can see that in the rejectValue methods I've used a code rather than a phrase: this is to localize your error messages. Now, the controller class. This is the class responsible of the binding between the application logic and what the user sees. As I said before, I want to keep things simpe: this is not the formal definition af a controller, you can find it here on Wikipedia.

public class FormController {

 private FormModel model = null;

 @ModelAttribute("model")
 public FormModel injectModel() {
  if (model == null)
   model = new FormModel();
  return model;
 }

 @RequestMapping(method = RequestMethod.GET)
 public String index() {
  return "index";
 }

 @RequestMapping(method = RequestMethod.POST)
 public ModelAndView doPost(@ModelAttribute("model") FormModel model,
   BindingResult bindingResult) {
  FormModelValidator validator = new FormModelValidator();
  validator.validate(model, bindingResult);

  if (bindingResult.hasErrors())
   return new ModelAndView("index");

  ModelAndView mav = new ModelAndView("index");
  mav.addObject("model", model);
  mav.addObject("message", "VALUES SUCCESSFULLY VALIDATED");
  
  return mav;
 }
 
}

You can even skip the implementation class and move al the code in the controller class.
Let's take a look at the controller.
We can see that it responds on the root path. It injects in the model our object (what we need to validate). It also handles the POST of the form (this is where the validation is performed).
You can also notice that our FormModel object is stored as a member of the controller class. This allows persistence between different posts of the form.
The last thing we need to take a look at, is the form.

<form:form method="post" modelAttribute="model">
 <div class="rows">
  <div class="row">
   <label>NAME</label>
   <form:input path="name" />
   <form:errors path="name" cssClass="errors" />
  </div>
  <div class="row">
   <label>SURNAME</label>
   <form:input path="surname" />
   <form:errors path="surname" cssClass="errors" />
  </div>
  <div class="row">
   <label>YEARS</label>
   <form:input path="years" />
   <form:errors path="years" cssClass="errors" />
  </div>
 </div>
 <div class="submit">
  <input type="submit" value="VALIDATE" />
 </div>
</form:form>

As you can see it is very simple. Just don't forget to include the namespace
http://www.springframework.org/tags/form
in your page directives.

You can check out the code (as a Spring Roo project) at this repository.

Bye,
Stefano

No comments:

Post a Comment