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
- Struts Fundamentals
- Form Beans
- Action Classes
- Struts Configuration File
- Struts Application Development
- Working with Form Tags
- Nested Tags
- Validation Framework
- Bean Validation
- Validation Framework
- Tiles
- Summary
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.
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.
|
|

|
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.
- The logon page -- Will look at this in
more detail below.
- The success page -- just a simple page
that indicates a successful log on.
- 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:
- Many of the tags are strut
tags, including the form tag.
- 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:
- 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.
- 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 cove