Suggested Pages

Friday, May 11, 2012

Spring MVC Custom Validator

In this post we'll see an example of a form data validation. This form has two fields: number and type. I use a Controller to manage the request and a custom Validator to validate the form.
If some errors occur during validation, we'll show error messages just above each field that has caused the problem.

Step-1: Create a POJO class representing the object you want to validate and the JSP page containing the form


As you can see Contact is a class that has two fields: number and type. This class contains exactly the fields of the form.

Contact.java

package com.simonefolinojavablog.spring.bean;

public class Contact {


 private int number;

 private String type;

 public int getNumber() {
  return number;
 }

 public void setNumber(int number) {
  this.number = number;
 }

 public String getType() {
  return type;
 }

 public void setType(String type) {
  this.type = type;
 }

 @Override
 public String toString() {
  return "Contact [number=" + number + ", type=" + type + "]";
 }
}


The following JSP has a form with two input text: type and number. The form tag specifies both the modelAttribute (the bean that maps the form) and the action (the request URL).

form.jsp

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>


<html>
<head>
<title>Form Page</title>
</head>

<body>

 <form:form id="" action="/springmvc-validator/contacts/save.htm" modelAttribute="contact"
  method="POST">
  <table>
   <thead>
    <tr>
     <th>Fields</th>
    </tr>
   </thead>
   <tbody>
    <tr>
     <td> <form:errors path="number" cssClass="error" element="div" />
     number: <input type="text" name="number" value="" /></td>
    </tr>
    <tr>
     <td> <form:errors path="type"  ssClass="error" element="div" />
      type: <input type="text" name="type" value="" /></td>
    </tr>
    <tr>
     <td><input type="submit" name="save" value="save" /></td>
    </tr>
   </tbody>
  </table>
 </form:form>

</body>


</html>




Step-2: Create a Validator


In the following code is shown a subclass of Validator: CustomValidator. We have to override two methods of Validator class: supports that tells which kind of bean has to be validated and validate that contains the logic of validation.

ContactValidator.java

package com.simonefolinojavablog.spring.validator;

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

import com.simonefolinojavablog.spring.bean.Contact;

@Component
public class ContactValidator implements Validator {

 @Override
 public boolean supports(Class clazz) {
  return Contact.class.equals(clazz);
 }

 @Override
 public void validate(Object target, Errors errors) {
  Contact contact =(Contact)target;
  System.out.println("contact:"+contact+"  validating...");
  ValidationUtils.rejectIfEmptyOrWhitespace(errors, "type", "errors.empty.type","error occur");
 }

}

Step-3: Create a Controller class


ContactController is a controller that makes use of a Validator to validate instances of Contact.
In this controller i use two annotations:
  • @InitBinder(value = "contact") to bind the object of type Contact whose name is contact and to register a custom validator for instances of Contact class.
  • @Valid to validate binding instance of Contact class with the Validator registered

If errors occur the controller returns to form View otherwise it returns to result.

ContactController.java

package com.simonefolinojavablog.spring.controller;

import javax.validation.Valid;

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

import com.simonefolinojavablog.spring.bean.Contact;
import com.simonefolinojavablog.spring.validator.ContactValidator;

@Controller
@RequestMapping(value = "/contacts")
public class ContactController {

 @InitBinder(value = "contact")
 protected void initBinder(WebDataBinder binder) {
  binder.setValidator(new ContactValidator());
 }

 @RequestMapping(value="/save",method = RequestMethod.POST)
 public String saveContact(@ModelAttribute(value = "contact") @Valid Contact contact,BindingResult errors, ModelMap modelMap) {
  
  if (errors.hasErrors()) {
   System.out.println("some errors occur");
   return "form";
  }
  return "result";
 } 
}

Step-4: Create an errors.properties file


We have to create a file that contains error messages, and declare the location of this file in Spring configuration.

errors.properties
errors.empty.number=number field is empty
errors.empty.type=type field is empty
typeMismatch.contact.number=type mismatch Contact Number
typeMismatch.java.lang.NumberFormatException=5. Invalid value for {0}, accepts only numbers. 
typeMismatch.java.lang.Integer=Must specify an integer value. 
typeMismatch.java.lang.Long=Must specify an integer value. 
typeMismatch.java.lang.Float=Must specify a decimal value. 
typeMismatch.java.lang.Double=Must specify a decimal value.  
typeMismatch.int=Invalid number entered 
typeMismatch=Invalid type entered

In Spring configuration we use a special bean called ResourceBundleMessageSource that points the properties files managed by Spring context.

spring-mvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

 <context:annotation-config />

 <context:component-scan base-package="com.simonefolinojavablog.spring" />

 <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
     <property name="basenames">
      <list>
       <value>errors</value>
      </list>
     </property>
    </bean>
      ...

</beans>


Step-5: Put into web.xml the information to load the root web application context


As you can see, we have to declare ContextLoaderListener because we need to load the root application context and not just the web application context. I'm going to speak about the difference between root application context and web application context in another post.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>SpringMVCValidator</display-name>
   <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:META-INF/spring/springcontext-*.xml</param-value> 
   </context-param>
   <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
   </listener>  
   <servlet>
        <servlet-name>SpringMVCValidator</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring/spring-mvc.xml</param-value>
        </init-param>
          <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
         <servlet-name>SpringMVCValidator</servlet-name>
         <url-pattern>*.htm</url-pattern>
    </servlet-mapping>

</web-app>

No comments :

Post a Comment

Suggested Pages