I'm validating a simple form using Spring and Hibernate in JSP (using SimpleFormController
) with the help of HibernateValidator
as explained here. The form containing only one field is as follows.
<%@page contentType="text/html" pageEncoding="UTF-8" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<form:form method="post" id="userForm" name="userForm" action="Temp.htm" commandName="validationForm">
<table>
<tr>
<td>User Name:<font color="red"><form:errors path="userName" /></font></td>
</tr>
<tr>
<td><form:input path="userName" /></td>
</tr>
<tr>
<td><input type="submit" value="Submit" /></td>
</tr>
</table>
</form:form>
The following is the command class in which validation criteria is defined.
package validators;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.NotEmpty;
final public class ValidationForm
{
@NotEmpty(message="Must not be left blank.")
@Size(min = 1, max = 2)
private String userName;
public void setUserName(String userName)
{
this.userName = userName;
}
public String getUserName()
{
return userName;
}
}
The following is the dispatchar-servlet.xml
file where different configurations can be made.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-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">
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
<bean id="tempService" class="usebeans.TempServiceImpl" />
<bean id="tempController" class="controller.Temp" p:tempService-ref="tempService" p:formView="Temp" p:successView="Temp"/>
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="/WEB-INF/messages" />
</bean>
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="index.htm">indexController</prop>
<prop key="Temp.htm">tempController</prop>
</props>
</property>
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp" />
<bean name="indexController"
class="org.springframework.web.servlet.mvc.ParameterizableViewController"
p:viewName="index" />
Where TempService
is an interface containing only one method add(ValidationForm validationForm){...}
and the TempServiceImpl
is a class which implements the TempService
interface.
The controller class Temp
is as follows.
package controller;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
import usebeans.TempService;
import validators.ValidationForm;
@SuppressWarnings("deprecation")
final public class Temp extends SimpleFormController
{
private TempService tempService=null;
public Temp()
{
setCommandClass(ValidationForm.class);
setCommandName("validationForm");
}
//This method may not be necessary.
public void setTempService(TempService tempService)
{
this.tempService = tempService;
}
@Override
protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, @ModelAttribute("validationForm") @Valid Object command, BindException errors) throws Exception
{
ValidationForm validationForm=(ValidationForm) command;
tempService.add(validationForm); //May not be necessary.
if(errors.hasErrors()) //Never evaluates to true even though the text box on the form is left blank.
{
System.out.println("User Name : "+validationForm.getUserName());
//Or do something.
}
else
{
//Do some stuff such as database operations like insert, update or delete.
}
ModelAndView mv=new ModelAndView("Temp", "validationForm", validationForm);
return mv;
}
@Override
protected ModelAndView showForm(HttpServletRequest request, HttpServletResponse response, BindException errors) throws Exception
{
ModelAndView mv=new ModelAndView("Temp", "validationForm", new ValidationForm());
return mv;
}
}
Now, what is happening here is that when the form is submitted on clicking the only submit button on the form, the onSubmit()
method in the controller class Temp
is invoked in which I'm imposing an if
condition if(errors.hasErrors()){}
.
Accordingly, if the only TextField on the form is empty, the form which is rendering contains validation errors and the if
condition should be evaluated to true and the specified error message should be displayed (as specified in the ValidationForm
class @NotEmpty(message="Must not be left blank.")
) but this never happens [The object of the ValidationForm
is available through the Object command
parameter of the onSubmit()
method]. The condition never evaluates to true whether or not the text box contains a value.
What am I missing here? I feel that I'm following the wrong way to use HibernateValidator
. Any hints or guidelines would be helpful to me.
[The application runs with no errors but the form which is intended to be validated isn't validated]
Putting @Valid on method params doesn't work with old-fashioned controllers that extend from CommandController
and its children (e.g., SimpleFormController
). It is a feature of the AnnotationMethodHandlerAdapter
, so you need to be using annotated controller for it to work.
(There is a reason you had to suppress a deprecation warning on that class! :) )
Reader's digest version:
Instead of defining your own urlMapping and everything in the dispatcher use <mvc:annotation-driven/>
Then instead of extending from SimpleFormController you just make a regular class and annotate it with @Controller and your method with @RequestMapping.
@Controller
@RequestMapping("/Temp.htm")
public class Temp {
@RequestMapping(method=RequestMethod.GET)
public ModelAndView getForm() {
ModelAndView mv=new ModelAndView("Temp", "validationForm", new ValidationForm());
return mv;
}
@RequestMapping(method=RequestMethod.POST)
public ModelAndView postForm(@Valid ValidationForm validationForm, BindingResult errors) {
tempService.add(validationForm); //May not be necessary.
if(errors.hasErrors()) //Never evaluates to true even though the text box on the form is left blank.
{
System.out.println("User Name : "+validationForm.getUserName());
//Or do something.
}
else
{
//Do some stuff such as database operations like insert, update or delete.
}
ModelAndView mv=new ModelAndView("Temp", "validationForm", validationForm);
return mv;
}
There are tons of tutorials on the internet with way more content than I can reproduce here. Check out the current version of the Spring PetClinic sample application for detailed examples.