Posts Tagged ‘struts

27
Mar
11

Preventing XSS using commons validator

This page describes the process of validating html submitted form to prevent a Cross Site Scripting attack using commons validator.

Background

Adding input validation to your application adds an extra layer of security however its only the second best method to protect against cross site scripting attacks.[1]

The best method is to is to encode the output before displaying it to the user.[2]

Regardless, adding more layers of security doesn’t hurt.

Approach

The approach taken here is to white-list characters that are allowed to be entered by creating a custom validator. Developers can use “mask” rule however this

  1. clutters up the validator.xml file
  2. could possibly interfere with a a field’s existing mask rule

Requirements

  1. Successful completion of my previous post

Procedure

We will be re-using the project created in my previous post. Or you can skip the implementation and just follow along below.

Create a Custom Validator

The following class extends the FieldChecks class provided by the struts framework. The extra method is based on the mask method of the parent class. The only difference is that the mask pattern is hard coded into the implementation of the method.

src/main/java/com/test/InfoSecurityChecks.java

package com.test;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.validator.Field;
import org.apache.commons.validator.GenericValidator;
import org.apache.commons.validator.ValidatorAction;
import org.apache.commons.validator.ValidatorUtil;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.validator.FieldChecks;
import org.apache.struts.validator.Resources;

public class InfoSecurityChecks extends FieldChecks {
	private static final long serialVersionUID = 1L;
	private static final Log log = LogFactory.getLog(InfoSecurityChecks.class);

	public InfoSecurityChecks() {
		super();
	}

	/**
	 * The code for this method was taken from the mask method of the parent
	 * class. The mask regular expression has been hard coded to only allow
	 * characters that are approved.
	 *
	 */
	public static boolean validateInfoSec(Object bean, ValidatorAction va,
			Field field, ActionErrors errors, HttpServletRequest request) {
		System.out.println("infosec validator ran");
		// The following is allowed
		// alpha numeric characters and space
		// special characters except < > ( )
		String mask = "^[A-Za-z0-9!\"\\\\#$%&'*+,/:;=\\.?@_\\`{\\|}\\~\\-\\^ ]*$";
		String value = null;
		if (isString(bean))
			value = (String) bean;
		else {
			value = ValidatorUtil.getValueAsString(bean, field.getProperty());
		}
		System.out.println(value);
		try {
			if ((!(GenericValidator.isBlankOrNull(value)))
					&& (!(GenericValidator.matchRegexp(value, mask)))) {
				errors.add(field.getKey(), Resources.getActionError(request,
						va, field));
				System.out.println("did not match returning false.");
				return false;
			}
			return true;
		} catch (Exception e) {
			 log.error(e.getMessage(), e);
		}
		return true;
	}
}

Modify the Validator Rules

Modify the validator-rules.xml and add an additional “validator” section towards the end.

src/main/webapp/WEB-INF/validator-rules.xml

      <validator name="infosec"
            classname="com.test.InfoSecurityChecks"
               method="validateInfoSec"
         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"
                  msg="errors.infosec">
      </validator>

Add the following new line to the application.properties

src/main/resources/application.properties

errors.infosec=The input contains invalid characters.

Modify the validation.xml and add “infosec” to the end of the depends attribute of the “lastName” attribute of the “userInformation” form.

src/main/webapp/WEB-INF/validation.xml

    <field property="lastName" depends="required,infosec">
        <arg key="userInformation.lastName" />
    </field>

Test the application

Return to the project top level directory and execute the following command to start the jetty servlet engine.

mvn clean compile jetty:run

Navigate to the following URL:
http://localhost:8080/

An extJS form should display allowing you to enter values. Click submit and an Ajax form submission will be made to the Struts Action. Any validation failures will show next to the component.

Try entering a <script>alert(‘test xss’);</script> in the last name field.

System should display a validation failure message indicating that there are invalid characters in the input.

References

[1] XSS (Cross Site Scripting) Prevention Cheat Sheet
[2] http://www.ibm.com/developerworks/web/library/wa-secxss/

27
Mar
11

ExtJS form validation using commons-validator

This page describes the process of using commons-validator to validate extJS form submissions.

Background

Commons validation is a mature project that’s been out there for a while now. It became popular when it was introduced as part of the Struts framework. Commons validation allows developers to specify validation rules inside XML files, thus allowing them to be applied uniformly across the site. In addition the same set of rules can be used to generate both client side and server side validation thus reducing maintenance cost.

In the interest of brevity, this page will only cover the server side validation.

Using commons-validator by itself doesn’t give you much benefit. All you get is the ability to specify rules and validation logic that returns whether the validation passed or failed.

You are left on your own to:

  1. Write your own code to iterate thru the form fields and collect the failure messages
  2. Write a servlet to handle requests over HTTP and present the failure messages back to the client
  3. Internationalization Support

Although its not that much work, when you start implementing it you quickly realize that this boiler plate code is something that a framework should provide.

This boiler plate code has been written years ago by the makers of the Struts framework. By extending the framework slightly, we can use it to validate forms submitted by extJS components.

Struts comes pre-packaged with the “html:errors” tag. Upon validation failures struts returns the user back to the “input” page and the input page contains a “html:errors” tag that displays the failed validation along with a description of the failure in HTML format.

The Approach

The approach presented here focues on extending the “html:errors” tag to return JSON instead of html. The JSON is parsed by the extJS formPanel and the errors are presented to the user.

On success the extJS formPanel expects:

{success: true, msg : 'Thank you for your submission.'}

On failure the extJS formPanel expects:

{
   success : false,
   msg     : 'This is an example error message',
   errors  : {
      firstName : 'Sample Error for First Name',
      lastName  : 'Sample Error for Last Name'
   }
}

Note:
Some of the code on this page are not core to the understanding “approach”, for this reason the code will initially be collapsed.

Requirements

Since this page is about integrating 3 different technologies together a basic understanding of struts, commons-validation, and extJS is assumed. If any of these technologies are not clear then please visit some of my other tutorial pages.

  1. Maven 2
  2. Basic Understanding of extJS, Struts 1 and commons-validator

Outline

This tutorial is quite lengthy.

Here is an outline:

  1. Create and configure a new project
  2. Extend the html:errors tag
  3. Configure the Struts Framework
  4. Create the struts action class and JSP
  5. Configure the page validation

Create and configure a new project

I would recommend starting from a new project.

Create a new project using Maven 2.

mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp

groupId: com.test
artifactId: form-validation

Answer the rest of the questions with defaults “Just hit the enter key”,

cd to the project base folder.

cd form-validation

Since this is a web project maven2 does not create the java source folder.

Create missing folder
mkdir -p src/main/java/com/test

Modify the project Configuration

Replace the pom.xml with the following.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.test</groupId>
	<artifactId>form-validation</artifactId>
	<packaging>war</packaging>
	<version>1.0-SNAPSHOT</version>
	<name>form-validation Maven Webapp</name>
	<url>http://maven.apache.org</url>
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>commons-validator</groupId>
			<artifactId>commons-validator</artifactId>
			<version>1.1.3</version>
		</dependency>
		<dependency>
			<groupId>struts</groupId>
			<artifactId>struts</artifactId>
			<version>1.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.geronimo.specs</groupId>
			<artifactId>geronimo-servlet_2.5_spec</artifactId>
			<version>1.2</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
			<version>1.1</version>
		</dependency>
		<dependency>
			<groupId>commons-beanutils</groupId>
			<artifactId>commons-beanutils</artifactId>
			<version>1.7.0</version>
		</dependency>
		<dependency>
			<groupId>commons-digester</groupId>
			<artifactId>commons-digester</artifactId>
			<version>1.8</version>
		</dependency>
		<dependency>
			<groupId>commons-collections</groupId>
			<artifactId>commons-collections</artifactId>
			<version>3.1</version>
		</dependency>
		<dependency>
			<groupId>org.json</groupId>
			<artifactId>json</artifactId>
			<version>20090211</version>
		</dependency>
	</dependencies>
	<build>
		<finalName>form-validation</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.0.2</version>
				<configuration>
					<source>1.5</source>
					<target>1.5</target>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.mortbay.jetty</groupId>
				<artifactId>jetty-maven-plugin</artifactId>
				<version>7.0.0.v20091005</version>
				<configuration>
					<scanIntervalSeconds>2</scanIntervalSeconds>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>


Extend the html:errors tag

Extend the html:errors tag to return errors in JSON format.

src/main/java/com/test/ExtJsonErrorsTag.java

package com.test;

import java.util.Iterator;

import javax.servlet.jsp.JspException;

import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.taglib.html.ErrorsTag;
import org.apache.struts.util.RequestUtils;
import org.apache.struts.util.ResponseUtils;
import org.json.JSONException;
import org.json.JSONObject;

public class ExtJsonErrorsTag extends ErrorsTag {

	private static final long serialVersionUID = 1L;

	public int doStartTag() throws JspException {
		ActionErrors errors = null;
		JSONObject jsonReturn = new JSONObject();
		try {
			errors = RequestUtils.getActionErrors(this.pageContext, this.name);
		} catch (JspException e) {
			RequestUtils.saveException(this.pageContext, e);
			throw e;
		}
		if ((errors == null) || (errors.isEmpty())) {
			
			try {
				jsonReturn.put("success", true);
				jsonReturn.put("msg", "Thank you for your submission.");
			} catch (JSONException e) {
				throw new JspException(e);
			}

			ResponseUtils.write(this.pageContext, jsonReturn.toString());
			return 1;
		}

		Iterator errorIterator = errors.properties();
		JSONObject jsonErrors = new JSONObject();

		while (errorIterator.hasNext()) {
			String property = (String) errorIterator.next();
			processErrors(errors, property, jsonErrors);
		}

		try {
			jsonReturn.put("success", false);
			jsonReturn.put("msg", "There was a validation failure.");
			jsonReturn.put("errors", jsonErrors);
			ResponseUtils.write(this.pageContext, jsonReturn.toString());
		} catch (JSONException e) {
			throw new JspException(e);
		}

		return 1;
	}

	private void processErrors(ActionErrors errors, String property,
			JSONObject jsonErrors) throws JspException {
		String message;
		Iterator reports = (property == null) ? errors.get() : errors
				.get(property);
		while (reports.hasNext()) {
			ActionError report = (ActionError) reports.next();

			message = RequestUtils.message(this.pageContext, this.bundle,
					this.locale, report.getKey(), report.getValues());

			if (message != null) {
				try {
					jsonErrors.put(property, message);
				} catch (JSONException e) {
					throw new JspException(e);
				}
			}
		}

	}
}

This is the tag descriptor for the above tag. Nothing interesting here. Just copy and paste this into struts-ext-html.tld.

src/main/webapp/WEB-INF/struts-ext-html.tld

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
<taglib>
	<tlibversion>1.2</tlibversion>
	<jspversion>1.1</jspversion>
	<shortname>html-ext</shortname>
	<uri>http://struts.apache.org/tags-html-ext</uri>
	<tag>
		<name>errors</name>
		<tagclass>com.test.ExtJsonErrorsTag</tagclass>
		<bodycontent>empty</bodycontent>
		<attribute>
			<name>bundle</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>footer</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>header</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>locale</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>name</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>prefix</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>property</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>suffix</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
	</tag>
</taglib>

Action Class and JSP

This is where you provide logic that will run after the form is validated. Control will only be passed to the execute method when the form is fully validated.

src/main/java/com/test/UserSubmitAction.java

package com.test;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
 
public class UserSubmitAction extends org.apache.struts.action.Action {
    public ActionForward execute(ActionMapping mapping,ActionForm form,
           HttpServletRequest request,HttpServletResponse response) throws Exception {
 
    	System.out.println("action ran.");

    	return mapping.findForward("success");
    }
}

The following JSP presents an extJS form to allow the user to enter data.

src/main/webapp/index.jsp

<html>
<head>
 
<link rel="stylesheet" type="text/css"
    href="http://dev.sencha.com/deploy/ext-3.3.1/resources/css/ext-all.css"/>
 
<script type="text/javascript"
    src="http://dev.sencha.com/deploy/ext-3.3.1/adapter/ext/ext-base-debug.js">
</script>
<script type="text/javascript"
    src="http://dev.sencha.com/deploy/ext-3.3.1/ext-all-debug.js">
</script>
 
<script type="text/javascript"> 
function buildWindow() {
    Ext.QuickTips.init();
    Ext.form.Field.prototype.msgTarget = 'side';
    var bd = Ext.getBody();

    var fs = new Ext.FormPanel({
        labelWidth: 75, 
        frame: true,
        title:'Form with crazy amount of validation',
        bodyStyle:'padding:5px 5px 0',
        width: 350,
        defaults: {width: 230},
        waitMsgTarget: true,
        defaultType: 'textfield',       
 
        items: [{
                fieldLabel: 'First Name',
                name: 'firstName'
            },{
                fieldLabel: 'Last Name',
                name: 'lastName'
            },{
                fieldLabel: 'Company',
                name: 'company'
            }, {
                fieldLabel: 'Email',
                name: 'email',
                vtype:'email'
            },{
                fieldLabel: 'Time',
                name: 'time'
            } 
        ],       
 
    });
 
    var onSuccessOrFail = function(form, action) {
        var result = action.result;
 
        if(result.success) {
            Ext.MessageBox.alert('Success', 'Success!');
        } else { // put code here to handle form validation failure.
        }
 
    }
 
    var submit = fs.addButton({
        text: 'Submit',
        disabled:false,
        handler: function(){
            fs.getForm().submit({
                url:'/form/UserSubmit',
                waitMsg:'Submitting Data...',
                submitEmptyText: false,
                success : onSuccessOrFail,
                failure : onSuccessOrFail
            });
        }
    });
 
    fs.render('form-first');
}
Ext.onReady(buildWindow);
</script>
</head>
<body>
<div id="form-first"></div>
</body>
</html>

Success and Failure JSP’s

This JSP displays regardless if there was a validation failure or not. This is to satisfy the extJS component requirement that all form submissions should return a result.

src/main/webapp/WEB-INF/result.jsp

<%@ taglib uri="/tags/struts-html-ext" prefix="html-ext" %>
<html-ext:errors/> 


Validation configuration

All the fields of the form are required. In addition the first name must be at least 10 and no more than 15 characters. The email address must be valid formatted and the time field must be in the proper format in order to proceed. All of this is coded into the following file.

src/main/webapp/WEB-INF/validation.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE form-validation PUBLIC
          "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN"
          "http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd">
 
<form-validation>
<formset>
<form name="userInformation">
    <field property="firstName" depends="required,minlength,maxlength">
        <arg0 key="userInformation.firstName" />
        <arg1 name="minlength" key="${var:minlength}" resource="false"/>
        <arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
        <var>
        	<var-name>minlength</var-name>
        	<var-value>10</var-value>
        </var>
        <var>
        	<var-name>maxlength</var-name>
        	<var-value>15</var-value>
        </var>
        
    </field>
    <field property="lastName" depends="required">
        <arg key="userInformation.lastName" />
    </field>
    <field property="company" depends="required">
        <arg key="userInformation.company" />
    </field>
    <field property="email" depends="required,email">
        <arg key="userInformation.email" />
    </field>
    <field property="time" depends="required,mask">
        <msg name="mask" key="userInformation.time.maskmsg"/>
        <arg0 key="userInformation.time" />
        <var><var-name>mask</var-name><var-value>^[0-9]{1,2}:[0-9]{1,2} (AM|PM)$</var-value></var>
    </field>
</form>
</formset>
</form-validation>

Configure the Struts Framework

The following files are necessary to get the struts framework initialized and ready to process form submissions. The lines specific to this application have been highlighted.

Struts Config

The following struts configuration file contains a dyna-form and an action mapping. The /UserSubmit action mapping “input” page will be invoked if there are validation failures. If all goes well with validation the control will forward to “result.jsp” which will display JSON output expected by the extJS component.

src/main/webapp/WEB-INF/struts-config.xml

<?xml version="1.0" encoding="ISO-8859-1" ?>
    <!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
          "http://struts.apache.org/dtds/struts-config_1_3.dtd">

<struts-config>
	<form-beans>
		<form-bean name="userInformation"
			type="org.apache.struts.validator.DynaValidatorForm">
			<form-property name="firstName" type="java.lang.String" />
			<form-property name="lastName" type="java.lang.String" />
			<form-property name="company" type="java.lang.String" />
			<form-property name="email" type="java.lang.String" />
			<form-property name="time" type="java.lang.String" />
		</form-bean>
	</form-beans>

	<action-mappings>
		<action name="userInformation" path="/UserSubmit" input="/WEB-INF/result.jsp"
			type="com.test.UserSubmitAction" validate="true">
			<forward name="success" path="/WEB-INF/result.jsp"></forward>
		</action>
	</action-mappings>

	<!-- The "application.properties" is located in the root of the classpath. -->
	<message-resources parameter="application" />

	<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
		<set-property property="pathnames"
			value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml," />
	</plug-in>

</struts-config>

The following file was taken from the commons-validator framework. It contains information about the various classes that perform validation. Just copy and paste this into validator-rules.xml. The client side JavaScript validation code has been removed since we will only be performing server side validation. I am thinking about writing another tutorial on how to have commons validator generate extJS specific client side JavaScript validation. Let me know if you guys are interested in seeing this.

src/main/webapp/WEB-INF/validator-rules.xml

<!DOCTYPE form-validation PUBLIC
          "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.0//EN"
          "http://jakarta.apache.org/commons/dtds/validator_1_0.dtd">

<form-validation>
   <global>
      <validator name="required"
            classname="org.apache.struts.validator.FieldChecks"
               method="validateRequired"
         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"
                  msg="errors.required">
      </validator>

      <validator name="requiredif"
                 classname="org.apache.struts.validator.FieldChecks"
                 method="validateRequiredIf"
                 methodParams="java.lang.Object,
                               org.apache.commons.validator.ValidatorAction,
                               org.apache.commons.validator.Field,
                               org.apache.struts.action.ActionErrors,
                               org.apache.commons.validator.Validator,
                               javax.servlet.http.HttpServletRequest"
                 msg="errors.required">
      </validator>

      <validator name="minlength"
            classname="org.apache.struts.validator.FieldChecks"
               method="validateMinLength"
         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"
              depends=""
                  msg="errors.minlength">
      </validator>


      <validator name="maxlength"
            classname="org.apache.struts.validator.FieldChecks"
               method="validateMaxLength"
         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"
              depends=""
                  msg="errors.maxlength">

      </validator>


      <validator name="mask"
            classname="org.apache.struts.validator.FieldChecks"
               method="validateMask"
         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"
              depends=""
                  msg="errors.invalid">

      </validator>


      <validator name="byte"
            classname="org.apache.struts.validator.FieldChecks"
               method="validateByte"
         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"
              depends=""
                  msg="errors.byte"
       jsFunctionName="ByteValidations">
      </validator>

      <validator name="short"
            classname="org.apache.struts.validator.FieldChecks"
               method="validateShort"
         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"
              depends=""
                  msg="errors.short"
       jsFunctionName="ShortValidations">
      </validator>

      <validator name="integer"
            classname="org.apache.struts.validator.FieldChecks"
               method="validateInteger"
         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"
              depends=""
                  msg="errors.integer"
       jsFunctionName="IntegerValidations">
      </validator>

      <validator name="long"
            classname="org.apache.struts.validator.FieldChecks"
               method="validateLong"
         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"
              depends=""
                  msg="errors.long"/>
      <validator name="float"
            classname="org.apache.struts.validator.FieldChecks"
               method="validateFloat"
         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"
              depends=""
                  msg="errors.float"
       jsFunctionName="FloatValidations">
      </validator>

      <validator name="double"
            classname="org.apache.struts.validator.FieldChecks"
               method="validateDouble"
         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"
              depends=""
                  msg="errors.double"/>

      <validator name="date"
            classname="org.apache.struts.validator.FieldChecks"
               method="validateDate"
         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"
              depends=""
                  msg="errors.date"
       jsFunctionName="DateValidations">


      </validator>

<!-- range is deprecated use intRange instead -->
      <validator name="range"
            classname="org.apache.struts.validator.FieldChecks"
               method="validateIntRange"
         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"
              depends="integer"
                  msg="errors.range">
      </validator>

      <validator name="intRange"
            classname="org.apache.struts.validator.FieldChecks"
               method="validateIntRange"
         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"
              depends="integer"
                  msg="errors.range">

      </validator>

      <validator name="floatRange"
            classname="org.apache.struts.validator.FieldChecks"
               method="validateFloatRange"
         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"
              depends="float"
                  msg="errors.range">
      </validator>

      <validator name="creditCard"
            classname="org.apache.struts.validator.FieldChecks"
               method="validateCreditCard"
         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"
              depends=""
                  msg="errors.creditcard">

      </validator>

     <validator name="email"
            classname="org.apache.struts.validator.FieldChecks"
              method="validateEmail"
         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                      org.apache.commons.validator.Field,
                      org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"
              depends=""
                  msg="errors.email">
      </validator>
   </global>
</form-validation>

The following file contains the messages to display to the user.

src/main/resources/application.properties

errors.required={0} is required.
errors.minlength={0} can not be less than {1} characters.
errors.maxlength={0} can not be greater than {1} characters.
errors.invalid={0} is invalid.
 
errors.byte={0} must be a byte.
errors.short={0} must be a short.
errors.integer={0} must be an integer.
errors.long={0} must be a long.
errors.float={0} must be a float.
errors.double={0} must be a double.
 
errors.date={0} is not a date.
errors.range={0} is not in the range {1} through {2}.
errors.creditcard={0} is an invalid credit card number.
errors.email={0} is an invalid e-mail address.

