Section 3: Processing Requests with Action Objects

The Basic Struts Flow of Control

Alert: the HTML version of this tutorial is no longer being actively maintained, and still covers Struts 1.1. For additional topics, updates for Struts 1.2, and complete source code, please see Jakarta Struts Tutorial: Processing Requests with Action Objects (in PDF).

3.1 The Six Basic Steps 3.2 Example 1: One Result Mapping
3.3 Example 2: Multiple Result Mappings 3.4 Source Code
Struts Tutorial Table of Contents More Info

This section describes the steps involved in creating a bare-bones Struts application, and gives examples that illustrate these steps. The applications shown in this section are stripped-down versions that use only the minimum necessary Struts capabilities. The next few sections illustrate more complete applications.

3.1 The Six Basic Steps in Using Jakarta Struts

With Struts, the normal processing flow is that a form submits data to a URL of the form blah.do. That address is mapped by struts-config.xml to an Action object, whose execute method handles the request. One of the arguments to execute is a form bean that is automatically created and whose properties are automatically populated with the incoming form data. The Action object then invokes business logic and data-access logic, placing the results in normal beans stored in request, session, or application scope. The Action uses mapping.findForward to return a condition, and the conditions are mapped by struts-config.xml to various JSP pages. The system forwards the request to the appropriate JSP page, where the bean:write tag is used to output properties of the form bean and results beans. Optionally, both the input form and the final JSP pages can use bean:message to output standard messages and labels as defined in a system property file.

Here are the minimum steps needed to create an application that follows this process. This section will focus on the basic flow and the Action objects; the next section will show how to use beans.

  1. Modify struts-config.xml.
    Use WEB-INF/struts-config.xml to:
    • Designate Action classes to handle requests for blah.do.
    • Specify the URLs that apply in various situations.
    • Declare any form beans that are being used.
    Be sure to restart the server after modifying struts-config.xml; the file is read only when the Web application is first loaded.
  2. Define a form bean.
    This bean is a class the extends ActionForm and will represent the data submitted by the user. It is automatically populated when the input form is submitted. Beans will be discussed in the next section.
  3. Create results beans.
    In the MVC architecture, the business-logic and data-access code create the results and the JSP pages present them. To transfer the results from one layer to the other, they are stored in beans. These beans differ from form beans in that they need extend no particular class, and they represent the output of the computational process, not the input to the process. Beans will be discussed in the next section.
  4. Create an Action object to handle requests.
    The struts-config.xml file designates the Action object that handles requests for various URLs. The Action objects themselves need to do the real work: invoke the appropriate business- and data-access-logic, store the results in beans, and designate the type of situation (missing data, database error, success category 1, success category 2, etc.) that is appropriate for the results. The struts-config.xml file then decides which JSP page should apply to that situation.
  5. Create form that invokes blah.do.
    You need to create an input form whose ACTION corresponds to one of the *.do addresses listed in struts-config.xml. At a minimum, the input form should look like this:
        <FORM ACTION=".../blah.do" ...>...</FORM>
    However, in Section 5, we will discuss the advantages of using the Struts html:form tag to build this input form.
  6. Display results in JSP.
    Since Struts is built around the MVC architecture, these JSP pages should avoid JSP scripting elements whenever possible. For basic Struts, these JSP pages usually use the Struts bean:write tag, but in JSP 2.0 the JSP 2.0 expression language is a viable alternative. In complex cases, the JSP pages also use the JSP Standard Tag Library (JSTL) or the Struts looping/logic tags.

    In most cases, the JSP pages only make sense when the request is funneled through the Action, since it is the Action that invokes the logic that creates the data that the JSP pages will display. So, the JSP pages are placed in WEB-INF, where RequestDispatcher can forward to them but where clients cannot access them directly. If the JSP pages makes sense independently of the Action (e.g., if they display session data), then the JSP pages should be placed in a regular subdirectory of the Web application, and the forward entries in struts-config.xml should say <forward ... redirect="true"/>.

3.2 Example 1: One Result Mapping

