4. Building Controller Components


4.1 Overview

Now that we understand how to construct the Model and View components of your application, it is time to focus on the Controller components. The framework includes a servlet that implements the primary function of mapping a request URI to an Action class. Therefore, your primary responsibilities related to the Controller are:

  • Write an ActionForm class to mediate between the Model and the View. (See also Building an ActionForm.)
  • Write an Action class for each logical request that may be received (extend the [org.apache.struts.action.Action] class).

To deploy your application, you will also need to:

  • Update the web application deployment descriptor file (in XML) for your application to reference the additional components.
  • Include the additional components with your application.


4.2 The ActionServlet


  • process user requests,
  • select the proper view to respond to the user.

Our controller delegates most of this grunt work to the Request Processor and Action classes.




4.2.1 Request Processor

The RequestProcessor is where the majority of the core processing occurs for each request. Since version 1.3, the default Request Processor (ComposableRequestProcessor) is composed using Commons Chain, which is an implementation of the Chain of Responsibility pattern (CoR). It is designed as a drop-in replacement of the Struts 1.2.x behaviour and brings greater flexibility and easier customization to the request processing process. Each step of the processing is represented as a separate Command in the Chain. By inserting, substituting, or removing Commands, you can customize the framework to work your way. Let's take a look at the default commands for the ComposableRequestProcessor Chain in turn. These Command classes are in either the org.apache.struts.chain.commands or org.apache.struts.chain.commands.servlet packages.

SetOriginalURI Store the URI of the original request in the request.
RemoveCachedMessages Removes any ActionMessages object stored in the session under Globals.MESSAGE_KEY and Globals.ERROR_KEY if the messages' isAccessed method returns true. This allows messages to be stored in the session, displayed one time, and be released.
SelectAction Determine the ActionMapping associated with this path.
AuthorizeAction If the mapping has a role associated with it, ensure the requesting client has the specified role. If the client does not, raise an error and stop processing of the request.
PopulateActionForm Populate the ActionForm associated with this request, if any.
SelectInput If validation failed, select the appropriate ForwardConfig for return to the input page.
ExecuteCommand Lookup and execute a chain command if the current ActionConfig is so-configured.
SelectForward If this mapping represents a forward, forward to the path specified by the mapping.
SelectInclude Select the include uri (if any) for the current action mapping.
PerformInclude If selected, include the result of invoking the path in this request.
CreateAction Instantiate an instance of the class specified by the current ActionMapping (if necessary).
ExecuteAction This is the point at which your Action's execute method will be called.
ExecuteForwardCommand Lookup and execute a chain command if the current ForwardConfig is so-configured.
PerformForward Finally, the process method of the RequestProcessor takes the ActionForward returned by your Action class, and uses it to select the next resource (if any). Most often the ActionForward leads to the presentation page that renders the response.

In Struts 1.2.x, Tiles processing required configuring the framework to use the TilesRequestProcessor implementation. In the Struts 1.3 Chain based request processor using Tiles simply involves configuring it to use an additional Tiles Command, and deploying the tiles sub-project jar. The following Command is in the org.apache.struts.tiles.commands package.

TilesPreProcessor Command class intended to perform responsibilities of the TilesRequestProcessor in Struts 1.2.x

4.2.2 Where did they go?

The Struts 1.2.x RequestProcessor utilized a similar but different set of messages. Here we provide a table summarizing the changes.

This chain attempts to emulate (most of) the standard request processing in the standard org.apache.struts.action.RequestProcessor class, by performing the corresponding tasks in individual Commands that are composable. The following list defines a cross reference between the processXxx methods and the Commands that perform the corresponding functionality:
processMultipart Integrated into servlet and legacy classes
processPath SelectAction (which also does processMapping)
processException ExceptionCatcher / ExceptionHandler
processLocale SelectLocale
processContent SetContentType
processNoCache RequestNoCache
processPreprocess LookupCommand with optional="true". Multiple occurrences of this can easily be added, to support additional processing hooks at any point in the chain without modifying the standard definition.
processCachedMessages RemoveCachedMessages
processMapping SelectAction (which also does processPath)
processRoles AuthorizeAction
processActionForm CreateActionForm
processPopulate PopulateActionForm
processValidate ValidateActionForm / SelectInput
processForward SelectForward
processInclude SelectInclude / PerformInclude
processActionCreate CreateAction
processActionPerform ExecuteAction

