Java Web Development with Struts and Tiles

By: Ken Sipe

Abstract: Struts are freely available and fairly easy to understand. However, it is one thing to know the framework and how it works and another to actually build a Web application. This tutorial begins with a primer on the architecture, moving quickly into more practical concerns surrounding the framework. Discussion points include suggested best practices, design aspects of a Struts application, and some tricks for sharing data between pages using the framework. Learn to exploit many of the tags included in the framework, its validation capabilities, and customization. Finally, we also discuss the Tiles framework, from basic manipulation through more extensive use of its controllers to create portal-like applications.

Ken Sipe is the CEO and Founder of Code Mentor, Inc., a company devoted to helping companies integrate open standards into their business processes for secure, flexibility, reliability and scalability solutions, improved TCO. He is frequently called on to validate or develop enterprise-level architecture, helping many clients make that transition from strategic vision to tactical implementation. He provides mentoring and best practices on all aspects of architecture, design and development practices. He is an instructor for Borland for Visibroker for Java and previously was an instructor for Rational for OOAD / UML and Rational Rose. Ken is a certified JBoss developer, and was an active member of the Voyager project, an open source project to provide a JBuilder OpenTool integration tool for JBoss. Since JBuilderX and its integration with JBoss, he has more time to pursue other endeavors. Thanks Borland and the JBuilder team! In addition Ken is an internationally recognized speaker in the field of distributed computing, most recently speaking at JavaOne in 2003 and BorCon in 2003 and is the author of the Apress! book on Tomcat 5.

kensipe@codementor.net

Java Web Development with Struts and Tiles
Ken Sipe  Code Mentor


Introduction and Motivation

The autonomy and syntactical details of Struts are freely available and fairly easy to understand however its one thing to know the framework and know how it works and another to build web applications with Struts. This intermediate level tutorial is designed with the expectation that those in attendance already know web architecture, Java, JSP and have worked with custom tags. There is a 10-15 minute primer to level set the knowledge across the group, which is more of a warm-up lap. From that point forward well be in a full sprint to the finish line, covering much of the best parts of the framework. This tutorial is based on a 3 day Struts training course. The choicest sections have been taken and condensed into this 4 hour tutorial.

The first hour will consist of that 10-15 minute warm-up, followed by a look at all the form beans used within the Struts framework. This will lead to a look at each of the available actions. These discussions will include suggested best practices for each component, as well as when and when not to use them. After looking at some of these more syntactical subjects, well focus on the design aspect of a Struts web application from a page to page perspective. This will include action to action design, which scope to use, and when to leverage which action. Well examine several nifty tricks on sharing data between pages in the request scope using the framework.

The second hour will continue the design aspect of Struts from a page stand point. Well example many of the tags available, pay close attention to several extremely useful but overlooked tags. Well examine several common issue developers have with Struts, such as Nesting, Iterating, Multibox, parameterized links.

Focusing on server-side validation, the third hour will focus on the included validation framework. Well start with the standard validation in the form bean, showing much of the internal semantics of the validation framework. Following this well discuss business logic validation in the action class, and how to handle it using the framework. The majority of the time well be looking through the declarative nature of the validation frame. Finishing with a discussion on what it takes to create your own validator.

The last topic is on Tiles. This session will start with tile basics showing how to easily manage common components of a web site. Slightly less known, well look at tile controllers and how to provide a personalized web site using tiles.

This whitepaper assumes that you know and are familiar with JSP / Servlet development. Check out the sun site for more information on JSP / Servlets if this is new to you.


Struts Intro

JSP Web Applications

There are 2 recognized models in the JSP world. The same clever folks at Sun that named the JDBC drivers must have been involved with naming the JSP models. They are creatively named model 1 and model 2. The two models are just descriptions of how JSP pages are used; Model 1 is nothing but JSP, Model 2 is the combination of JSP and Servlets. Below are illustrations of both models.

By understanding the models below, in combination with the understanding of the model/view/controller pattern discussed below, you will be prepared to understand the huge advantages which struts brings to the table.


Model 1

Model 1 simply refers to a JSP web application, where JSP pages are used for every aspect of the development. A JSP posts to another JSP page or in some cases the JSP page posts to itself.

JSP to Itself

JSP to JSP

Advantages

  • Simple -- usually the default model for beginners or could be great for a prototype or demo.

Disadvantages

  • Spaghetti -- Need I say more!
  • Non Modular code -- difficult to reuse

Model 2

Model 2 simply refers to a JSP web application, where JSP pages are used for the GUI aspect of the web development and the logic of the application is placed in the Servlets it posts to, providing the base for a model view controller architecture. It may not be obvious in the illustration below, usually a servlet will provide all the logic setting up the request and session scope and then will forward to the JSP for display. This JSP will then post to another servlet.

JSP to Servlet

Description

The logic of login, connection to the database, EJB, etc. are no longer in the JSP. The Servlet assess all resources, providing beans for the JSP to display.

Advantages

  • Separates the layers of the application. The View layer has dependencies only on resources needed for display. The logic of the application is not in the view.

Disadvantages

  • The creation of a page or set of pages is no longer a one to one mapping to a single source of code. In another words the one JSP page is now a Servlet and a JSP page.
  • The above mentioned disadvantage, requires more organization and forethought ( Warning: you may even have to "design" your application )

Model summary

  • A Model 1 analogy would be a VB programmer, where they would put a button on a form, double click and start coding. No real design work just RAD development.
  • There is a better approach, as people have been publishing their findings in the last decade. The MVC provides a way for beans and logic to be used in different views. Likewise the view can change over time leverage the same logic. This decouples the view from the logic.

Model View Controller

The MVC architecture has its roots in Smalltalk, where it was originally applied to the graphical user interaction model. However, it is straightforward to map these concepts into the domain of multi-tier enterprise applications:

  • The model represents enterprise data and the business rules that govern access to and updates of this data. Often the model serves as a software approximation to a real-world process, so simple real-world modeling techniques apply when defining the model.
  • A view renders the contents of a model. It accesses enterprise data through the model and specifies how that data should be presented. It is the view's responsibility to maintain consistency in its presentation when the model changes. This can be achieved by using a push model, where the view registers itself with the model for change notifications, or a pull model, where the view is responsible for calling the model when it needs to retrieve the most current data.
  • A controller translates interactions with the view into actions to be performed by the model. In a stand-alone GUI client, user interactions could be button clicks or menu selections, whereas in a Web application, they appear as GET and POST HTTP requests. The actions performed by the model include activating business processes or changing the state of the model. Based on the user interactions and the outcome of the model actions, the controller responds by selecting an appropriate view.


MVC in a Web World

In web application development, the JSP pages will be our view, the Servlets will be the controllers and the model consists of Java beans, EJBs or other Java classes.

In practice we will create a JSP page for each view in our system. Typically I create HTML only versions to get a look and feel and buy in from the client.

Then through OOAD the model is designed. Then the Servlets access data, and instantiate beans or the model.

Passing the model into the request object or session object and forwarding to the appropriate view.

The illustration below shows the concept of MVC in a Java web application. It doesnt apply struts at this time. Understanding this concept will aid the reader in understand how Struts helps make a web MVC developer move productive.


