Struts 2.0 + Hibernate Validation
As long as you are feeling lazy to write code…you are on the right track.
-Vamshi.Somanchi
Objectives:
-
Struts2.0 validation?
-
Hibernate validator?
-
POJO class?
-
How to write them as a Frame Work?
-
Why should you appreciate me???
Struts 2.0 Validation
Struts 2 supports manual validation via the validate method and the XWork Validation framework. The Xwork Validation Framework supports chaining validation into sub-properties using the validations defined for the properties class type and the validation context.
Telling you in simple terms Struts 2.0 have inbuilt functionalities to validate the Parameters.
The Struts 2 validation framework uses xml based configuration file. The file name should be <Your action class> -validation.xml. Lets say our action class name is Login.java, so our validation configuration file will be Login-validation.xml.
| <?xml version=”1.0″ encoding=”UTF-8″?><!DOCTYPE validators PUBLIC ”-//OpenSymphony Group//XWork Validator 1.0.2//EN” “http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd“><validators>
<field name=”username”> <field-validator type=”requiredstring”> <param name=”trim”>true</param> <message>Login name is required</message> </field-validator> </field> <field name=”password”> <field-validator type=”requiredstring”> <param name=”trim”>true</param> <message>Password is required</message> </field-validator> </field> </validators> |
There are two functions which are provided by the Action class they are catching the “action errors” and “field errors”.
Action errors are Server side validation.
Field errors are client side validation.
Thing to be observed here is if you have some set of forms we need to write same number of validator.xml files in order to handle them.
Hibernate
Hibernate is a solution for object relational mapping and a persistence management solution or persistent layer. This is probably not understandable for anybody learning Hibernate.
What you can imagine is probably that you have your application with some functions (business logic) and you want to save data in a database. When you use Java all the business logic normally works with objects of different class types. Your database tables are not at all objects.
Hibernate provides a solution to map database tables to a class. It copies the database data to a class. In the other direction it supports to save objects to the database. In this process the object is transformed to one or more tables.
Saving data to storage is called persistence. And the copying of tables to objects and vice versa is called object relational mapping.
Hibernate Validator
Following the DRY (Don’t Repeat Yourself) principle, Hibernate Validator let’s you express your domain constraints once (and only once) and ensure their compliance at various level of your system automatically.
Hibernate Validator comes bundled with a set of common validations (@NotNull, @Email, @Max, and so on), and you can build you own validation rules very easily
POJO
POJO is an acronym for Plain Old Java Object, and is favored by advocates of the idea that the simpler the design, the better. The name is used to emphasize that the object in question is an ordinary Java Object, not a special object, and in particular not an Enterprise Java Bean(especially before EJB 3).
These are the brief descriptions.
Integrating all these as a Frame Work.
Web-based application is developed Using a Struts 2.0 Frame work now …. Now what is this I am going to integrate?
Hibernate validation what we have discussed above has to be integrated into our application.
Hidden secret of this document is very simple … we can avoid JavaScript for basic validations.
Integration is not complicated understand each and every point in that…..
Step 1:
Our POJO class parameters has to be defined with the hibernate validations
Like this…
|
import org.hibernate.validator.AssertTrue; import org.hibernate.validator.Email; import org.hibernate.validator.Length; import org.hibernate.validator.NotEmpty; import org.hibernate.validator.NotNull; import org.hibernate.validator.Pattern;
public class EbookUsers implements Serializable {
private Integer userId;
@NotEmpty(message = “{ebookUsers.firstName}”) @Pattern(regex=“[A-Za-z]+”,message=“{ebookUsers.firstName}”) @Length(min = 3 , max = 25 ,message= “{ebookUsers.firstName}”)
private String firstName;
@NotEmpty(message = “{ebookUsers.lastName}”) @Pattern(regex=“[A-Za-z]+”,message=“{ebookUsers.lastName}”) @Length(min = 3 , max = 25 ,message= “{ebookUsers.lastName}”)
private String lastName;
@NotEmpty(message = “{ebookUsers.loginName}”) @Pattern(regex=“[0-9a-zA-Z]+”,message=“{ebookUsers.loginName}”) @Length(min = 6, max = 25, message = “{ebookUsers.loginName}”)
private String loginName;
@NotEmpty(message = “{ebookUsers.passWord}”) @Length(min = 6, max = 10, message = “{ebookUsers.passWord}”)
private String passWord;
private String street;
private String city;
private String state;
private String country;
@Pattern(regex=“^([0-9a-zA-Z]([-\\.\\w]*[0-9a-zA-Z])*@(([0-9a-zA-Z])+([-\\w]*[0-9a-zA-Z])*\\.)+[a-zA-Z]{2,9})$”,message=“{ebookUsers.email}”) @NotEmpty(message = “{ebookUsers.email}”)
private String email;
@NotEmpty(message = “{ebookUsers.phone}”) @Pattern(regex=“[0-9]+”,message=“{ebookUsers.phone}”) @Length(min = 10, max = 10, message = “{ebookUsers.phone}”) private String phone;
@NotEmpty(message = “{ebookUsers.mobile}”) @Length(min = 10, max = 10, message = “{ebookUsers.mobile}”) @Pattern(regex=“[0-9]+”,message=“{ebookUsers.mobile}”) private String mobile;
private int failedAttempts;
@Length(min = 5 , max = 5 , message = “{ebookUsers.zip}”) @Pattern(regex=“[0-9]+”,message=“{ebookUsers.zip}”) private String zip; } //powered by vamshi.somanchi |
|
|
The above class have a User Information.
I have used those what I need total annotations available are listed below.
|
Annotation |
Apply on | Runtime checking | Hibernate Metadata impact |
|---|---|---|---|
|
@Length(min=, max=) |
property (String) | check if the string length match the range | Column length will be set to max |
|
@Max(value=) |
property (numeric or string representation of a numeric) | check if the value is less than or equals to max | Add a check constraint on the column |
|
@Min(value=) |
property (numeric or string representation of a numeric) | check if the value is more than or equals to min | Add a check constraint on the column |
|
@NotNull |
property | check if the value is not null | Column(s) are not null |
|
@NotEmpty |
property | check if the string is not null nor empty. Check if the connection is not null nor empty | Column(s) are not null (for String) |
|
@Past |
property (date or calendar) | check if the date is in the past | Add a check constraint on the column |
|
@Future |
property (date or calendar) | check if the date is in the future | none |
|
@Pattern(regex=”regexp”, flag=) or @Patterns( {@Pattern(…)} ) |
property (string) | check if the property match the regular expression given a match flag (see java.util.regex.Pattern ) | none |
|
@Range(min=, max=) |
property (numeric or string representation of a numeric) | check if the value is between min and max (included) | Add a check constraint on the column |
|
@Size(min=, max=) |
property (array, collection, map) | check if the element size is between min and max (included) | none |
|
@AssertFalse |
property | check that the method evaluates to false (useful for constraints expressed in code rather than annotations) | none |
|
@AssertTrue |
property | check that the method evaluates to true (useful for constraints expressed in code rather than annotations) | none |
|
@Valid |
property (object) | perform validation recursively on the associated object. If the object is a Collection or an array, the elements are validated recursively. If the object is a Map, the value elements are validated recursively. | none |
|
|
property (String) | check whether the string is conform to the email address specification | none |
|
@CreditCardNumber |
property (String) | check whether the string is a well formated credit card number (derivative of the Luhn algorithm) | none |
|
@Digits |
property (numeric or string representation of a numeric) | check whether the property is a number having up to integerDigits integer digits and fractionalDigits fractonal digits | define column precision and scale |
|
@EAN |
property (string) | check whether the string is a properly formated EAN or UPC-A code | none |
|
@Digits |
property (numeric or string representation of a numeric) | check whether the property is a number having up to integerDigits integer digits and fractionalDigits fractonal digits | define column precision and scale |
Each and every annotation is designed with a requirement this will be very clear if you observe the Coloum Apply On.
There is one special annotation named @Pattern this will allow the developer to add the “Regular expression”. Example can be seen in EbookUsers class.
These annotations hold the properties of the parameters throughout the application, and can be crosschecked where ever necessary.
Step 2:
Write a properties file to define the errors messages. Parameter identification should be done with “POJO class object . Parameter name” (this is just for a good practice)
for example:
@NotEmpty(message = “{ebookUsers.phone})”
Private String phone;
Here I am giving the properties files for the above mentioned POJO class.
|
EBOOKUSERS START HERE
ebookUsers.firstName=Enter First Name. It should be minimum of ‘3′ characters and maximum of ‘25′ characters. ebookUsers.lastName=Enter Last Name. It should be minimum of ‘3′ characters and maximum of ‘25′ characters. ebookUsers.loginName=Enter User Name. It should be minimum of ‘6′ characters and maximum of ‘25′ characters. ebookUsers.passWord=Enter Password. It should be minimum of ‘6′ characters and maximum of ‘10′ characters. ebookUsers.phone=Enter Phone Number. It should be exactly of ‘10′ Numbers (eg:xxxxxxxxxx) ebookUsers.mobile=Enter Mobile Number. It should be exactly of ‘10′ Numbers (eg:xxxxxxxxxx) ebookUsers.email=Enter proper Email ID (eg:ebook@emantras.com) ebookUsers.zip=Zip should be exactly of ‘5′ numbers. ebookUsers.city=City should be minimum of ‘3′ characters and maximum of ‘25′ characters. ebookUsers.state=State should be minimum of ‘3′ characters and maximum of ‘25′ characters. ebookUsers.country=Country should be minimum of ‘3′ characters and maximum of ‘25′ characters. ebookUsers.street=Street should be minimum of ‘3′ alphanumeric characters and maximum of ‘25′ alphanumeric characters.
EBOOKUSERS END HERE //Powered by vamshisomanchi |
Step 3:
We need to write a class which will act like a centralized wire between pojo class and properties file.
This is necessary because we cant load properties file where ever we need that is again a bad practice.
Let’s name this class as EbookValidation.
This class basically loads the messages from properties file based on the class name and the message name and loads that errors in Invalidvalues class we can retrive these errors messages and add them to struts error messges which inturn will display in the JSP page.
This is how we write the Validation.
|
import java.io.File; import java.io.FileInputStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle;
import org.hibernate.validator.ClassValidator; import org.hibernate.validator.InvalidValue;
public class EbookValidation {
Collection errors = null;
public Collection validate(Class clazz, Object obj) {
InvalidValue[] invalidValues = null; try { errors = new HashSet(); ClassValidator classValidator = new ClassValidator(clazz, loadproperties()); invalidValues = classValidator.getInvalidValues(obj); // System.err.println(” invalidValues “+invalidValues); for (int i = 0; i < invalidValues.length; i++) {
errors.add(invalidValues[i].getMessage().trim()); } } catch (Exception e) { e.printStackTrace(); } return errors; }
public ResourceBundle loadproperties() { String baseName = “ebook”; // ebook.properties is properties file name ResourceBundle rb = null; try { // Get the resource bundle for the default locale rb = ResourceBundle.getBundle(baseName); } catch (MissingResourceException e) { // The resource bundle cannot be found or // the key does not exist in the resource bundle } return rb; } } //Powered by Vamshi.Somanchi |
Step 4:
This is where we write our controller to do some operations with the POJO class.
Lets say for example I am planning to insert my user values into the database.
|
public String editUserProfile(){ String pageEditUser=“EditUser”; roles=new Roles(); Collection err = this.getEbookValidation().validate(EbookUsers.class,getEbookUsers());
// this is where we load the properties file using Class
if (err.size() > 0){ //this happens if errors are collected. this.setActionErrors(err); //this line sets the action errors. return Action.ERROR; //returns to the error page } else (xyz bla bla bla){ do the insertion operation. } return Action.SUCCESS;
} |
|
|
Now values are collected and these collected values will be displayed in JSP with the following strus tags
|
<%@ taglib prefix=“s” uri=“/struts-tags” %> <html> <head> </head> <body> <!– error will be loaded here with the following tag–> <s:div cssClass=“your wish”><s:actionerror/></s:div>
This is you body page and … .. . </body>
</html>
|
All the collected error messges will be displayed one after the other.
—–***THE END***——-