4.3 ActionForm Classes

An ActionForm represents an HTML form that the user interacts with over one or more pages. You will provide properties to hold the state of the form with getters and setters to access them. ActionForms can be stored in either the session (default) or request scope. If they're in the session it's important to implement the form's reset method to initialize the form before each use. The framework sets the ActionForm's properties from the request parameters and sends the validated form to the appropriate Action's execute method.


  • The ActionForm object also offers a standard validation mechanism. If you override a "stub" method, and provide error messages in the standard application resource, The framework will automatically validate the input from the form (using your method). See Automatic Form Validation for details. Of course, you can also ignore the ActionForm validation and provide your own in the Action object.
  • You may also place a bean instance on your form, and use nested property references. For example, you might have a "customer" bean on your ActionForm, and then refer to the property "customer.name" in your presentation page. This would correspond to the methods customer.getName() and customer.setName(String Name) on your customer bean. See the Apache Struts Taglib Developer Guides for more about using the nested syntax.

4.3.1 DynaActionForm Classes

Maintaining a separate concrete ActionForm class for each form in your application is time-consuming. It is particularly frustrating when all the ActionForm does is gather and validate simple properties that are passed along to a business JavaBean.




The types supported by DynaActionForm include:

  • java.math.BigDecimal
  • java.math.BigInteger
  • boolean and java.lang.Boolean
  • byte and java.lang.Byte
  • char and java.lang.Character
  • java.lang.Class
  • double and java.lang.Double
  • float and java.lang.Float
  • int and java.lang.Integer
  • long and java.lang.Long
  • short and java.lang.Short
  • java.lang.String
  • java.sql.Date
  • java.sql.Time
  • java.sql.Timestamp