What are Struts?

Apache Struts is a web application framework.  As this may insinuate, Struts consists of a variety of solutions to common web architecture problems.  Additionally it consists of several packages that could easily be leveraged in other than web architectures.  The goal of the struts project is to provide an open source framework useful in building web applications with Java Servlet and JavaServer Pages (JSP) technology.

Struts includes the following primary areas of functionality:

7         A controller Servlet that dispatches requests to appropriate Action classes provided by the application developer.

7         JSP custom tag libraries, and associated support in the controller Servlet, that assists developers in creating interactive form-based applications.

7         Utility classes to support XML parsing, automatic population of JavaBeans properties based on the Java reflection APIs, and internationalization of prompts and messages.

7         Supportive frameworks:

n       7   Tiles -- used to create Portals, Portlets and web layouts

n       7   Validation Framework -- used to provide declarative validation

n       7   Commons -- used for a variety of things including, commons logging, and datasource management

Struts is part of the Jakarta Project, sponsored by the Apache Software Foundation. The official Struts home page is at http://jakarta.apache.org/struts.

Struts version 1.0 hit cyber space on of June 15, 2001. We are currently at version 1.1, which was released final on June 30, 2003.

Oh yeah and did I mention that it's free. Not only free, but it's open source!


Struts MVC Architecture

The advantage of the strut framework is that we've abstract the model one step further. Now the "traditional" controller doesn't even know where the next view is. It returns a response to the front controller which determines the appropriate view based on the response.

In the Strut framework, the views are determined via the strut-config.xml file, which provides a mapping of response to URI which usually equals to a JSP page.

The framework provides the ActionServlet, the developer must provide the ActionBean and register it with the framework.


Struts 1.1 Features

Struts 1.1 provides the following great enhancements:

1.      Tiles  replaces the components framework in struts 1.0. Tiles are much more flexible. An example will be provided below.

2.      Validation Framework - provides a declarative way to manage validation. In addition it works in a way which allows for internationalization.

3.      Architectural enhancements

'         4 RequestProcessor  With Struts 1.0, everyone extended ActionServlet for per web request functionality. This is no longer necessary. That functionality is abstracted into the RequestProcessor. Now all your web.xml files for struts will look the same.

'         5 ExceptionHandler  Another abstraction, this controller manages exceptions and ActionErrors. This class provides another way to manage these concerns without extending the ActionServlet.


JBuilder and Struts

Pre-JBuilder 9.0

Ever since JBuilder 5.0 it has been possible to use and develop Struts applications in JBuilder, albeit in many cases with great pain. For help with working in any of these environments post on the Borland news group, I or someone will provide some assistance.

The capability of pre-JBuilder 9 consisted on being able to have a struts library, have it built into WAR files and running the web application. It provided nothing more than that. It didnt provide any Struts tag support. In many cases you have to go outside JBuilder to move or copy files around, such as tag libs. In all cases you needed to download and configure Struts.

JBuilder 9.0

JBuilder 9 provides struts 1.0 support right out of the box. In addition it provides the following functionality which can greatly increase your time to market:

n       7 Object Gallery support

n       ActionForms with registration in Struts-config

'         Action Class

'         JSP from ActionForms

'         Struts Converter

n       7 JSP convert to Struts

n       7 Struts Editor and Structure Pain support

n       7 Tiles Editor support

n       7 Automatic struts configuration in WAR

JBuilder 9.0 with Struts 1.1

The JBuilder 9 editor will support 1.1. You must do the following:

1.      Download Struts 1.1

2.      Configure the Struts Library. It should be noted that it JBuilder 9 doesnt like to manage a Struts 1.0 and Struts 1.1 library. You should work with one or the other, however it is possible. Post interests on the newsgroup. (newsgroups.borland.com:borland.public.jbuilder.servlets-jsp)

3.      Change the DTD for the struts-config.xml file to <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">

When you do this the structure pane should change. The table below outlines the differences in the structure pane.

JBuilder 9 Struts 1.0 Structure Pane

JBuilder 9 Struts 1.1 Structure Pane

JBuilder 10.0

Struts support goes over the top!!! The support for struts is amazing in JBuilder 10. Jbuilder 10 provides all the support that JBuilder 9 provides, with the following additional supports.

1.      Management of the Struts configuration files, graphically. For those who have done a significant amount of Struts development in the past, you know that managing the configuration file is the most difficult part. JBuilder 10 is a dream.

2.      Creation of DynaForms is as simple as JavaBeans.

3.      Promotion of forwards to global forwards.

4.      Quick and easy access to implementation classes.

5.      Quick and easy addition of the Validation plugin or Tiles Plugin.

6.      Struts tag support in JSP pages

The rest of this paper will detail many of these benefits as we talk through creating a Struts application in JBuilder 10.


Struting a JBuilder 10.0 Application - Tutorial

Setting up the JBuilder Project

There is nothing to download, there is nothing to configure!!! JBuilder 10 out of the box supports Struts 1.1. It already has a library setup on install.

Create the Project

Create a new project in JBuilder. All the defaults should be fine. The default server should be tomcat 4.0. If it is not change it to Tomcat 4.0 or 4.1.

Create a Web Application

Select File|New. From the Object Gallery select Web Application.

Notice that the next dialog provides an option for Struts support.

After entering a application name, selecting Struts 1.1, select OK. Notice the web application now has a virtual folder named Struts 1.1. This is where all your Struts 1.1 configuration files will be (sort of). Currently struts-config.xml and tiles-def.xml will show up in this folder. Validation.xml isnt there yet for some reason.

Here is what just happened. The struts-config.xml file was created, with DTD and was configured in the web.xml file. The struts libraries were add to the project and added as a dependencies for the web application (so they will be built into the WAR file). The ActionServlet was configured in the web.xml file. The web.xml file was configured with all the struts tag lib entries as well as a mapping for the *.do.


Creating the JSP pages in JBuilder

Now that we are setup let's create a logon example. This example was specifically picked because there were lots of examples on the web to reference, including the examples with struts. So you can compare and contrast if you run into issues. Additionally there are enough of the MVC concepts that you should be able to quickly get the point and move on to your on projects. Additionally I'll be doing a book store example for the presentation which will be available for download. First we will need 3 JSP view pages.

  1. The logon page -- Will look at this in more detail below.
  2. The success page -- just a simple page that indicates a successful log on.
  3. The failure --Just a simple page that indicates a failed attempt.

Step 1: Create JSP Pages

First lets just add a JSP page to JBuilder. This will be the logon JSP page so lets modify it to have 2 input text fields and 1 submit button. It should look like this.

The logon.jsp page

<html>
<head>
<title>
Logon
</title>
</head>
<body bgcolor="#ffffff">
<h1>
Logon Page
</h1>
<br />
<form action="/logon.do">
User Name: <input type="text" name="username"/>
<br />
Password: <input type="password" name="password"/>
<br />
<input type="Submit"/>
</form>
</body>
</html>

This jsp example is show to show off some the JBuilder functionality. After writing the JSP page, select the jsp in the project pane, then from the context menu select the convert to Struts option. This will convert all the tags to struts.

Too cool!

The Struts logon.jsp page