In this example, the URL http://hostname/struts-test/actions/register1.do should be handled by the class RegisterAction1 (which extends Action and is in the coreservlets package). RegisterAction1 always returns "success", and this return value results in the JSP page /WEB-INF/results/result1.jsp being displayed to the client.


  1. Modify struts-config.xml.
  2. Define a form bean.
  3. Create results beans.
  4. Create an Action object to handle requests.
  5. Create form that invokes blah.do.
  6. Display results in JSP.
  7. Final results for this example.
  8. Design Strategy for URLs.

  1. Modify struts-config.xml.
    Use WEB-INF/struts-config.xml to:
    • Designate Action classes to handle requests for blah.do. In this case, we designate that RegisterAction1 should handle requests for /actions/register1.do (notice that .do is implied automatically). To accomplish this, we add an action entry to action-mappings, where action has the following attributes.
      • path: the relative path that should be mapped to the Action, minus the .do extension. Thus, path="/actions/register1" refers to http://hostname/webAppName/actions/register1.do. See this section for a discussion of why it is useful to use /actions/register1 instead of just register1 in the path.
      • type: the fully qualified class name of the Action object that should be invoked when a request for the specified path is received.
      • name, scope, and input: these attributes are omitted in this example, but are used in later examples when beans are used.
      In this case, the action element looks like this:
      <action path="/actions/register1"
              type="coreservlets.RegisterAction1">
        ...
      </action>
    • Specify the URLs that apply in various situations. In this case, we use the forward element to say that result1.jsp applies when RegisterAction1 returns "success", as follows:
      <forward name="success"
               path="/WEB-INF/results/result1.jsp"/>
    • Declare any form beans that are being used. Beans are postponed until the next section, so this step is omitted for now.

    Here is the resultant struts-config.xml (download the source code here).
    struts-config.xml
    <?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE struts-config PUBLIC ... > <struts-config> <action-mappings> <action path="/actions/register1" type="coreservlets.RegisterAction1"> <forward name="success" path="/WEB-INF/results/result1.jsp"/> </action> </action-mappings> </struts-config>
  2. Define a form bean.
    Beans are postponed until the next section, so this step is omitted for now.
  3. Create results beans.
    Beans are postponed until the next section, so this step is omitted for now.
  4. Create an Action object to handle requests.
    In general, your Action subclass should:
    • Be in a package. In this case, we have
      package coreservlets;
      This means that the class file should go in your_web_app/WEB-INF/classes/coreservlets/.
    • Add Struts-specific import statements to whatever imports are otherwise needed. In this case, we have
      import javax.servlet.http.*;
      import org.apache.struts.action.*;
    • Extend the Action class. In this case, we have
      public class RegisterAction1 extends Action {...}
    • Override the execute method. This method is defined as follows.
        public ActionForward execute(ActionMapping mapping,
                                     ActionForm form,
                                     HttpServletRequest request,
                                     HttpServletResponse response)
            throws Exception {
          ...
          }
    • Return mapping.findForward. The execute method should have one or more return values. These values will then be mapped to specific JSP pages by forward entries in struts-config.xml. In this case, we simply return "success" in all situations.
        public ActionForward execute(ActionMapping mapping,
                                     ActionForm form,
                                     HttpServletRequest request,
                                     HttpServletResponse response)
            throws Exception {
          return(mapping.findForward("success"));
        }

    For this simple example, the Action will do nothing but return "success". Here is the code (download the source code here).
    RegisterAction1.java
    package coreservlets; import javax.servlet.http.*; import org.apache.struts.action.*; public class RegisterAction1 extends Action { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { return(mapping.findForward("success")); } }
  5. Create form that invokes blah.do.
    In this case, we need an HTML form that invokes http://hostname/struts-test/actions/register1.do. We place the HTML form in the forms subdirectory and use a relative URL for the ACTION as follows.
    register1.jsp (Excerpt)
    <!DOCTYPE ...> <HTML> <HEAD><TITLE>New Account Registration</TITLE></HEAD> <BODY BGCOLOR="#FDF5E6"> <CENTER> <H1>New Account Registration</H1> <FORM ACTION="../actions/register1.do" METHOD="POST"> Email address: <INPUT TYPE="TEXT" NAME="email"><BR> Password: <INPUT TYPE="PASSWORD" NAME="password"><BR> <INPUT TYPE="SUBMIT" VALUE="Sign Me Up!"> </FORM> </CENTER> </BODY></HTML>
    The POST method is used because the form contains a password field, and .do must be listed explicitly in the URL even though it is omitted in the action declaration in struts-config.xml. (However, the html:form tag shown in the Section 5 will automatically add .do to the URL.) See this section for a discussion of why it is useful to place the forms in a subdirectory instead of in the top-level Web application directory.
  6. Display results in JSP.
    In general, there can be several possible JSP pages corresponding to the various possible return values of the execute method of the Action. In struts-config.xml, each JSP page is declared in a forward entry within the appropriate action. In this simple case, the only return value is "success", so /WEB-INF/results/result1.jsp is used in all cases. This JSP page displays a simple message, as shown below (download the source code here).
    result1.jsp
    <!DOCTYPE ..."> <HTML> <HEAD><TITLE>Success</TITLE></HEAD> <BODY BGCOLOR="#FDF5E6"> <CENTER> <H1>You have registered successfully.</H1> (Version 1) </CENTER> </BODY></HTML>
  7. Final Results.
    First, the HTML form is invoked with the URL http://localhost/struts-test/forms/register1.jsp, as follows.

    Input form

    This form is then filled in and submitted, with the form's ACTION resulting in the URL http://localhost/struts-test/actions/register1.do. This address is mapped by struts-config.xml to the RegisterAction1 class, whose execute method is invoked. This method returns a mapping.findForward with a value of "success", and that value is mapped by struts-config.xml to /WEB-INF/results/result1.jsp, which is the final result displayed to the user. However, since the JSP page is invoked with RequestDispatcher.forward, not response.sendRedirect, the URL displayed to the user is register1.do, not result1.jsp. See the following screen shot.

    Result of form submission
  8. Design Strategy: URLs.
    There are two basic options for choosing the action and form URLs in this and subsequent examples: using simple paths or using paths with subdirectories.

    Option 1: No Subdirectories Option 2: Subdirectories
    Action path gives a name only:
    <action
      path="/register1"
      ...>
    Action path gives a pseudo-directory name:
    <action
      path="/actions/register1"
      ...>
    Form placed in top-level Web application directory:
    http://hostname/struts-test
    /register1.jsp
    Form placed in Web application subdirectory:
    http://hostname/struts-test
    /forms/register1.jsp
    Form specifies only blah.do:
    <FORM
      ACTION="register1.do"
      ...>
    Form specifies path with .. or /webAppName/:
    <FORM
      ACTION="../actions/register1.do"
      ...>

    Although the first option is simpler, there are several reasons why I think the second option is preferable:

    • Having all action URLs start with a similar path (/actions in this case) makes it easier to distinguish action URLs from other URLs.
    • Having all action URLs start with a similar path makes it much easier to use web.xml to apply filters or Web application security settings to actions.
    • Having all forms in the same physical directory simplifies organization and editing of the forms.
    • Having all forms start with a similar path (/forms in this case) makes it much easier to use web.xml to apply filters or Web application security settings to forms.

