Creating forms and validating it, in a web application, is an inevitable task which no developer can get away with. In this part we will learn how to get our form validated by Struts2 ( Manually ).

What we will learn this part ?

  1. The different ways Struts2 can provide validation.
  2. Learn manual validation and the components in Struts2 that helps validating forms manually.

Objective: We take the last tutorials code and add manual validation.

In strtus2 we can validate in two different ways .

Manual validation: Which is pretty much like validating each field by hand or in other words writing logic to validate your fields in context.

Automatic Validation: This makes use of out of box validation framework, with this a developer doesn’t have to write even single line of Java code (in most cases), just few configuration to do and done. We will take this discussion to the later tutorials.

So lets start with manual validation.This part takes code and objective from the last tutorial and adds validation to it, So if you don't understand something in this part , come back after reading the last part.

Requisites for manual validation: 

  1. Make sure defaultStack or your package must extend the "struts-default". The defaultStack, has all the necessary interceptors in place to make your validation workflow. Remember validation and workflow interceptors are must for Struts2 validation.
  2. Make your action classes either extend the ActionSupport or implements ValidationAware and Validatable interfaces. The Validatable interface provides a validate() method as contract which we would override and ValidationAware provides contracts likeaddFieldError,addActionError and few more and upon overriding those struts will do the necessary arrangement for managing ( displaying, adding errors ) in our development components. Many don't go with the implementation approach since it is too much of work, rather they make the Actions extends the ActionSupport class which does implements these two interfaces.
  3. Override the public void validate() method , with your logic that validates each of the fields , and use addFieldError() method for mapping your fields to the error message.

Lets start with a sequence diagram on the flow we want to achieve

Rough validation flow in struts2

 

Lets have a look at the struts.xml

<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
    <package name="test" namespace="" extends="struts-default">
        <action name="userRegForm"  class="com.bullraider.app.validation.ManualValidationAction" method="getUserRegistrationForm">
            <interceptor-ref name="defaultStack">
            <param name="validation.excludeMethods">getUserRegistrationForm</param>
            </interceptor-ref>
            <result name="success">/UserRegistrationForm.jsp</result>
        </action>
        <action name="registerUser"  class="com.bullraider.app.validation.ManualValidationAction" method="registerUser">
            <result name="input">/UserRegistrationForm.jsp </result>
            <result name="success">/WelcomeUser.jsp</result>
        </action>
    </package>
</struts>


We followed the first rule given above by extending "struts-default"  in our package. As you can see the userRegForm.action maps to the getUserReigstrationForm , and since we don't want to do validation while requesting the form , we excluded the validation to be performed.And in the other action registerUser.action  which needs fields to be validated, we did not restrict the validation here, and the results like "input" when there is any error with the validation maps to the UserRegistrationForm.jsp where the user will see the mistakes while submiting the form and the resutlt sucess when the validation passes fine , mapped to the WelcomeUser.jsp page.

Our action ManualValidationAction.java looks like below.

package com.bullraider.app.validation;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.Preparable;
import com.opensymphony.xwork2.Validateable;
import com.opensymphony.xwork2.ValidationAware;

public class ManualValidationAction extends ActionSupport implements Preparable {

   //For brevity other methods and fields are removed, download the source code to see all

// or visit the last article
    public void validate(){
        //Username can't be blank
        if(username.equals("")){
            addFieldError("username", "The Username can't be empty");
        }
        //password must not be blank , and it should be more than 6 characters
        if(password.equals("")){
            addFieldError("password","The Password can't be empty");
        }else if(password.length()<6){
            addFieldError("password","Password must be minimum of 6 characters");
        }
        // Email must not be blank , and it should be follow the pattern of email address
        if(email.equals("")){
            addFieldError("email","The Email can't be empty");
        }else{
            String  expression="^[\\w\\-]([\\.\\w])+[\\w]+@([\\w\\-]+\\.)+[A-Z]{2,4}$";
               CharSequence inputStr = email;
               Pattern pattern = Pattern.compile(expression,Pattern.CASE_INSENSITIVE);
               Matcher matcher = pattern.matcher(inputStr);
               if(!matcher.matches())
                   addFieldError("email","Invalid email address");
        }
    }
}

 

Our Action class  follows the rule number 2 by extending the ActionSupport and we talk about the Preparable interface in the last chapter. It has also a validate method which validates each of the fields for example checks for emptiness, length and email pattern validation and uses the addFieldError() method which maps the fields and the error message to be displayed when in error.The validate method doesn't return you any boolean field, it is because the interceptors checks if there are any field error after executing the validate method. Also notice that the registerUser return only success , it doesn't even call the validate method nor it returns any "input" String. It is taken care of the interceptor.

Lets have little discussion about the JSP pages.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>User Registration Form</title>
<s:head />
</head>
<body>
<s:form name="registerform" action="registerUser">
    <s:textfield name="username" label="User Name" required="true" />
    <s:password name="password" label="Password" required="true" />
    <s:textfield name="email" label="Email Id" required="true" />
    <s:radio label="Sex" list="sexValues" name="sex"></s:radio>
    <s:checkboxlist label="Interests" list="interestValues"
        name="interests">
    </s:checkboxlist>
    <s:select list="countryValues" name="country" label="Country"></s:select>
    <s:submit />
</s:form>
</body>
</html>

We don't have anything special here , the <s:head> tags adds the necessary css and js ( Not client side validation code,js is used for manipulating the dom elements here, Manual validation doesn't add client side validation ) code that is necessary to make our form look appropriate ( like marking the fields labels appear red).

And finally the WelcomeUser.jsp page which displays the inputs given ie the user details

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
    <%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
Hi <s:property value="username"/><br/>
You are a: <s:property  value="sex" /><br/>
Your Email Id: <s:property value="email"/><br/>
You Belong to: <s:property value="country"/> <br/>
Your Interests are: <s:property value="interests"/>
</body>
</html>

Download the source code ManualValidation.war

Well we are done with the manual validation , but it A manual validation is too much of work, and come with the following disadvantages.

  1.  A minor change in validation logic/rule will force you to compile the Action code, and go through the process(develope,deploy , etc).
  2. Server side validation is not the only thing in web application, with this case you will have to write the client side validation i.e JavaScript code by hand.And do a little bit of work on having both serverside and client side validation code to be synced up.

A manual validation will solve these two problems we will see next tutorial.

The Flow in Slow: This flow only depicts the validation work , for userRegForm.action see last tutorial.

Step 1:  The user fills the  form and submits the form to registerUser.action

Step 2: The Action ManualValidationAction is created, and the PrepareInterceptor executes and the fields on the Action assigned the values of the user inputs.

Step 3: The Validation Interceptor executes the validate() method.[Remember it is not our Action who calls the validate() method.]

Step 4: As the validate() method returns back to the validation interceptor,he workflow interceptor executes  next , and it checks if there is any error i.e by checking if any field error is present.[Remember: validate() method doesn't return boolean]

Step 4.1:  if error present it returns the "input" as result and the post-processing occures ie all the interceptors before validation interceptor executes and finally see Step 5.

Step 4.2: If the result is  no error is detected  the flow continue  executing other interceptor on path and finally executes action method registerUser() and then it returns "success" finally see Step 5.

Step 5: Depending on what is the result , "input": UserRegistrationForm.jsp or if "success" : WelcomeUser.jsp is displayed to the user.