<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<%@ taglib uri="/WEB-INF/struts-template.tld" prefix="template" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html:html>
<head>
<title>
Logon
</title>
</head>
<body bgcolor="#ffffff">
<h1>
Logon Page
</h1>
<br />
<html:form action="/logon.do">
User Name: <html:text property="username"/>
<br />
Password: <html:password property="password"/>
<br />
<html:submit property=""/>
</html:form>
</body>
</html:html>

Items to note:

  1. Many of the tags are strut tags, including the form tag.
  2. The action is to logon.do. This will be explained in greater detail later.

The Struts logon.jsp page a few Struts Additions

Lets add a few struts details to the JSP and show off some JBuilder. In the editor edit the jsp, html:form tag just after the /logon.do press the space key. Look Struts tag support.

Add focus support to the username. Then add <html:errors/> support. The resulting jsp is shown below.

<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<%@ taglib uri="/WEB-INF/struts-template.tld" prefix="template" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html:html>
<head>
<title>
Logon
</title>
</head>
<body bgcolor="#ffffff">
<h1>
Logon Page
</h1>
<html:errors />
<br />
<html:form action="/logon.do" focus="username" >
User Name: <html:text property="username"/>
<br />
Password: <html:password property="password"/>
<br />
<html:submit property=""/>
</html:form>
</body>
</html:html>

Items to note:

  1. Notice the convenience of the focus attribute on the form tag. This was added in the later stages of struts. It creates javascript based on it setting.
  2. The html:errors tag, this is the location that error message will appear in the case that a validation error occurs. Oh yeah, I forgot to tell you , validation is part of the framework.

Create the other JSP pages. One is named Success.jsp, the other is Failure.jsp. They should just indicate success or failure. The code is available for download.


Step 2: Create ActionForms

Next lets take the easy way to creating a form bean. Again there are a couple of ways to manage this. The older way still exists which is to go to the object gallery and select new actionform. The other way is to go the struts-config editor and in the structure pane, select actionforms, right-mouse and select ActionForm wizard. Give your ActionForm a name and a package name. Here comes the magic on the 2nd page of the wizard, select from jsp page, select the logon.jsp and look attributes. And they are cased correctly. Additionally after the wizard is complete, it creates the ActionForm class, configures it in the struts-config file.

package net.codementor.logon;
 
import org.apache.struts.action.*;
import javax.servlet.http.*;
 
public class LogonForm extends ActionForm
{
    private String password;
    private String username;
    public String getPassword()
    {
        return password;
    }
    public void setPassword(String password)
    {
        this.password = password;
    }
    public String getUsername()
    {
        return username;
    }
    public void setUsername(String username)
    {
        this.username = username;
    }
    public ActionErrors validate(ActionMapping actionMapping, HttpServletRequest httpServletRequest)
    {
        /**@todo: finish this method, this is just the skeleton.*/
        return null;
    }
    public void reset(ActionMapping actionMapping, HttpServletRequest httpServletRequest)
    {
    }
}

For the Action Form, will extend the ActionForm class. Here the minimum required is to provide properties for every field on the JSP form.


Step 3: Create Action Class

From the struts-config structure pane or from the object gallery, select new action class wizard. After giving the class a package and name, the 2nd page has form beans in the drop down list.

Complete the rest of the wizard. Remember to change the action path to logon instead of the default logonAction. Here is the code that will be generated.

package com.codementor.logon;
import org.apache.struts.action.*;
import javax.servlet.http.*;
public class LogonAction extends Action
{
    public ActionForward execute(ActionMapping actionMapping, ActionForm actionForm, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)
    {
        /**@todo: complete the business logic here, this is just a skeleton.*/
        LogonForm logonForm = (LogonForm) actionForm;
        throw new java.lang.UnsupportedOperationException("Method perform() not yet implemented.");
    }
}

 

Lets put some logic in this class. The logic will default to failure. It will check to see if the user name is borcon. If it is it will forward to success. Realize at this point that these are logical names and could be mapped to anything. This mapping is made in the struts-config file. Below is the resulting code.

package com.codementor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
public class LogonAction extends Action
{
    public ActionForward execute(ActionMapping mapping,
                                 ActionForm actionForm,
                                 HttpServletRequest httpServletRequest,
                                 HttpServletResponse httpServletResponse)
    {
        LogonForm form = (LogonForm) actionForm;
        String forward = "failure";
        httpServletRequest.getAttribute("");
        if (form.getUsername().equals("borcon"))
        {
            forward = "success";
        }
        return mapping.findForward(forward);
    }
}

If you looked at Struts in the early days, you need to take another look. The Action bean used to implement an interface, now it extends the action class. There is some debate on this in the newsgroups, but that's the way it is.

So... extend the Action class, and provide the implementation for at least the perform method, which returns the find forward mapping. Pay attention to this string mapping as it will be important.

Also notice the form being passed in; It will obviously extend ActionForm ( probably a bad name ), and we'll cast it to our form. But if you look close, you notice that the form has values in it and we didn't provide any code. This is due to the properties of the ActionForm having the same names as the names used in the attributes of the html form tags.


Step 4: Configure the Forwards

You ready for some cool stuff!

Select the Struts Configuration file to edit. In the structure pane, double click the /logon. Now you are editing the Action in the editor. It should look like this.

Now from the project pane, drop the Failure.jsp page to the grayed out <forward> on the editor, until the grayed out icon shows a red border.

Do the same for the success page until the diagram looks like the following

Since the default forward names are the names we used in the action class, we are ready to run. Notice that we didnt once have to work with the struts configuration file directly.


Step 5: Test your project!

Right Mouse click on the logon.jsp page. Select web run. Type in "borcon", you should go to the success page. Anything else goes to the failure page. Try putting a break point in the action bean and debugging your application.


Struts Fundamentals

This section describes in details the fundamental elements of struts. First we describe in detail the configuration file, its general layout with examples how to leverage each element. Then well walk through the core of the struts framework on the Java side, examining all the ActionForms available. This section finishes with a detailed look at each of the action classes.

Struts Configuration File

The configuration file by a defacto standard is named struts-config.xml file, however this name is arbitrary. The file is configured in the web.xml file as an initial parameter for the ActionServlet defined for the parameter named config.

  <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>
    <init-param>
      <param-name>debug</param-name>
      <param-value>2</param-value>
    </init-param>
    <init-param>
      <param-name>application</param-name>
      <param-value>ApplicationResources</param-value>
    </init-param>
    <load-on-startup>2</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>

 

The struts configuration file defines the following elements for struts:

7         DataSources

7         Form Beans

7         Global Exceptions

7         Global Forwards

7         Actions

7         Controllers

7         Message Resources

7         Plugins

Its a good practice to order the file in this fashion, as it makes it more convenient when not using a tool to find what youre looking for. Lets look at examples for each configuration option.

DataSources

Although I would recommend using other data sources first, such as ones defined by the application server, Jboss / WAS / BEA, struts does define a way to configure the data source in the struts config file.

<data-sources>
        <data-source>
               <set-property property="driverClass
                       value="org.postgresql.Driver"/>
               <set-property property="password value="mypassword"/>
               <set-property property="url
               value="jdbc:postgresql://localhost/mydatabase"/>
     <set-property property="user value="myusername"/>
   </data-source>
 </data-sources>