3.3 Example 2: Multiple Result Mappings

In this example, the URL http://hostname/struts-test/actions/register2.do should be handled by the class RegisterAction2. The execute method of RegisterAction2 returns "success", "bad-address", or "bad-password", and these return values result in the JSP pages /WEB-INF/results/result2.jsp, /WEB-INF/results/bad-address2.jsp, and /WEB-INF/results/bad-password2.jsp, respectively.

The main new feature in this example is the use of multiple forward entries within the action element.

  1. Modify struts-config.xml.
  2. Define a form bean.
  3. Create results beans.
  4. Create an Action object to handle requests.
  5. Create form that invokes blah.do.
  6. Display results in JSP.
  7. Final results for this example.
  1. Modify struts-config.xml.
    Use WEB-INF/struts-config.xml to:
    • Designate Action classes to handle requests for blah.do. In this case, we use the action element to designate that RegisterAction2 should handle requests for /actions/register2.do (again, note that .do is implied, not listed explicitly).
    • Specify the URLs that apply in various situations. In this case, we use multiple forward elements, one for each possible return value from the execute method of the Action object.
    • Declare any form beans that are being used. Beans are postponed until the next section, so this step is omitted for now.
    Here is the resultant struts-config.xml (download the source code here).
    struts-config.xml (Excerpt)
    <?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE struts-config PUBLIC ... > <struts-config> <action-mappings> ... <action path="/actions/register2" type="coreservlets.RegisterAction2"> <forward name="bad-address" path="/WEB-INF/results/bad-address2.jsp"/> <forward name="bad-password" path="/WEB-INF/results/bad-password2.jsp"/> <forward name="success" path="/WEB-INF/results/result2.jsp"/> </action> </action-mappings> </struts-config>
  2. Define a form bean.
    Beans are postponed until the next section, so this step is omitted for now.
  3. Create results beans.
    Beans are postponed until the next section, so this step is omitted for now.
  4. Create an Action object to handle requests.
    This example is similar to the previous one except that there are multiple mapping.findForward entries. We return "bad-address" if the email address is missing, is less then three characters long, or does not contain an "@" sign. We return "bad-password" if the password is missing or is less than six characters long. Otherwise we return "success". In this simple example we use request.getParameter explicitly, but in later examples we let Struts automatically populate a bean from the request data.

    Here is the code (download the source code here).

    RegisterAction2.java
    package coreservlets; import javax.servlet.http.*; import org.apache.struts.action.*; public class RegisterAction2 extends Action { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { String email = request.getParameter("email"); String password = request.getParameter("password"); if ((email == null) || (email.trim().length() < 3) || (email.indexOf("@") == -1)) { return(mapping.findForward("bad-address")); } else if ((password == null) || (password.trim().length() < 6)) { return(mapping.findForward("bad-password")); } else { return(mapping.findForward("success")); } } }
  5. Create form that invokes blah.do.
    In this case, we need an HTML form that invokes http://hostname/struts-test/actions/register2.do. We place the HTML form in the forms subdirectory and use a relative URL for the ACTION as follows.
    register2.jsp (Excerpt)
    <!DOCTYPE ...> <HTML> <HEAD><TITLE>New Account Registration</TITLE></HEAD> <BODY BGCOLOR="#FDF5E6"> <CENTER> <H1>New Account Registration</H1> <FORM ACTION="../actions/register2.do" METHOD="POST"> Email address: <INPUT TYPE="TEXT" NAME="email"><BR> Password: <INPUT TYPE="PASSWORD" NAME="password"><BR> <INPUT TYPE="SUBMIT" VALUE="Sign Me Up!"> </FORM> </CENTER> </BODY></HTML>
  6. Display results in JSP.
    In this case, we have three possible JSP pages, as shown below (download the source code here).
    bad-address2.jsp
    <!DOCTYPE ...> <HTML> <HEAD><TITLE>Illegal Email Address</TITLE></HEAD> <BODY BGCOLOR="#FDF5E6"> <CENTER> <H1>Illegal Email Address</H1> Address must be of the form username@host. Please <A HREF="../forms/register2.jsp">try again</A>. </CENTER> </BODY></HTML>
    bad-password2.jsp
    <!DOCTYPE ...> <HTML> <HEAD><TITLE>Illegal Password</TITLE></HEAD> <BODY BGCOLOR="#FDF5E6"> <CENTER> <H1>Illegal Password</H1> Password must contain at least six characters. Please <A HREF="../forms/register2.jsp">try again</A>. </CENTER> </BODY></HTML>
    result2.jsp
    <!DOCTYPE ...> <HTML> <HEAD><TITLE>Success</TITLE></HEAD> <BODY BGCOLOR="#FDF5E6"> <CENTER> <H1>You have registered successfully.</H1> (Version 2) </CENTER> </BODY></HTML>
  7. Final Results.
    First, the HTML form is invoked with the URL http://localhost/struts-test/forms/register2.jsp, as follows.

    Input form 2

    In the first case, this form is given "Bill Gates" as an email address and is submitted.

    Form with bad email address

    The form's ACTION results in the URL http://localhost/struts-test/actions/register2.do. This address is mapped by struts-config.xml to the RegisterAction2 class, whose execute method is invoked. This method examines the email address, determines it is illegal because it lacks an "@" sign, and returns mapping.findForward with a value of "bad-address". That value is mapped by struts-config.xml to /WEB-INF/results/bad-address2.jsp, which is the final result displayed to the user for this input.

    Result for bad email address

    In the second case, the form is given a legal email address but a password that is only two characters long.

    Form with bad password

    The form's ACTION results in the URL http://localhost/struts-test/actions/register2.do. This address is mapped by struts-config.xml to the RegisterAction2 class, whose execute method is invoked. This method examines the password, determines it is too short, and returns mapping.findForward with a value of "bad-password". That value is mapped by struts-config.xml to /WEB-INF/results/bad-password2.jsp, which is the final result displayed to the user for this input.

    Result for bad password

    In the third case, the form is given a legal email address and password. The form's ACTION results in the URL http://localhost/struts-test/actions/register2.do. This address is mapped by struts-config.xml to the RegisterAction2 class, whose execute method is invoked. This method finds no problem with either the email address or the password, so returns mapping.findForward with a value of "success". That value is mapped by struts-config.xml to /WEB-INF/results/result2.jsp, which is the final result displayed to the user for this input.

    Result 2

3.4 Source Code for this Section

The following list gives the source code for all files described in this section, listed in the order that they appear.

To download the code, right-click on the links and choose "Save Target As". Be sure to reproduce the same directory structure as given here. The easiest approach is to download and unjar the entire struts-test WAR file, but this takes some time since this WAR file includes the Struts JAR files, not just the example code.

Next section: Handling Request Parameters with Form Beans

More Information

J2EE Short Courses
Personally developed and taught by the author of Core Servlets & JSP, More Servlets & JSP, and this Jakarta Struts tutorial.
Contact Marty
Send email to hall@coreservlets.com to report errors and omissions in this writeup, or to inquire about training courses on Struts, JSP, servlets, JSF, AJAX, or Java 5 programming.
References
Jakarta Struts Books
Servlet & JSP Books