In JSP pages using the Struts Taglib, attributes of DynaActionForm objects can be referenced just like ordinary ActionForm objects. Wherever a Struts tag refers to a "property", the tags will automatically use the DynaActionForm properties just like those of a conventional JavaBean. You can even expose DynaActionForm properties using bean:define. (Although, you can't use bean:define to instantiate a DynaActionForm, since it needs to be setup with the appropriate dyna-properties).

If you are using the Struts JSTL EL taglib, the references are, by default, different. Only properties of ordinary ActionForm objects can be directly accessed through the JSTL expression language syntax. The DynaActionForm properties must be accessed through a slightly different syntax. The JSTL EL syntax for referencing a property of an ActionForm goes like this:


The syntax for referencing a property of a DynaActionForm would be:




DynaActionForms are not a drop-in replacement for ActionForms. If you need to access DynaActionForm properties in your Action, you will need to use the map-style accessor, like myForm.get("name"). If you actively use the ActionForm object in your Action, then you may want to use conventional ActionForms instead.

DynaActionForms cannot be instantiated using a no-argument constructor. In order to simulate the extra properties, there is a lot of machinery involved in their construction. You must rely on the framework to instantiate a DynaActionForm for you, via the ActionMapping.




DynaActionForms relieve developers of maintaining simple ActionForms. For even less maintenance, try the LazyActionForm described in the following section.

4.3.2 LazyActionForm Classes

Struts Lazy ActionForm which wraps a LazyDynaBean (see Commons BeanUtils JavaDoc).

There isn't really that much to this implementation as most of the lazy behaviour is in LazyDynaBean and wrapping the LazyDynaBean is handled in the parent BeanValidatorForm. The only thing it really does is populate indexed properties which are a List type with a LazyDynaBean in the get(name, index) method.

Lazy DynaBeans provide several types of lazy behaviour:

  • lazy property addition - properties which do not exist are automatically added.
  • lazy List facilities - automatically grows a List or Array to accomodate the index value being set.
  • lazy List creation - automatic creation of a List or Array for indexed properties, if it doesn't exist.
  • lazy Map creation - automatic creation of a Map for mapped properties, if it doesn't exist.

Using this lazy ActionForm means that you don't have to define the ActionForm's properties in the struts-config.xml. However, a word of warning, everything in the Request gets populated into this ActionForm circumventing the normal firewall function of Struts forms. Therefore you should only take out of this form properties you expect to be there rather than blindly populating all the properties into the business tier.

Having said that it is not necessary to pre-define properties in the struts-config.xml, it is useful to sometimes do so for mapped or indexed properties. For example, if you want to use a different Map implementation from the default HashMap or an array for indexed properties, rather than the default List type:

                    <form-bean name="myForm" type="org.apache.struts.validator.LazyValidatorForm">
                        <form-property name="myMap" type="java.util.TreeMap" />
                        <form-property name="myBeans" type="org.apache.commons.beanutils.LazyDynaBean[]" />

Another reason for defining indexed properties in the struts-config.xml is that if you are validating indexed properties using the Validator and none are submitted then the indexed property will be null which causes validator to fail. Pre-defining them in the struts-config.xml will result in a zero-length indexed property (array or List) being instantiated, avoiding an issue with validator in that circumstance.

This implementation validates using the ActionForm name . If you require a version that validates according to the path then it can be easily created in the following manner:

                    public class MyLazyForm extends LazyValidatorForm {

                        public MyLazyForm () {


Rather than using this class, another alternative is to either use a LazyDynaBean or custom version of LazyDynaBean directly, the framework now automatically wraps objects which are not ActionForms in a BeanValidatorForm. For example:

                    <form-bean name="myForm" type="org.apache.commons.beanutils.LazyDynaBean">

For more coding examples, see the LazyValidatorForm How-To.

4.3.3 Map-backed ActionForms

The DynaActionForm classes offer the ability to create ActionForm beans at initialization time, based on a list of properties enumerated in the the framework's configuration file. However, many HTML forms are generated dynamically at request time. Since the properties of these forms' ActionForm beans are not all known ahead of time, we need a new approach.


public FooForm extends ActionForm {

    private final Map values = new HashMap();

    public void setValue(String key, Object value) {
        values.put(key, value);

    public Object getValue(String key) {
        return values.get(key);



  • The framework should look for get/set methods that take a String key parameter to find the correct sub-property value. The framework will, of course, use the keyname value from the parentheses when it calls the get/set methods.

Here is a simple example:

                    <html:text property="value(foo)"/>



Note that there is nothing special about the name "value". Your map-backed property could instead be named "property", "thingy", or any other bean property name you prefer. You can even have multiple map-backed properties on the same bean.


public FooForm extends ActionForm {

    private final List values = new ArrayList();

    public void setValue(int key, Object value) {
        values.set(key, value);

    public Object getValue(int key) {
        return values.get(key);

In your presentation pages, you access individual entries in a list-backed property by using a different special notation: listname[index]. The braces in the bean property name indicate that the bean property named listname is indexed (probably backed by a List), and that the framework should look for get/set methods that take an index parameter in order to find the correct sub-property value.

While map-backed ActionForms provide you with more flexibility, they do not support the same range of syntax available to conventional or DynaActionForms. You might have difficulty referencing indexed or mapped properties using a map-backed ActionForm. The validwhen validator (since Apache Struts 1.2.1) also does not support map-backed ActionForms.

4.4 Action Classes


public ActionForward execute(ActionMapping mapping,
                    ActionForm form,
                    ServletRequest request,
                    ServletResponse response)
                    throws Exception;

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

Since the majority of teams using the framework are focused on building web applications, most projects will only use the "HttpServletRequest" version. A non-HTTP execute() method has been provided for applications that are not specifically geared towards the HTTP protocol.




The perform method may still be used in Apache Struts 1.1 but is deprecated. The Apache Struts 1.1 method simply calls the new execute method and wraps any Exception thrown as a ServletException. The deprecated perform method was removed in Apache Struts 1.2.

4.4.1 Action Class Design Guidelines

Remember the following design guidelines when coding Action classes:



4.5 Exception Handler

You can define an ExceptionHandler to execute when an Action's execute method throws an Exception. First, you need to subclass org.apache.struts.action.ExceptionHandler and override the execute method. Your execute method should process the Exception and return an ActionForward object to tell the framework where to forward to next. Then you configure your handler in struts-config.xml like this:



If the handler attribute is not specified, the default handler stores the exception in the request attribute under the value of the Globals.EXCEPTION_KEY global key.

The possible attributes for the "exception" element are as follows:

Attribute Description Default
bundle Servlet context attribute for the message resources bundle associated with this handler. The default attribute is the value specified by the string constant declared at Globals.MESSAGES_KEY. org.apache.struts.Globals.MESSAGES_KEY
className The configuration bean for this ExceptionHandler object. If specified, className must be a subclass of the default configuration bean "org.apache.struts.config.ExceptionConfig"
extends The name of the exception handler that this will inherit configuration information from. None
handler Fully qualified Java class name for this exception handler. "org.apache.struts.action.ExceptionHandler"
key The key to use with this handler's message resource bundle that will retrieve the error message template for this exception. None
path The module-relative URI to the resource that will complete the request/response if this exception occurs. None
scope The context ("request" or "session") that is used to access the ActionMessage object [org.apache.struts.action.ActionMessage] for this exception. "request"
type Fully qualified Java class name of the exception type to register with this handler. None



4.6 PlugIn Classes



PlugIns are configured using <plug-in> elements within the framework's configuration file. See PlugIn Configuration for details.

4.7 The ActionMapping Implementation



4.8 Writing Action Mappings

How does the controller servlet learn about the mappings you want? It would be possible (but tedious) to write a small Java class that simply instantiated new ActionMapping instances, and called all of the appropriate setter methods. To make this process easier, the framework uses the Commons Digester component to parse an XML-based description of the desired mappings and create the appropriate objects initialized to the appropriate default values. See the Commons website for more information about the Digester.

The developer's responsibility is to create an XML file named struts-config.xml and place it in the WEB-INF directory of your application. The format of this document is described by the Document Type Definition (DTD) maintained at http://struts.apache.org/dtds/struts-config_1_3.dtd. This chapter covers the configuration elements that you will typically write as part of developing your application. There are several other elements that can be placed in the struts-config file to customize your application. See Configuring Applications for more about the other elements in the framework's configuration file.



  • <form-beans>
  • <global-forwards>
  • <action-mappings>



This section contains your global forward definitions. Forwards are instances of the ActionForward class returned from an Action's execute method. These map logical names to specific resources (typically JSPs), allowing you to change the resource without changing references to it throughout your application. You use a <forward> element for each forward definition, which has the following important attributes:

  • name: The logical name for this forward. This is used in your Action's execute method to forward to the next appropriate resource. Example: homepage



Other often-used attributes include:


For a complete description of the elements that can be used with the action element, see the configuration DTD or the online DTDDoc docs, and the ActionMapping documentation.

4.8.1 ActionMapping Example

Here's a mapping entry based on the MailReader example application. The MailReader application now uses DynaActionForms. But in this example, we'll show a conventional ActionForm instead, to illustrate the usual workflow. Note that the entries for all the other actions are left out:

            type="org.apache.struts.webapp.example.LogonForm" />
            redirect="false" />
            validate="true" />





<!-- Edit mail subscription -->


The configuration file includes several other elements that you can use to customize your application. See Configuring Applications for details.

4.9 Using ActionMappings for Pages




4.10 Using Wildcards in ActionMappings

[Since Apache Struts 1.2.0] As an application grows in size, so will the number of action mappings. Wildcards can be used to combine similar mappings into one more generic mapping.


<!-- Generic edit* mapping -->







  • attribute
  • catalog
  • command
  • forward
  • include
  • input
  • multipartClass
  • name
  • parameter
  • prefix
  • roles
  • suffix
  • type

Also, the action mapping properties (set using the <set-property key="foo" value="bar"> syntax) will accept wildcard-matched strings in their value attribute.


  • catalog
  • command
  • path

Like the action mapping, the action forward properties (set using the <set-property key="foo" value="bar"> syntax) will accept wildcard-matched strings in their value attribute.

4.11 Commons Logging Interface


  • If Log4J is there, use it.
  • If JDK 1.4 is there, use it.
  • Otherwise, use SimpleLog.


Because the framework uses commons-logging and, therefore, includes the necessary JAR files, you've probably had the occasional fleeting thought, "Should I use commons-logging?" The answer (surprise!) depends on the requirements for your particular project. If one of your requirements is the ability to easily change logging implementations with zero impact on your application, then commons-logging is a very good option.



package com.foo;
                    // ...
                    import org.apache.commons.logging.Log;
                    import org.apache.commons.logging.LogFactory;
                    public class Foo {
                    // ...
                    private static Log log = LogFactory.getLog(Foo.class);
                    // ...
                    public void setBar(Bar bar) {
                    if (log.isTraceEnabled()) {
                    log.trace("Setting bar to " + bar);
                    this.bar = bar;
                    // ...


For examples of using logging in the framework classes, see the Action classes in our MailReader example application.