Form Beans

This section of the struts configuration file details the form bean. The next section we look at the details of the possibility and options for form beans in more detail, however its necessary to know for this section of xml there are 2 basic types of form beans. The first is a Java class which extends the ActionForm class. The other is the DynaActionForm which isnt extended by the developer, it is configured in the xml file.

The details of a standard ActionForm class looks like this.

<form-beans>
    <form-bean name="logonForm" type="com.codementor.LogonForm" />
</form-beans>

When working with Dynaforms there is much more to configure. Heres an example:

  <form-beans>
    <form-bean name="logonForm" type="org.apache.struts.action.DynaActionForm">
      <form-property name="userName" type="java.lang.String" />
      <form-property name="password" type="java.lang.String" />
    </form-bean>
  </form-beans>

Here a form bean is created with the properties of username and password. Additionally the initial value and size of the property could be specified.

Global Exceptions

Struts defines a way to handle exceptions declaratively. These declarations for exception handling can be handled locally on a per action basis. This section of xml allows for the declaration of exception handling which will be common to all actions unless overridden locally for an action.

<global-exceptions>
        <exception
               type="app.ExpiredPasswordException"
               path="/changePassword.jsp"/>
</global-exceptions>

In this case the Exception type is provided for the type. For a catch all you could configure java.lang.Exception. Like many paths in struts the path is really a resource uri, meaning it could be the name of a title def,etc.

Global Forwards

Forwards is the term given to the mechanism of struts which transfers (forwards) the request to another configured resources. This commonly is an action, a tile definition or a JSP. Global Forwards allow a common forward which would likely be configured a number of times as a local forward to several actions to be configured once. Again the global forward can be override at a local forward level if necessary. Additionally it is extremely useful to configure global forwards for common url references within your web application, not just for your internal resource needs. This allows for updates to urls to be configured in one location.

<global-forwards>
   <forward name="Home" path="/viewHome.do" />
   <forward name="Logon" path="/Logon.jsp" />
</global-forwards>

Here the name is the moniker used in the Action class or specified in the struts JSP tag. The path is really a resource uri, meaning it could be the name of a title def,etc.

Actions / Action Mappings

Action Mappings is where strut actions are configured. In a couple of sections well list all the action classes available in struts and provided details on their unique configuration needs. Below is an example of a standard action configuration.

<action name="logonForm" path="/logon" 
        input="/Login.jsp"  scope="request" 
        type="com.codementor.LogonAction" >
    <forward name="success" path="/Success.jsp" />
    <forward name="failure" path="/Failure.jsp" />
</action>

The attributes of this xml node can be confusing to developers just starting out. The name seems like it would be the name of the action. It is not! Its the name of the form bean that will be used with this action. It is possible to have a action that does not specify a form bean as well. The path is the key to this action. It means if a logon.do is requested from this struts application, then this action will be involved. The path attribute is required.

The input page is intended to the page the request is coming from. Regardless if it is or not, it is the page that the request will be sent to if the action is configured to validate the form bean and the form returns a validation.

The scope is the scope that the form bean is configured in for this action. It is possible for a form bean to be configured for multiple actions. If the scope is specified for session for multiple actions the actions will be using the same form bean. It is important to note that session is the default scope.

The type is the class which provides the action or code implementation for this action. The execute method of this action will be invoked when a request for the logon.do is received.

Controllers

Prior to Struts 1.1, if was extremely common to see developers extending the ActionServlet, for many reasons such as logging, or security. With Struts 1.1 this isnt necessary. Struts 1.1 defines a RequestProcessor infrastructure for this purpose now. This is commonly referred to as the Struts Controller. A common controller to replace the default RequestProcessor with is the TilesRequestProcessor, below youll see how to configure it.

<controller processorClass="org.apache.struts.tiles.TilesRequestProcessor" />

Message Resources

Prior to Struts 1.1, the resource bundle was configured with the web.xml file for the ActionServlet. This feature is backward compatible and still works, developers are encouraged to now configure their property files in the struts configuration file, under the message resources. Not shown here, but this approach is significantly more flexible and powerful, as a number of resource bundles can be defined here with keys.

<message-resources parameter="com.codementor.ApplicationResources" /> 

Plugins

With standard Servlets it is often useful to use the initial parameters in the web.xml file to initial certain aspects of the web application or the Servlet itself. Struts does not provide this ability for action classes, however plugins provide a similar capability of initialize a web application at web application start up. A common configuration is to initialize the Tiles framework with the TilesPlugin shown below.

<plug-in className="org.apache.struts.tiles.TilesPlugin">
  <set-property property="definitions-config" value="/WEB-INF/tiles-defs.xml" />
</plug-in>

Form Beans

The form beans provide an abstraction above the standard web parameter and query string mechanism. Form beans are intended to be tightly couple to the view. JSP pages provide the view, accessing a form bean for the dynamic data that is to be displayed. The compiled JSP also populates the form bean when submitted. There are 4 types of ActionForms defined in the framework:

7         ActionForm

7         ValidatorActionForm

7         DynaActionForm

7         DynaValidatorActionForm

Although there are 4 types of form beans, the intention for all four are the same, providing model access to the controlling actions and to the view.

ActionForm

ActionForm is a basic Form for Struts which follows the standard rules for JavaBeans, essentially providing a group of properties. Additionally the ActionForm defines two methods:

1)     public void reset(ActionMapping mapping, HttpServletRequest request) { }

a.      Provides a way to reset the properties of the form.

b.      Typically used when the form bean is used in cache of the session scope.

c.      Think of as a constructor or the init() of the bean

2)     public ActionErrors validate(ActionMapping mapping, HttpServletRequest request)

a.      Used to provide validation when action is configured to do so.

ValidatorActionForm

This class is the required super class for forms involved with validation with the validation framework. A later section will go into greater detail. ValidatorActionForm is subclass of ActionForm. It is used just like the ActionForm, with the exception that you do not want to override the validate() method. Under the covers the ValidatorActionForm overrides the validate() method in order to provide validation.

DynaActionForm

The DynaActionForm is quite different the examples previously provided. It is a class that is already provided by the Struts and is not extended. It is configured as an ActionForm in the struts configuration file, like such:

  <form-beans>
    <form-bean name="logonForm" type="org.apache.struts.action.DynaActionForm">
      <form-property name="userName" type="java.lang.String" />
      <form-property name="password" type="java.lang.String" />
    </form-bean>
  </form-beans>

The difference here is the logonForm isnt a java class, so it is not strongly type in the action class. The framework provides checks that the property is of the specified type. In the action class instead of casting the ActionForm to the specific user-defined type, you cast it to the DynaActionForm. Heres an example of accessing the DynaForm.

DynaActionForm form = (DynaActionForm)actionForm;
form.get("userName");

DynaValidatorActionForm

The DynaValidatorActionForm is a DynaActionForm and is configured and managed exactly the same. The difference is the DynaValidatorActionForm is also a ValidatorForm, meaning it works with the validator framework. It is required if you desire to work with DynaForms using the validator framework.

Action Classes

