Meyyappan has posted 101 posts at DZone. View Full User Profile

Struts 2 Hibernate Validation Tutorial

06.15.2012
| 21754 views |
  • submit to reddit

The Hibernator Validator framework follows the DRY (Don't Repeat Yourself) principle. Using Hibernator Validator you need to specify the constraints using annotations in the domain object. Once you specify the constraints you can use it in any layer of your application without duplicating it.

Hibernate Validator comes with basic buit-in constraints like @Length(min=, max=), @Max(value=), @Min(value=), @NotNull, @NotEmpty and so on. You can also build your own constraints easily.

In this example you will see how to integrate Struts 2 with Hibernator Validator using the Full Hibernate Plugin 1.4 GA.

You need to have all the lib files that we used in the previous example ( Struts 2 Hibernate Integration ).

The domain object User, with the validation constraints is shown below.

package com.vaannila.domain;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.validator.Length;
import org.hibernate.validator.NotEmpty;

@Entity
@Table(name = "USER")
public class User implements Serializable {

	private static final long serialVersionUID = 6295524232169619097L;

	private Long id;

	private String name;

	private String password;

	private String gender;

	private String country;

	private String aboutYou;

	private Boolean mailingList;

	@Id
	@GeneratedValue
	@Column(name = "USER_ID")
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	@NotEmpty
	@Length(max=50)
	@Column(name = "USER_NAME", nullable = false, length = 50)
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	@Length(min=6, max=10)
	@Column(name = "USER_PASSWORD", nullable = false, length = 10)
	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}
	
	@NotEmpty(message="Please select a gender")
	@Column(name = "USER_GENDER")
	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}
	
	@NotEmpty(message="Please select a country")
	@Column(name = "USER_COUNTRY")
	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}
	
	@NotEmpty
	@Length(max=100)
	@Column(name = "USER_ABOUT_YOU", length = 100)
	public String getAboutYou() {
		return aboutYou;
	}

	public void setAboutYou(String aboutYou) {
		this.aboutYou = aboutYou;
	}

	@Column(name = "USER_MAILING_LIST")
	public Boolean getMailingList() {
		return mailingList;
	}

	public void setMailingList(Boolean mailingList) {
		this.mailingList = mailingList;
	}

}

As you can see in addition to the JPA annotations you have the Hibernator Validator constraints.

The @NotEmpty constraint checks if the String is not null or not empty.

The @Length(min=6, max=10) constraint checks whether the lenght is within the min max range.

The validation messages are auto generated by the plug-in. You can also override the default message using the message attribute of the constraint. For gender and country properties we specify a customized message.

@NotEmpty(message="Please select a gender")
@Column(name = "USER_GENDER")
public String getGender() {
    return gender;
}

@NotEmpty(message="Please select a country")
@Column(name = "USER_COUNTRY")
public String getCountry() {
    return country;
}

In the UserAction class you need to specify the @Valid annotation for the domain object that needs to be validated.

package com.vaannila.web;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.validator.Valid;

import com.opensymphony.xwork2.ActionSupport;
import com.vaannila.dao.UserDAO;
import com.vaannila.dao.UserDAOImpl;
import com.vaannila.domain.User;

public class UserAction extends ActionSupport {

	private static final long serialVersionUID = -6659925652584240539L;

	@Valid
	private User user;
	private List<User> userList = new ArrayList<User>();
	private UserDAO userDAO = new UserDAOImpl();
		
	public String add()
	{		
		userDAO.saveUser(user);
		return SUCCESS;
	}
	
	public String list()
	{
		userList = userDAO.listUser();
		return SUCCESS;
	}
		
	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	public List<User> getUserList() {
		return userList;
	}

	public void setUserList(List<User> userList) {
		this.userList = userList;
	}

}

Since we use the Hibernate Plugin you need to extend the package form hibernate-default package. The hibernate-default package has the following three interceptor stacks.

 

  • basicStackHibernate: Struts2 basickStack + Hibernate session and transaction capability.
  • defaultStackHibernate: Struts2 defaultStack (no validations) + Hibernate validation, session and transaction capability.
  • defaultStackHibernateStrutsValidation: Struts2 defaultStack (with validation) + basicStackHibernate.

The struts configuration file is shown below.

<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
	<package name="default" extends="hibernate-default">
		<action name="addUser" method="add" class="com.vaannila.web.UserAction">
			<result name="input">/register.jsp</result>
			<result name="success" type="redirect">listUser</result>
		</action>
		<action name="listUser" method="list" class="com.vaannila.web.UserAction">
			<interceptor-ref name="basicStackHibernate" />
			<result name="success">/register.jsp</result>
		</action>
	</package>
</struts>

By default the defaultStackHibernate interceptor stack will be used. In the addUser action we use this inteceptor stack since we need validation capability and during the listUser action action we use basicStackHibernate because we don't need validation capability this time.

In the register.jsp page instead of using the name attribute to specify the property value we use the key attribute. This is need for the default validation messages to be generated.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@taglib uri="/struts-tags" prefix="s"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Registration Page</title>
<s:head />
<style type="text/css">
@import url(style.css);
</style>
</head>
<body>
<s:actionerror/>
<s:form action="addUser">
	<s:hidden name="user.id" />
	<s:textfield key="user.name" />
	<s:password key="user.password" />
	<s:select key="user.gender" list="{'Male','Female'}" headerKey=""
		headerValue="Select" label="Gender" />
	<s:select key="user.country" list="{'India','USA','UK'}" headerKey=""
		headerValue="Select" label="Country" />
	<s:textarea key="user.aboutYou" />
	<s:checkbox key="user.mailingList"
		label="Would you like to join our mailing list?" />
	<s:submit />
</s:form>


<s:if test="userList.size() > 0">
	<div class="content">
	<table class="userTable" cellpadding="5px">
		<tr class="even">
			<th>Name</th>
			<th>Gender</th>
			<th>Country</th>
			<th>About You</th>
			<th>Mailing List</th>
		</tr>
		<s:iterator value="userList" status="userStatus">
			<tr
				class="<s:if test="#userStatus.odd == true ">odd</s:if><s:else>even</s:else>">
				<td><s:property value="name" /></td>
				<td><s:property value="gender" /></td>
				<td><s:property value="country" /></td>
				<td><s:property value="aboutYou" /></td>
				<td><s:property value="mailingList" /></td>
			</tr>
		</s:iterator>
	</table>
	</div>
</s:if>
</body>
</html>

The key values should be specified in the UserAction.properties file and this file should be saved next to the UserAction.java file.

user.name=User Name
user.password=Password
user.aboutYou=About You
user.mailingList=Mailing List

The default validation messages will be generated using the field labels as prefix.

When you execute the example and submit the form without entering any values you will see the following validation messages.

The validation messge for the fields User Name, Password and About You has the field label before the default validation error message. This is because we specified the key values in the UserAction.properties file. If you only want the validation message to be displayed then don't specify an entry for that field in the properties file. Here the gender and the country fields have only the customized error messages and not the field labels.

Everything else remains the same as the previous example ( Struts 2 Hibernate Integration ).

You can download and try this example here.

Source :Download (15 KB)
Source + Lib :Download (9.8 MB)

 

 

Published at DZone with permission of its author, Meyyappan Muthuraman.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags: