Showing posts with label Form validation. Show all posts
Showing posts with label Form validation. Show all posts

Wednesday, March 28, 2012

Spring Form Validation with Validator Interface

Spring 3 has a native validation support and this short post shows how it can be used.

As stated in the Spring reference itself:
  • validation should not be tied to the web tier
  • it should be easy to localize
  • it should be possible to plug in any validator available
Therefore, Spring has Validator interface and it can be used in any layer of the application.

Let's say you have a Company entity and you need a validation for it...

public class Company{

 private Long id; 
 private String name;
 private String address;
 private String contactEmail;
 private String websiteUrl;
 private String description;
 private String username;
 private String password;

 // getters and setters...
}

First, you need to do is to create a CompanyValidatior class which implements a Validator interface.

package com.demo.springmvcjpa.validation;

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

import com.demo.springmvcjpa.model.Company;

public class CompanyValidator implements Validator {

 public boolean supports(Class clazz) {
  return Company.class.isAssignableFrom(clazz);
 }

 public void validate(Object target, Errors errors) {
  ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "name.required"); 
  ValidationUtils.rejectIfEmptyOrWhitespace(errors, "contactEmail", "email.required");
  ValidationUtils.rejectIfEmptyOrWhitespace(errors, "address", "address.required");
 }

}

As you have noticed, there are 2 methods in Validator interface that need to be implemented:
1) supports - checks if this validator can validate instances of the supplied class, and
2) validate - which validates the given object and logs errors in Errors object (if any).

There's ValidationUtils helper class with a couple of useful methods: rejectIfEmpty and rejectIfEmptyOrWhitespace.

Sure, you need to register your bean by adding:


You'll also need to modify the CompanyController class:
package com.demo.springmvcjpa.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import com.demo.springmvcjpa.model.Company;
import com.demo.springmvcjpa.service.CompanyService;
import com.demo.springmvcjpa.validation.CompanyValidator;

@Controller
@RequestMapping("/company")
public class CompanyController {

 private static final Logger logger = LoggerFactory.getLogger(CompanyController.class);

 CompanyService companyService;

 @Autowired
 public void setCompanyService(CompanyService companyService) {
  this.companyService = companyService;
 }
 
 @Autowired
 private CompanyValidator validator;

 @ModelAttribute("company")
 public Company init(@PathVariable String id) {
  return companyService.find(id);
 }
 
 @RequestMapping(value="/{id}", method=RequestMethod.GET)
 public ModelAndView view(ModelAndView mv, @ModelAttribute("company") Company company) {
  logger.info("requesting company");
  mv.addObject("company", company);
  mv.setViewName("company/save");
  return mv;
 }

 @RequestMapping(value="/{id}", method=RequestMethod.POST)
 public String update(ModelAndView mv, @ModelAttribute("company") Company company, BindingResult result) {
     logger.info("updating company");
     validator.validate(company, result);
     if (result.hasErrors()) {
      return "company/save";
     } else {
      return "redirect:/spring/company/details/" + companyService.save(company).getId();
     }
 }

        // other methods...
 
}
And finally, to display errors in the view you need to add line:

This is the case when you want to show the errors altogether on top of the form (see the example below). You may want to add error message beside after each form field (or something similar), in which case you would replace * value for path attribute with corresponding property name.
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ page session="false" %>

 
 
 
 
Name:
Description:
Address:
Email:
Website URL:
Username:
Password:

Note that class="required", type="url" and possibly some other attributes are part of Client side validation and are not necessary. If you want to read more about Client Side Validation with jQuery Validator plugin you may want to read this post.

Dont't forget to add error messages to your messages.properties file:

company.name.required=Name is required
company.address.required=Address is required simple
company.email.required=Email is required

This is how validation may look like for simple objects. I'll write more about validation for composite objects.


Monday, March 5, 2012

Client Side Form Validation - jQuery Validation plugin

Client side validation and server side validation are both important and should go side by side.

Client Side validation - valuable for quick check of simple input mistakes, very fast, increases interactivity, user doesn't need to wait after each submit, saves server load and there's no unnecessary traffic, but it's not a replacement for a server side validation.

Server side validation - still needed as a "second line of defence" (user can easily disable or change JavaScript and break the client side validation) and for more complicated validations.

One of the options for a client side validation is jQuery Validation plugin which makes things really simple. This plugin contains a set of validation methods (e.g. email/url validation) and provides API so you can write your own methods.

All you need is a single line of code to select the form and apply validation plugin:

<script type="text/javascript">
$(document).ready(function(){
     $("form#simpleForm").validate();
</script>


And some metadata on the form:
- class="required valid" and minlength="2" for name input
- class="required valid" and type="email" for email input


<form id="simpleForm" method="get" action="" novalidate="novalidate">
  <p>
   <label for="name">Name (minimum 2 characters) *</label>
   <input id="name" name="name" class="required valid" minlength="2"><label for="cname" generated="true" class="error" style="display: none; ">Please enter at least 2 characters.</label>
  </p><p>
   <label for="email">E-Mail *</label>
   <input id="email" type="email" name="email" class="required valid"><label for="cemail" generated="true" class="error" style="display: none; ">Please enter a valid email address.</label>
  </p>
  <p>
   <input class="submit" type="submit" value="Submit">
  </p>
</form>

Some of the most used input field attributes are:

class="required"
type="email", "url", "date", "number", "digits", "creditcard", "phoneUS"
min, max, maxlength, minlength="5"


More complex examples and explanations can be found on:
http://jquery.bassistance.de/validate/demo/index.html
Documentation for jQuery Validation plugin: http://docs.jquery.com/Plugins/Validation
If you want to read more about Server Side Validation using Spring Validator interface there's another post explaining how it can be done.