The action classes define the behavior, flow and logic of the application. Struts provides several actions to accomplish this task. It most cases it is intended that the developer will extend a particular type of action and provide the desired behavior. All of the actions are configured in the struts-config.xml file with a path attribute. The path attribute is the key to that actions invocation. The well detail the following action classes:

7         Action

7         DispatchAction

7         LookupDispatchAction

7         ForwardAction

7         TilesAction

Action

Action classes are user-defined Actions which extend the Action class. It is required for all Actions to override the execute method to provide the necessary logic followed by a return of a forward mapping.

Action Class
public class LogonAction extends Action {
 
  public ActionForward execute( ActionMapping mapping,
                               ActionForm actionForm,
                               HttpServletRequest request,
                               HttpServletResponse response) {
 
    LogonForm logonForm = (LogonForm) actionForm;
 
    String forward = "failure";
    if(logonForm.getUserName().equals("mentor"))
    {
      forward = "success";
    }
    return mapping.findForward(forward);
  }
}
Action Configuration
<action  input="/Login.jsp" name="logonForm" path="/logon" scope="request" type="com.codementor.LogonAction">
   <forward name="success" path="/Success.jsp" />
   <forward name="failure" path="/Failure.jsp" />
</action>

DispatchAction

Working with standard Java Web components you may be familiar with a Servlet having a doPost() and a doGet(). Commonly this was used to provide the view of information from the doGet() and the submission of changes through the doPost() in the same Servlet. Struts does not provide this same type of mechanism. Addition thought must go into a design as to provide more actions to cover the same behavior to use one of the DispatchActions.

DispatchActions are subclasses of the Action Class. It is intend that the developer will extend the DispatchAction with a user defined class. However instead of overriding the execute method, the developer creates methods with the same signature as the execute method with arbitrary names.

public ActionForward <method.name>(ActionMapping mapping,
        ActionForm actionForm,
        HttpServletRequest request,
        HttpServletResponse response) throws Exception {

So if the class has an arbitrary named execute method how does the framework know how to invoke it? And what if there are more than one method?

First defining more than one method in a DispatchAction is the point, if you were going to define only one you may as well use the Action class instead. The answer to method discovery is in the configuration of the action in the configuration file. Lets look at a quick example.

Action Class
public class LogonAction extends DispatchAction {
 
  public ActionForward login( ActionMapping mapping,
                               ActionForm actionForm,
                               HttpServletRequest request,
                               HttpServletResponse response) {
    LogonForm logonForm = (LogonForm) actionForm;
 
    String forward = "failure";
    if(logonForm.getUserName().equals("mentor"))
    {
      forward = "success";
    }
    return mapping.findForward(forward);
  }
 
 public ActionForward sendPassword( ActionMapping mapping,
                               ActionForm actionForm,
                               HttpServletRequest request,
                               HttpServletResponse response) {
 
    return mapping.findForward("passwd");
  }
} 

Here we changed the LogonAction to be a DispatchAction and defined a login method (with its original behavior), adding the sendPassword method as well.

Action Configuration
<action input="/Login.jsp" name="logonForm" parameter="action" path="/logon" type="com.codementor.LogonAction">
   <forward name="passwd" path="/Password.jsp" />
   <forward name="failure" path="/Failure.jsp" />
</action>

Notice the parameter attribute added to the action xml element. This indicates that a parameter is now required. The path defines the action and the parameter defines the method. For instance, localhost:8080/sample/logon.do?action=login, would invoke the login method of that action. This is incredibly cool when used on a page where the buttons are defined with the name action and the value of the method to invoke. Lets look at how that JSP might look:

JSP Code
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<html:html>
<head>
<title>
Login Form
</title>
</head>
<body bgcolor="#ffffff">
<html:errors/>
<html:form  action="/logon" focus="userName">
        User Name: <html:text maxlength="16" property="userName" size="16"/><br />
        Password: <html:text maxlength="16" property="password" size="16"/><br />
 
<html:submit property="action" value="login"></html:submit>
<html:submit property="action" value="sendPassword"></html:submit>
</html:link>
<html:reset value="Reset"/>
</html:form>
</body>
</html:html>

In this case, the button depressed will determine the action performed.

LookupDispatchAction

Theres one problem with the DispatchAction; in the case of using the cool button trick just mentioned the button for sending a password reads sendPassword. Its not cased correctly nor does it look appealing. Those crazy clients seem to want good aesthetics with their functionality. The LookupDispatchAction solves the problem, providing all the functionality of the DispatchAction. It is coded the same way except the super class is the LookupDispatchAction and it requires the implementation of one abstract method, the getKeyMethodMap() method.

Heres the extension to the DispatchAction above:

  protected Map getKeyMethodMap() {
    HashMap map = new HashMap();
    map.put("button.login","login");
    map.put("button.password","sendPassword");
    return map;
  }

In this case, the buttons use the message resource bundle to provide the display names.

Resource Bundle
button.login=Login
button.password=Send Password
JSP Code
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<html:html>
<head>
<title>
Login Form
</title>
</head>
<body bgcolor="#ffffff">
<html:errors/>
<html:form  action="/logon" focus="userName">
        User Name: <html:text maxlength="16" property="userName" size="16"/><br />
        Password: <html:text maxlength="16" property="password" size="16"/><br />
 
<html:submit property="action"><bean:message key="button.login"/></html:submit>
<html:submit property="action"> <bean:message key="button.password"/></html:submit>
</html:link>
<html:reset value="Reset"/>
</html:form>
</body>
</html:html>

Here the bean:message for the submit buttons looks up the display names. The same key which is used for the button lookup is used in the map returned by the getKeyMethodMap() method. Now the button has an aesthetic display name such as Send Password and the button is tied to the sendPassword method. Additionally you havent exposed your internal code to the outside world.

ForwardAction

The forward action provides a way to map an action path to another resource. This is extreme useful when working with Tiles. Its also a good way to provide abbreviated action names to other actions, for example a dispatch action which requires a specific parameter yet may be called often.

Forward Configuration

There are 2 configurations for the forward action. The long hand includes the type attribute equal to the ForwardAction. Heres the short hand.

<action path="/home" forward="index.jsp"/>

The forward could be to any uri resource.

TilesAction

This action will be covered in more detail in the Tiles section. It is significant because it has a slightly different method signature.

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

Forwards

Forwards are defined globally and local to an action. The forwards are logical strings (monikers) which are associated with a resource. The resource is configured with the path attribute. It can be a JSP page, a Tiles definition, an action, a Servlet or any number of web resources. Forwards by default are request forwards in the web sense, however they can also be configured to provide a redirect as soon below. With a redirect the browser address location is changed. Technically the browser is told to request another page and is handed the page to request for. The original request is lost. In other words the web request isnt passed to a redirect.

<forward name="success" path="/Success.jsp" redirect="true />


Struts Application Development

Common Tags

Its easy to get lost in the sea of tags available in the struts framework. Just as there are hundreds of thousands of words in the English language and people tend to use three to four thousand as a base of normal conversation, there is a small set of tags which are necessary to have a full grasp of in order to make a struts web application. Listed below is the set of tags which I commonly work with in a web application.

7         html:form

7         html:img

7         html:image

7         html:errors

7         html:link

7         html:multibox

7         html:radio

7         html:checkbox

7         html:text

7         html:select

7         html:options

7         bean:write

7         bean:define

7         logic:iterator

7         logic:match

7         logic:equal

7         logic:notEqual

7         Nested versions of all these tags

7         tiles:insert

7         tiles:put

 

Note on running JSP pages

If you are trying to access a JSP page which has struts tags in it prior to accessing an action, the <load-on-startup> must be specified in web.xml for the ActionServlet. For some reason this is a common omission. If accessed after an action, its fine, but prior to an action without the load on startup will cause a failure to occur. The struts tags require initialization by the ActionServlet to function.

html:link

The struts link tag has four types of links which can really make development and management of the application easier after you get use to it. The first is the forward link.

Forward
<html:link forward=Home>

The forward tag works in conjunction with the struts configuration file and looks up global forwards and replaces the link if the forward URL encoded correctly. This is a great way to manage external links as well as to have a common string name that represents a location.

Action
<html:link action=login>

The action style of the link also works in conjunction with the struts configuration file in that it looks up action mappings and replaces the url for this link with a properly encoded link to that action. This removes the style of Servlet mapping from you site so if necessary it can change over time.

Page
<html:link page=login.do>

This type of link is used to encode links which are not in the struts-config file.

href
<html:link href="javascript:history.back(1)">

This type of link is used when you do not want the url encoded. It is extremely useful when the link has javascript embedded in it such as the example above.

anchors
<html:link action="wages/DefWageReport" anchor="SSN">

It is possible to combine the link styles above with an anchor as demonstrated.

Passing parameters

It is also possible to send parameters to the link. This would work with all the link types listed above. The first approach is to just send one parameter.

<nested:link forward="selectDrug" paramId="drugID" paramProperty="id">

In this example assuming the forward selectDrug is selectDrug.do, the url would be selectDrug.do?drugID=301. This also assumes that the form bean has a property named ID and its value at this time was 301.

Another approach would be necessary in order to send more than one parameter. This requires that all the parameters are wrapped up in a Map were the keys are the parameter names and the values are the parameter values. Assuming a map with drugID=301 and docID=101, and that map accessible through the form bean through a property named prescription, the resulting struts link might look like this:

<nested:link forward="selectDrug" paramName="prescription">
 
Resulting in: selectDrug.do?drugID=301&docID=101

Working with Form Tags

Html:form

The html:form tag obviously creates the form tag, however it is also required by the form based tags. The form based tag are required to be nested in a html:form tag. There several addition benefits of using the struts form tag:

-         Use an action name as the action of the form. This reduces the dependency of the Servlet mapping through the application. This is a seeming small benefit, but one which is easy. (i.e., <html:form action=/logon"> instead of <html:form action=/logon.do">)

-         Use the focus attribute to have javascript added to your page which onload with focus the field. (i.e., <html:form action=/logon" focus=userName>

Submission techniques

In order to submit a form in a struts JSP there are a few approaches to learn:

Submit button

Regular submit button <html:submit value=Submit /> is the first approach. It can also be written <html:submit>Submit</html:submit>. This tag must be in a form tag for the JSP to compile.

Additionally multiple submit button can be coded to use the DispatchAction or LookupDispatchAction approach. That might look like this:

<html:submit property="btn"><bean:message key="update.amend" /></html:submit>
<html:submit property="btn"><bean:message key="add.employees" /></html:submit>

In this case the selected submit button with have a value which will be assigned to the property, this looks like a parameter to the framework and the correct method is invoked.

Image tag

There are two image tags in struts. By convention one is html:img and the other html:image. The img tag is an image which can be used any where on the jsp page. The image is a submit tag which must nested in a struts form tag.

<html:form action=/action.do>
        <html:link src="/images/emp_button_view_report.gif" />
</html:form>

Like the submit tag, the property tag may be used to provide the DispatchAction affect.

Submitting Issues

What if you want to submit to another action from the same form?

One option would be through javascript change the action of the form.

<html:image src=images/emp_button_run_model.gif onclick=document.forms[0].action=runModel.do border=0 />

What if you wanted to submit from outside the form tag?

Not necessarily a struts solution, javascript to the rescue.

document.forms[0].submit()

Form Fields

html:text

Using the struts text field gets and sets the values of the form bean.

<html:text property=userName />
html:select

This tag is more complex. First an understanding of html is necessary. An html select looks like:

<select name="employees">
        <option value="101" selected="selected">Ken</option>
        <option value=102>Tammy</option>
        <option >Amanda</option>       
</select>

Where the value selected is assigned to employees when the form is submitted. By default Ken is selected. The elements may have values associated or they may not. If Ken is selected a submitted, the employees property would be assigned the value of 101. The value of Amanda is Amanda.

When working with struts the select statement it is simple. For example, <html:select property=employee > would create a select tag whose value would submit to the employee property. However there are several ways to work with the options of select statements in struts; hard-coding (struts and straight html), array of Strings and Collections.

Hard-coding

Sounds evil, but lets remember we are talking about JSPs. Heres a full example:

<html:select property=employee>
        <html:options value=Ken />
        <html:options value=Tammy />
        <html:options value=Amanda />
</html:select>

In this case the html produced looks like <option value=Ken>Ken</option> for the first option.

String Arrays

Assuming a form bean with a property named employeeList which is an array of Strings. In this case all the work of populating the String array is executed in the action prior to the page being displayed.

<html:select property=employee>
        <html:options name=employeeList />
</html:select>
Collections

It is possible to have a collection of Strings, but lets add a little more value to the example. For the example the collection will hold an array of Employee objects. The employee object is just a POJO which has a name and employeeID property which looks like:

public class Employee {
  private String name;
  private String employeeID;
    public String getName()     {
        return name;
    }
    public void setName(String name)     {
        this.name = name;
    }
    public String getEmployeeID()     {
        return employeeID;
    }
    public void setEmployeeID(String employeeID)     {
        this.employeeID = employeeID;
    }
}

Heres the code for the new select.

<html:select property=employee>
        <html:options collection=employeeList property=employeeID         labelProperty=name />
</html:select>

When this page is being displayed, the collection employeeList is iterated. Each element will create an option tag. The display label of the option will be the name of the employee. The value will be the employeeID. The value of the employee property of the form bean, if set to a valid employeeID from the list, will be the default value of the select box. Upon submission of the page the value of the employee property will be set to the employeeID of the selected employee.

checkbox

html:multibox

Many times when working with checkboxes on an html page the intent is to work with a related set of options. Struts make this extremely easy with the multibox tag. Where the checkbox tag works with Booleans, the multibox works with String[]. Lets look at an example:

<html:multibox property="benefits" >401K</html:multibox>401K
<html:multibox property="benefits" >Health</html:multibox>Health
<html:multibox property="benefits" >Dental</html:multibox>Dental

Here all the tags reference the same property of the form bean. That property, benefits, is a String[]. If the user selected 401K and Health the string array would have these 2 elements in the array and not the Dental. Its important to note if you use the multibox that you must zero out the String[] in the reset method of the form bean. This is based on how html works.

Heres an extended example of providing a list employees to select for a project team.

<logic:iterate id=employee" property=employees">
  <html:multibox property=selectedEmployees">
   <bean:write name=employee property=employeeID/> 
  </html:multibox> 
   <bean:write name=employee property=name/> 
</logic:iterate>


Validation Framework

Web validation can be broken into two validation locations; client-side and server-side. This section will focus mostly on the server-side validation, however it should be noted there are techniques in the struts validation framework which configure javascript for download to the client for client-side validation. Within the struts framework there are several options for server-side validation, they include form bean validation, action class validation as well as using the validation framework. First well look into form bean and action class validation, and then well detail the validation framework.

Common Validation Classes

Java Classes

In order to understand how the validation framework works, you must understand the java.text.MessageFormat provided by the JDK. This class is used to format parameterized strings. It essentially replaces tokens or marks placed in the string with argument values. The marks are denoted as a single digit number wrapped in a {}, for example {0} or {1}. The range is 0-9. Its easiest just to show an example.

        String message = "The disk named {0} contains {1} files.";
        String[] args = {"Foo","300"};
        System.out.println(MessageFormat.format(message,args));

This example would produce the output: The disk named Foo contains 300 files. As demonstrated the zero element of the string array replaces the {0} marker.

Struts Classes

The validation framework makes heavy use of the property file. Use the <message-resources /> tag detailed above to include a property file for the application.

The are two main error classes in Struts to know of; the ActionErrors and the ActionError. The ActionErrors is a grouping of ActionError.

Bean Validation

The struts 1.0 way of validating was through the form bean. This required the developer to override the validate method and to configure the action in the action mappings with the attribute validate=true.

public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
    ActionErrors errors = new ActionErrors();
    if ( (userName == null) || (userName.length() < 1)) {
      errors.add("userName", new ActionError("error.username.required"));
    }
    if ( (password == null) || (password.length() < 1)) {
      errors.add("password", new ActionError("error.password.required"));
    }
    return errors;
  }

In this example if the user name is empty and ActionError will be created, added to the ActionErrors object and returned indicating a validation error. This approach ties the validation in the form bean requiring compilation for changes.

Validation Framework

The validation framework, new to Struts 1.1, over comes some of the limitations of the older approach. The framework is a set of validation rules (which can be extended and added to). The rules are coupled to the form beans through XML.

Rules and Validation

Although there can be more, there are typically 2 XML files which are used to configured the framework. The files by convention are named validation-rules.xml and validation.xml. These files are configured in the struts-config.xml file through the validator plugin.

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

The validation-rules.xml is the file where the rules are defined and configured. If not defining any user defined rules the standard validation-rules.xml provided by struts in the validation sample web application can be used. It contains all the predefined validation rules provided by the framework. Heres an example:

<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">
         <javascript><![CDATA[ 

This file is not created by the developer, merely used in configuration. It is too long to show in its entirety. As you see the rule required is defined here. It is coded in the class FieldChecks in the method validateRequired.

validation.xml

The validation.xml file is what ties everything together. It is the file that is written by the developer. Lets look at an example:

<form-validation >
  <formset>
    <form name="logonForm" >
      <field
        property="userName"
        depends="required" />
    </form>
  </formset>
</form-validation >

Here we configure the logonForm. The logonForm is the configured name of a form bean in the struts-config.xml file. The form name in the validation.xml file must match exactly the name of the bean as configured in the struts-config.xml file. Continue with the example, the property of userName is configured to be required. Thats it for configuration, however we are not done.

Code and Configuration

List above are several necessary steps in understand how to configure the framework which include:

1)     Configure ValidatorPlugin in struts-config.xml.

2)     Configure validation.xml file.

Additional steps to complete configuration include:

1)     Add error messages to the property file which is used by struts.