userInformation.firstName=First Name
userInformation.lastName=Last Name
userInformation.company=company
userInformation.email=email
userInformation.time=time
userInformation.time.maskmsg=Time must be formatted like (##:## AM|PM)

This is a bare minimum log4j.properties file.

src/main/resources/log4j.properties

# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=INFO, A1
 
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d %-5p %c - %m%n

src/main/webapp/WEB-INF/web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

    <servlet>
        <servlet-name>action</servlet-name>
        <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
        <init-param>
            <param-name>config</param-name>
            <param-value>
         /WEB-INF/struts-config.xml
        </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
 
    </servlet>
 
    <servlet-mapping>
        <servlet-name>action</servlet-name>
        <url-pattern>/form/*</url-pattern>
    </servlet-mapping>

  <!-- Struts Tag Library Descriptors -->
 
  <taglib>
    <taglib-uri>/tags/struts-html-ext</taglib-uri>
    <taglib-location>/WEB-INF/struts-ext-html.tld</taglib-location>
  </taglib>
  
</web-app>

Test the application

In the project top folder type in the following command to compile and run the code in jetty servlet engine.

mvn clean compile jetty:run

Navigate to the following URL:
http://localhost:8080/

An extJS form should display allowing you to enter values. Click submit and an Ajax form submission will be made to the Struts Action. Any validation failures will show next to the component.

That’s all for now.

26
Jan
11

Spring 2 Enabling Your Struts 1 Application

This page describes the process of integrating the spring framework into an existing struts 1 project.

This page is an attempt to rewrite an page I wrote a few years ago.

This page contains the complete source and uses Maven 2 to help create the project and manage the dependencies and execute the test environment. Its a good idea that you learn what Maven 2 is about by clicking on the Maven tutorial on the right navigation of this page.

Requirements

  • Maven 2
  • Java 5
  • Basic understanding of struts.
  • Struts 1.3.10

Background

The trick to integrating spring framework is to define the action classes as spring beans and wrap them using a DelegatingActionProxy.

This page follows the same example described in the following blog…

http://www.vaannila.com/struts/struts-example/struts-hello-world-example-1.html

Procedure

mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp

For the group id enter: com.test
For the artifactId enter: strutsSpringExample

Answer the rest of the questions using defaults [Hit Enter].

cd to the project’s folder

Next we create the src/main/java folder since this is not done for us using the archetype.

on unix you type:

cd strutsSpringExample

In unix you can type:
mkdir -p src/main/java/com/test

Project Configuration

Modify the pom.xml file. It should look like this…

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.test</groupId>
  <artifactId>strutsSpringExample</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>strutsSpringExample Maven Webapp</name>
  <url>http://maven.apache.org</url>
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc-struts</artifactId>
			<version>2.5.5</version>
		</dependency> 
		<dependency>
			<groupId>org.apache.struts</groupId>
			<artifactId>struts-core</artifactId>
			<version>1.3.10</version>
		</dependency>
		<dependency>
			<groupId>org.apache.struts</groupId>
			<artifactId>struts-taglib</artifactId>
			<version>1.3.10</version>
		</dependency> 
		<dependency>
			<groupId>org.apache.geronimo.specs</groupId>
			<artifactId>geronimo-jsp_2.1_spec</artifactId>
			<version>1.0.1</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.apache.geronimo.specs</groupId>
			<artifactId>geronimo-servlet_2.5_spec</artifactId>
			<version>1.2</version>
			<scope>provided</scope>
		</dependency>
	</dependencies>

	<build>
		<finalName>strutsSpringExample</finalName>
		<plugins>          
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.0.2</version>
				<configuration>
				    <source>1.5</source>
				    <target>1.5</target>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.mortbay.jetty</groupId>
				<artifactId>jetty-maven-plugin</artifactId>
				<version>7.0.0.pre5</version>
				<configuration>
				<webAppConfig>
					<contextPath>/</contextPath>
				</webAppConfig>
				    <scanIntervalSeconds>2</scanIntervalSeconds>
				</configuration>
			</plugin>    
		</plugins>
	</build>
</project>

The following is a standard web.xml file. Nothing really different here.

src/main/webapp/WEB-INF/web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app> 
	<servlet>
		<servlet-name>action</servlet-name>
		<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
		<init-param>
		    <param-name>config</param-name>
		    <param-value>
		 /WEB-INF/struts-config.xml
		</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>	 
	</servlet>
	 
	<servlet-mapping>
		<servlet-name>action</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>

	<welcome-file-list>
	<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
</web-app>

The following is a struts configuration file. This is the first change that is done to integrate the spring framework. (see highlighted)

Also note on line 16 the type is specified as DelegatingActionProxy.

src/main/webapp/WEB-INF/struts-config.xml

<?xml version="1.0" encoding="ISO-8859-1" ?>
    <!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
          "http://struts.apache.org/dtds/struts-config_1_3.dtd">
 
<struts-config>

    <form-beans>
        <form-bean name="HelloWorldActionForm"
              type="com.test.HelloWorldActionForm"/>
    </form-beans>

    <action-mappings>
        <action path="/HelloWorld" name="HelloWorldActionForm" 
        	scope="session" 
        	type="org.springframework.web.struts.DelegatingActionProxy">
            <forward name="success" path="/helloWorld.jsp"></forward>
        </action>
    </action-mappings>
 
    <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
     <set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml"/>
    </plug-in>
 
</struts-config>

The following is the main spring configuration file. It gets loaded by the ContextLoaderPlugIn mentioned above. The name of the spring beans MUST match the “path” attribute of each action mentioned in the struts config. This is how the DelegatingActionProxy finds the spring bean that is handling the request.

src/main/webapp/WEB-INF/applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC
    "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">
 
<beans>
 
    <bean name="/HelloWorld" class="com.test.HelloWorldAction">
    </bean>
 
</beans>

The following is a standard struts form bean. Nothing here has changed due to spring.

src/main/java/com/test/HelloWorldActionForm.java

package com.test;

public class HelloWorldActionForm extends
           org.apache.struts.action.ActionForm {
 
    private String message;
 
    public HelloWorldActionForm() {
        super();
    }
 
    public String getMessage() {
        return message;
    }
 
    public void setMessage(String message) {
        this.message = message;
    } 
}

The following is a standard struts action. Nothing really different here.

src/main/java/com/test/HelloWorldAction.java

package com.test;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
 
public class HelloWorldAction extends org.apache.struts.action.Action {
 
    private final static String SUCCESS = "success";
 
    public ActionForward execute(ActionMapping mapping,ActionForm form,
           HttpServletRequest request,HttpServletResponse response) throws Exception {
 
		HelloWorldActionForm helloWorldForm = (HelloWorldActionForm) form;
		if(helloWorldForm.getMessage() == null || 
			"".equals(helloWorldForm.getMessage().trim())) {
			helloWorldForm.setMessage("Hello World!");		
		}
				
        return mapping.findForward(SUCCESS);
 
    }
}

The following file allows the web application to redirect the browser to the HelloWorld.do struts action.

No spring spectific changes here either.
src/main/webapp/index.jsp

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>Your Page Title</title>
<meta http-equiv="REFRESH" content="0;url=<c:url value='/HelloWorld.do'/>"></HEAD>
<BODY>
Optional page text here.
</body>
</html>

The following is a standard JSP that contains a struts form. It posts back to the action that rendered it.

src/main/webapp/helloWorld.jsp

<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>

<html:html>
<head>
<title>Hello World</title>
</head>
<body>
<h1>
<bean:write name="HelloWorldActionForm" property="message" />

<html:form action="/HelloWorld">
	<html:text property="message"/>	
	<html:submit/>
</html:form>
</h1>
</body>
</html:html>

Test the application

The application can be tested using jetty inside the strutsSpringExample project directory

Just type:

mvn clean compile jetty:run

That’s all for now!

08
Sep
09

Integrating Core Spring with the Struts Framework

This page explains how to take the “core spring hello world application” and integrate it with struts framework.

Requirements

A typical Struts application is a collection of Action classes. The trick to integrating spring framework into one of these application is to convert the action classes to spring beans. Spring beans are managed by the spring container. The container is initialized via xml configuration file.

In the Example application listed at the above URL you were introduced with an account transfer process. The customer wanted some amount of money transferred between 2 accounts. For this we used the AccountTransferService. The service used 2 data mangers configured as spring beans. Once the datamangers were configured they were “injected” into the AccountTransferService. All of this was done thru XML configuration and none of the components of the system knew how to construct each other. This leads to a loosely coupled system since we can swap out the implementation of the datamangers for testing or development purposes.

In this page we will convert the Struts Actions into spring enabled beans. We will “inject” the objects that the action needs to do its job. In this case the AccountTransferService will be injected into the Action. The action will handle the request, delegate the processing of the request to the AccountTransferService, then forward to the success page.

ContextLoaderPlugin

This plugin loads a spring context file for the struts ActionServlet. This allows your struts actions to be managed by Spring. You can do this 2 ways.

  • Override Struts’ default RequestProcessor with Spring’s DelegatingRequestProcessor
  • Use the DelegatingActionProxy class in the type attribute of your action-mapping element.

In the first method the type attribute of the struts action element will be ignored. In the second method you can use the DelegatingActionProxy as the type in your action-mapping. This is the approach we will cover here.

DelegatingActionProxy

The job of this class is to delegate the handling of a request to an Action Bean that is “spring enabled”. Spring enabling a bean means that we have defined it in a spring configuration file and injected it with the dependencies it needs to do its job.

It will chose the spring-enabled bean based on the URI of the incoming request. If we are asking for accountTransfer.do it will look for a spring bean named “/accountTransfer” in the spring application context.

The bridge between the Action in struts-config.xml and the strutsConfiguration.xml is built with the action-mapping’s “path” and the bean’s “name”. If you have the following in your struts-config.xml


<action path="/users" .../>

You must define that Action’s bean with the “/users” name in the strutsConfiguration.xml file.


<bean name="/users" .../>

Before we can start making this we need to add a few things to the pom.xml file.

Insert the pom file modifications here.

<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc-struts</artifactId>
        <version>2.5.5</version>
</dependency>
<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc-struts</artifactId>
        <version>2.5.5</version>
</dependency>

Modify the struts-config.xml and add the following towards the end of the file.

<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
 <set-property property="contextConfigLocation" value="/WEB-INF/spring-config.xml"/>
</plug-in>

We will create an Action called AccountTransferAction. We will have this action spring enabled by putting it into the spring configuration file.

Modify application.xml and add the following section.

<bean name="/accountTransfer" class="strutsexample.AccountTransferAction">
<property name="accountTransferService" ref="accountTransferService"/>
</bean>

Update the struts-config.xml file and replace the strutsexample.AccountTransferAction with org.springframework.web.struts.DelegatingActionProxy. As you can see in the above bean definition the “accountTransferService” is injected into the “Spring Enabled” struts action.

<action path="/AccountTransfer" forward="/pages/accountInput.jsp" />
<!--
 <action path="/AccountTransferSubmit"  type="strutsexample.AccountTransferAction">
 <forward name="success" path="/pages/accountTransferSuccess.jsp"></forward>
 </action>

 <action path="/AccountTransferSubmit"  type="org.springframework.web.struts.DelegatingActionProxy">
 <forward name="success" path="/pages/accountTransferSuccess.jsp"></forward>
 </action>
 -->

The code in comments represents 2 ways to define an action. The first one is how you would typically define a struts action. The second element represents a spring enabled struts action. Go ahead and copy the second element outside the comments and save the file.

The following is the

src/main/webapp/WEB-INF/spring-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC
        "-//SPRING//DTD BEAN//EN"
        "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
        <bean name="/AccountTransferSubmit" class="strutsexample.AccountTransferAction">
                <property name="accountTransferService" ref="accountTransferService"/>
        </bean>
</beans>

The following is the

src/main/webapp/WEB-INF/applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC
        "-//SPRING//DTD BEAN//EN"
        "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
        <bean name="accountDataManager" class="accountTransfer.AccountDataManagerImpl"/>
        <bean name="customerDataManager" class="accountTransfer.CustomerDataManagerImpl"/>
        <bean name="accountTransferService" class="accountTransfer.AccountTransferServiceImpl">
                <property name="accountDataManager" ref="accountDataManager"/>
                <property name="customerDataManager" ref="customerDataManager"/>
        </bean>
</beans>

Add the following Action class file to the project

package strutsexample;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import accountTransfer.AccountTransferServiceIF;

public class AccountTransferAction extends Action {
        private static final Log logger = LogFactory.getLog(AccountTransferAction.class);

        private AccountTransferServiceIF accountTransferService;

        public AccountTransferServiceIF getAccountTransferService() {
                return accountTransferService;
        }

        public void setAccountTransferService(
                        AccountTransferServiceIF accountTransferService) {
                this.accountTransferService = accountTransferService;
        }

        @Override
        public ActionForward execute(ActionMapping mapping, ActionForm form,
                        HttpServletRequest request, HttpServletResponse response)
                        throws Exception {

                logger.info("struts action ran with: " + accountTransferService);

                return mapping.findForward("success");
        }
}

Add the following JSP’s to the project.

src/main/webapp/pages/accountTransferSuccess.jsp

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
 <head>
 <title>XHTML 1.0 Strict Template</title>
 <meta http-equiv="Content-type" content="text/html; charset=iso-8859-1" />
 <meta http-equiv="Content-Language" content="en-us" />
 </head>
 <body>

Account Transfer Success!

</body>
</html>

src/main/webapp/pages/accountInput.jsp

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
        <title>XHTML 1.0 Strict Template</title>
        <meta http-equiv="Content-type" content="text/html; charset=iso-8859-1" />
        <meta http-equiv="Content-Language" content="en-us" />
</head>
<body>
        <form action="AccountTransferSubmit.do">
        <input type="text" value="test" />
        <input type="submit"/>
        </form>
</body>
</html>

That’s all! you just spring enabled your struts application!

package strutsexample;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import accountTransfer.AccountTransferServiceIF;

public class AccountTransferAction extends Action {
private static final Log logger = LogFactory.getLog(AccountTransferAction.class);

private AccountTransferServiceIF accountTransferService;

public AccountTransferServiceIF getAccountTransferService() {
return accountTransferService;
}

public void setAccountTransferService(
AccountTransferServiceIF accountTransferService) {
this.accountTransferService = accountTransferService;
}

@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {

logger.info(“struts action ran with: ” + accountTransferService);

return mapping.findForward(“success”);
}
}

This site is a collaborative effort! The complete text and sourcecode for this is available on GitHub. Corrections and enhancements are welcome, please make the change and submit a pull request in the comment area below.
07
Sep
09

Struts 1 Lesson 1 Hello World with Maven 2

Introduction

This page explains how you can get a basic struts hello world application up and running using Maven 2.

Lets start with the pom file and use it to regenerate our eclipse project.

Implementation

Start by creating a project from a Maven archetype.

mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp

Answer the rest of the questions like this▒?▒

Define value for groupId: : com.test
Define value for artifactId: : strutsTest
Define value for version:  1.0-SNAPSHOT: :
Define value for package:  com.test: :

Hit enter for the rest of the defaults.

cd to the project’s folder
Next we create the src/main/java folder since this is not done for us using the archetype.

on unix you type: mkdir src/main/java

Next we generate the eclipse project (optional). The project is still not ready however this step makes editing the pom.xml file easier.

mvn eclipse:clean eclipse:eclipse

Import the Existing project (generated project) into eclipse.

Next steps are to typically modify the pom.xml file and insert the rest of the dependencies and regenerate the eclipse project by re-typing the above command and clicking refresh on the eclipse project.

Update your pom.xml file to look like this…

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.test</groupId>
  <artifactId>strutsTest</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>strutsTest Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.1.2</version>
        </dependency>
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
                <dependency>
                        <groupId>org.apache.struts</groupId>
                        <artifactId>struts-core</artifactId>
                        <version>1.3.10</version>
                </dependency>
                <dependency>
                    <groupId>org.apache.geronimo.specs</groupId>
                    <artifactId>geronimo-servlet_2.5_spec</artifactId>
                    <version>1.2</version>
                    <scope>provided</scope>
                </dependency>
  </dependencies>
  <build>
    <finalName>strutsTest</finalName>
        <plugins>
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>7.0.0.v20091005</version>
                        <configuration>
                         <scanIntervalSeconds>2</scanIntervalSeconds>
                        </configuration>
            </plugin>
        </plugins>
  </build>
</project>

It all starts with the web.xml

In the above code you see spring included as a dependency. Lets leave it there for now since this example is used to build a project that uses spring with struts together.

Next we will modify the web.xml file

src/main/webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
        id="WebApp_ID" version="2.5">
        <display-name>strutsTest</display-name>
        <welcome-file-list>
                <welcome-file>index.jsp</welcome-file>
        </welcome-file-list>

        <servlet>
                <servlet-name>action</servlet-name>
                <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
                <init-param>
                        <param-name>config</param-name>
                        <param-value>
         /WEB-INF/struts-config.xml
        </param-value>
                </init-param>
                <load-on-startup>1</load-on-startup>

        </servlet>

        <servlet-mapping>
                <servlet-name>action</servlet-name>
                <url-pattern>*.do</url-pattern>
        </servlet-mapping>

</web-app>

Next comes the struts-config.xml file. Both the web.xml and this file belong in the /WEB-INF folder.

src/main/webapp/WEB-INF/struts-config.xml

<?xml version="1.0" encoding="ISO-8859-1" ?>
    <!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
          "http://struts.apache.org/dtds/struts-config_1_3.dtd">

<struts-config>
        <action-mappings>
                <action path="/HelloWorld"  type="com.test.HelloWorldAction">
                        <forward name="success" path="/helloWorld.jsp"></forward>
                </action>
        </action-mappings>
</struts-config>

Next is the hello world struts action
src/main/java/com/test/HelloWorldAction.java

package com.test;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

public class HelloWorldAction extends org.apache.struts.action.Action {

    private final static String SUCCESS = "success";

    public ActionForward execute(ActionMapping mapping,ActionForm form,
           HttpServletRequest request,HttpServletResponse response) throws Exception {

        return mapping.findForward(SUCCESS);

    }
}

Next we will create the JSP’s used to display the pages.

src/main/webapp/index.jsp

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>Your Page Title</title>
<meta http-equiv="REFRESH" content="0;url=<c:url value='/HelloWorld.do'/>"></HEAD>
<BODY>
Optional page text here.
</BODY>
</HTML>

Next is the Hello World page

src/main/webapp/helloWorld.jsp

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
 <head>
  <title>XHTML 1.0 Strict Template</title>
  <meta http-equiv="Content-type" content="text/html; charset=iso-8859-1" />
  <meta http-equiv="Content-Language" content="en-us" />
 </head>
Struts Hello World.
 <body>
</body>
</html>

Test the application

Start up jetty and test your application

mvn jetty:run

navigate to http://localhost:8080/

You should see a Hello World message.

In the next section we will step thru the process of integrating spring with this simple struts application.

This site is a collaborative effort! The complete text and sourcecode for this is available on GitHub. Corrections and enhancements are welcome, please make the change and submit a pull request in the comment area below.



Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 77 other followers

February 2017
S M T W T F S
« Mar    
 1234
567891011
12131415161718
19202122232425
262728  

Blog Stats

  • 795,599 hits