2)     Form bean must extend the ValidatorForm class.

3)     Code the JSP page to display the error

Error Message

The following error messages are provided with struts in the validation sample web application. They are generic and should work great as is. These need to be placed in the configured application property file.

#Struts Validator Basic Error Message
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 an byte.
errors.short={0} must be an short.
errors.integer={0} must be an integer.
errors.long={0} must be an long.
errors.float={0} must be an float.
errors.double={0} must be an double.
errors.date={0} is not a date.
errors.range={0} is not in the range {1} through {2}.
errors.creditcard={0} is not a valid credit card number.
errors.email={0} is an invalid e-mail address.
ValidatorForm

There are two validator form classes available depending on if you are using the standard form bean approach or the dyna form approach. They are ValidatorActionForm and the DynaValidatorActionForm. In order to use the validator framework you must extend one of these classes. If you are switching from using the older validation approach be careful to remove any overriding code for the validate method. It is this method of the ValidatorActionForm which provides the framework behavior for validating.

html:errors

If you desire to list all the errors at the top of the page use the <html:errors /> tag. This can further be configured to have a header and footer that which can be used to delimit your error message on the displayed page.

If you are interested in displaying just one error, usually to place the message where the error occurred on the page you can use the <html:errors property=userName/>. This will display only the error associated with the property userName.

Pre-Defined Validators

The follow are the validators which are provided in the framework.

-         Required

-         minLength

-         maxLength

-         Range

-         Date

-         Basic types (integer, long, double, float )

-         Email

-         creditCard

-         Mask

Lets look at how to configure these. The required validator weve already illustrated. It doesnt require any further configuration.

minLength
<field property=userName depends="minlength">
        <arg0 key=userName resource=false/>
        <arg1 name="minlength" 
                       key="${var:minlength}"                                        resource="false"/>
        <var>
               <var-name>minlength</var-name>
               <var-value>5</var-value>
        </var>
</field>

This configures the userName to require a minimum length. The minLength requires a configuration for the what the minimum size is. This configured in the var node. Some of the rules require input to function. Each rules which does has a var-name which it will read from the <var> node. In the case for minLength it is minLength which is coded to be 5 here.

Notice the arg0 and arg1 tags. These are used with the MessageFormat class so arg9 is the last tag that could be configured. For the argX tags there is a key attribute. This attribute is used to lookup the replace of the {0} marker in the error message with the value found in the property file for the key. In the case of arg0 here, the attribute resource=false tells the framework to not lookup the key, just use the key value in this case userName as the replacement for {0}.

The most confusing tag for some is the arg1. First it has a name attribute. This indicates if you have more than one rule defined that this is arg1 for this rule only not for all of them. This is different for arg0. In the example given arg0 will be replaced for all configured rules to have the value userName which is appropriate. arg1 also indicates that the value of the key will be used, but what is the value of the key. Here it is ${var:minLength}, which is the value of the var-name (or variable) named minLength which is 5. This provides a way to configure in one place the value of the minimum length which is used by the rule and used to display the error message.

If our property file has the following entry:

errors.minlength={0} can not be less than {1} characters.

Then an error condition for this page would report

userName can not be less than 5 characters.
maxLength

The maxLength is configured the same as minLength, except the var-name it uses is maxLength.

Range

Range really is quite the same as well, however it uses 2 vars, so let see what that would look like.

<field property=priorty depends=range">
        <arg0 key=responseForm.priority.displayname />
        <arg1 name=range" key=${var:min}   resource="false"/>
        <arg2 name=range" key=${var:max}   resource="false"/>
        <var>
               <var-name>min</var-name>
               <var-value>1</var-value>
        </var>
        <var>
               <var-name>max</var-name>
               <var-value>4</var-value>
        </var>
</field>

Additionally this error message will have 3 text markers. Notice here as well the arg0 is a key which is to looked up out of the property file.

Date
<field property=date depends=date">
        <arg0 key=responseForm.date.displayname />
        <var>
               <var-name>datePattern</var-name>
               <var-value>MM/dd/yyyy</var-value>
        </var>
</field>

Here date depends on the datePattern var. Read the javaDoc on the SimpleDateFormat for an understanding of the patterns which can be used. Although not shown here the datePattern can be looked up from the resource bundle. This provides an internationalized way of validating the pattern.

CreditCard
<field property=creditCard depends=creditCard">
        <arg0 key=responseForm.creditCard.displayname />
</field>

The credit card rule applies an algorithm on the field to validate it is a valid number for a visa, master card, etc.

Mask
<field property=postalCode depends=mask">
        <arg0 key=responseForm.postal.displayname />
        <var>
               <var-name>mask</var-name>
               <var-value>^d{5}*$</var-value>
        </var>  
</field>

The mask is a very useful rule. It uses regular expression to validate the field. The var-name is mask. In this example it validates that the field has 5 consecutive digits (non-alpha characters).

Global Constants

There is a way to define globals in the validation.xml. This could be extremely useful when using more than 2 configuration files, such as have a file that has a list of constants that is used for the company or department. Here is a configuration example:

<form-validation>
<global>
        <constant>
        <constant-name>phone</constant-name>
        <constant-value> ^(?(d{3}))?[-| ]?(d{3})[-| ]?(d{4})$</constant-value>
        </constant>
</global>

For this example we defined the format of a phone number to be (314) 555-1212. It is used in the var by specifying the value of phone as in ${phone} as shown below.

<var>
        <var-name>mask</var-name>
        <var-value>${phone}</var-value>
</var>

Multiple Rules

There is nothing to configure multiple rules for the same field. A quick example show be suffient.

<form-validation >
  <formset>
    <form name="logonForm" >
      <field  property="userName  depends="required,mask" >
               <arg0 key=logon.username.displayname />
               <var>
               <var-name>mask</var-name>
               <var-value> ^[a-zA-Z0-9]*$</var-value>
               </var>
               


Tiles

Tiles is a way of providing the benefits of frames or design with frames in mind without the headaches of frames. The browser sees one page without frames. I can it frames without frames. It provides a consistent look across the web application and can greatly reduce maintenance costs.

Consider the grapic below when considering to break up a page into logical grouping well can a tile.

From here on well provide an example of setting up tiles using a header, a footer and a body.

Configuration

There is a special request process which must be configure for tiles to function; the TilesRequestProcessor. The TilesRequestProcessor must also be configured with at least the location of the tiles definitions, commonly defined in a file named tiles-def.xml. Both of these configurations are in the struts-config.xml.

<struts-config>
        <controller processorClass="org.apache.struts.tiles.TilesRequestProcessor" />
</struts-config>

and

<plug-in className="org.apache.struts.tiles.TilesPlugin">
    <set-property property="definitions-config" value="/WEB-INF/tiles-def.xml" />
</plug-in>

Thats it! After it is configured we need to define tiles in the tiles-def.xml file and use them in the struts configuration file.

Layout

Lets start with the Layout file. A JSP page will need to define the layout of the tiles. Heres an example:

<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html:html>
<head><title><tiles:getAsString name="title"/></title></head>
 
<body bgcolor="#ffffff">
  <!--Header page information -->
  <tiles:insert attribute="header"/> <br />
 
  <!--Main body page information -->
  <tiles:insert attribute="body"/>  <br />
 
    <!--Footer page information -->
  <tiles:insert attribute="footer"/> <br />
 
</body>
</html:html>
<title>
 
 

 

footer

 

Tile Definitions

With the layout being defined, we are really to create a tile definition.

  <definition name="main" path="/Layout.jsp">
    <put name="header" value="/header.jsp" />
    <put name="footer" value="/footer.jsp" />    
  </definition>

Here we define a definition named main which uses the layout we defined. It replaces the tiles of header and footer, but not the body. This is considered to be an abstracted definition. It wouldnt be directly used as a forward in struts. Lets put this definition to use.

<definition extends="main" name="login.page">
    <put name="body" value="/Login.jsp" />
    <put name="title" value="Logon Page" />
  </definition>
 <definition extends="main" name="success.page">
    <put name="body" value="/Success.jsp" />
    <put name="title" value="Success Page" />
  </definition>

The login.page definition extends the main definition. This means that this definition uses all the configurations of the extended definition, except for the ones it overrides, in this case the body and title. Now the body of this page is the Login.jsp page, which will be displayed with the proper header and footer. The same is true for the success.page.

Additionally the <tiles:getAsString name="title"/> will be replaced with the title configured in the definition. This allows each page to have its own title.

Notice that now a change in the header or footer will be seen across the entire site.

JSP Changes

The JSP should have the html headers, titles, etc removed. Referencing the tutorial example in the begin section of this paper, here are the changes to Login.jsp

<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html:form action="logon.do" focus="userName">
<br>
        User Name: <html:text maxlength="16" property="userName size="16"/><br />
        Password: <html:text maxlength="16" property="password size="16"/><br />
<html:submit value="Submit" property="Submit"/>
<html:reset value="Reset"/>
</html:form>

And Success Page

<h1>
Successful Login
</h1>

Tiled Struts-Config.xml File

Here is the changes to the configuration file for the login example.

<struts-config>
  <form-beans>
    <form-bean name="formBean" type="com.codementor.LogonForm" />
  </form-beans>
  <action-mappings>
    <action path="/loginPage" forward="login.page" />
 
 <action input="/loginPage.do" name="formBean" path="/logon" type="com.codementor.LogonAction">
      <forward name="success" path="success.page" />
      <forward name="failure" path="failure.page" />
    </action>
  </action-mappings>

As highlighted the paths have changed to reference the tile definition names. Notice there are no action code changes. The only changes we made were in the configuration files. Additionally we added an action for the login page. Previously the login page was reference directly such as login.jsp. Now that it is a tile it can not be referenced by the browser directly and have the header and footer. The change now forces the page to be referenced as loginPage.do which forwards to the tile version of the login page.

Thats it!


Summary

If you want to take MVC to the next level the current working answer is struts. It is easy to use after your first walk through. There are many advantages of implementing a strut based solution, one of the greatest being that without recompiling, we could easily make an XML change and redirect the mapped action to some other page. This is a wonderful way to provide a web wizard such as a registration wizard.

One of it's greatest strengths is it's early adoption by many in the community which has led to a large number of support sites, as well as very good documentation on the apache site.

JBuilder 10 has just become the best tool available on the market for struts development. There are more features in JBuilder 10 for struts then can be covered in one paper. What was cover should make a new struts developer productive in JBuilder and an expert struts developer just down right excited. I cant image writing struts applications outside JBuilder anymore. Hats off to the JBuilder development team!

Happy Coding!


  Latest Comments  View All Add New RSS ATOM

Move mouse over comment to see the full text

Server Response from: SC1