Struts Basics

Sang Shin, sang.shin@sun.com, Sun Microsystems, www.javapassion.com/j2ee




In its short existence, Struts has established itself as a popular web application framework that is based on MVC (Model-View-Controller) architecture.  In this hands-on lab, you will learn the fundamental concept, architecture, and features of Struts 1.1 by building and deploying simple Struts applications, following a step-by-step guide using NetBeans. The features of Struts that will be exercised include creating ActionForm object, creating Action object, forwarding at either success or failure, validation, internationalization, and error handling.

Expected duration: 90 minutes (excluding homework)


Prerequisites

This hands-on lab assumes you have some basic knowledge or programming experience on the following  technologies.


Software Needed

Before you begin, you need to install the following software on your computer. 


OS platforms you can use

Change Log


Lab Exercises


Exercise 1: Build and run "struts-submit-solution" sample application

In this exercise, you are going to build and run "ready-to-build" Struts sample application.  You will then build the same application from scratch.

  1. Open, build, and run "struts-submit-solution" sample application

(1.1) Open, build, and run "struts-submit-solution" sample application

0. Start NetBeans IDE. 
1. Open struts-submit-solution NetBeans project. 

2. Build and run struts-submit-solution project.


Figure-1.12: Running struts-submit-solution project

3. Check input validation.


Figure-1.13: Input validation error messages

4. Enter values in the input form fields.

Figure-1.14: Message gets displayed


Summary

In this exercise,  you have built and run a ready-to-build-and-run "struts-submit-solution" sample application to get a sense how the application works.  In the next exercise, you are going to build it from scratch.

                                                                                                                        return to the top



Exercise 2: Build "struts-submit" application from scratch

In this exercise, you are going to build the struts-submit-solution application from scratch.  The goal of this exercise is to let you get exposed to a step by step process of building the same application you built and ran in the previous exercise.   Even though the "struts-submit" application is simple, it lets you explore most core features of the Struts framework listed below:


(2.1) Create a NetBeans project


1. Create a new NetBeans project.
2. Provide project name to the project.

Figure-1.20: Name and Location of the project

3. Use Struts as a Web application framework.

Figure-1.21: Add Struts 1.2.9 framework to the application

                                                                                                   return to top of the exercise

(2.2) Take a look at the IDE generated web.xml


<Learning points> Because a Struts application is a Web application, it has to follow the same rules that any Web application has to follow.  Every Web application must have a web.xml configuration file.  The web.xml file should define the ActionServlet, which functions as a controller  from the standpoint of the MVC (Model-View-Controller) framework.  In other words, every request to a Struts application has to go through the ActionServlet. The ActionServlet is provided by the Struts framework.

The example web.xml file shown  above in Code-1.22 below has three different categories of configuration information:

    * ActionServlet configuration
    * ActionServlet mapping
    * Struts tag library descriptors

Under ActionServlet configuration section, note that several initialization parameters are specified as following through <init-param> elements including the location of struts-config.xml file.


1. Take a look at IDE generated web.xml especially paying special attention to the bold-fonted comments.  For the struts-submit application you are building here, there is nothing else you have to add or modify to the IDE generated web.xml.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <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>detail</param-name>
            <param-value>2</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>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>
            index.jsp
        </welcome-file>
    </welcome-file-list>
    <jsp-config>
        <taglib>
            <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
            <taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
        </taglib>
        <taglib>
            <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
            <taglib-location>/WEB-INF/struts-html.tld</taglib-location>
        </taglib>
        <taglib>
            <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
            <taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
        </taglib>
        <taglib>
            <taglib-uri>/WEB-INF/struts-nested.tld</taglib-uri>
            <taglib-location>/WEB-INF/struts-nested.tld</taglib-location>
        </taglib>
        <taglib>
            <taglib-uri>/WEB-INF/struts-tiles.tld</taglib-uri>
            <taglib-location>/WEB-INF/struts-tiles.tld</taglib-location>
        </taglib>
    </jsp-config>
</web-app>
Code-2.20: IDE generated web.xml

                                                                                                   return to top of the exercise

(2.3) Modify "struts-config.xml" file


<Learning points> A Struts application has to have a Struts application configuration file (hereafter configuration file). As is shown in the web.xml file above, the name and location of the configuration file can be user definable. In this example and in most other simple Struts applications, the default name of the configuration file is struts-config.xml and it typically resides under application's ./WEB-INF directory.  The configuration information is then read by Struts framework when the application gets started.

The struts-config.xml file shown below in Code-2.30 contains two categories of information:

          o Form bean definitions
          o Action mapping definitions

A form bean definition is defined via <form-bean> element as a child of  <form-beans> element.  A form bean defines a JavaBean class which is used to represent the input form data that are entered by the user. Each <form-bean> element has two attributes: "name" and "type".  The "name" attribute defines a logical name of the form bean and "type" attribute specifies the full path of the form bean class. The value of the "name" attribute is used in the action mapping definition.  In the example shown below in Code-2.30, the name of the bean is "submitForm" and the name of the bean class is "submit.SubmitForm".

An action mapping definition is defined via <action> element as a child of <action-mappings> element.  Each <action> element defines the following


1. Double click struts-config.xml under struts-submit->Configuration Files to open it in the source editor.
2. Modify the struts-config.xml as shown in Code-2.30 below.  The code fragments that need to be added are highlighted in bold and blue-colored font.

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
          "http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">


<struts-config>
    <form-beans>
        <form-bean      name="submitForm"
                                 type="submit.SubmitForm"/>      
    </form-beans>
   
    <global-exceptions>
   
    </global-exceptions>

    <global-forwards>
        <forward name="welcome"  path="/Welcome.do"/>
    </global-forwards>

    <action-mappings>
        <action path="/Welcome" forward="/welcomeStruts.jsp"/>
        <action   path="/submit"
                  type="submit.SubmitAction"
                  name="submitForm"
                  input="/submit.jsp"
                  scope="request"
                  validate="true">
            <forward name="success" path="/submit.jsp"/>        
            <forward name="failure" path="/submit.jsp"/>        
        </action>
    </action-mappings>
   
    <controller processorClass="org.apache.struts.tiles.TilesRequestProcessor"/>

    <message-resources parameter="com/myapp/struts/ApplicationResource"/>   
   
    <!-- ========================= Tiles plugin ===============================-->
    <!--
    This plugin initialize Tiles definition factory. This later can takes some
    parameters explained here after. The plugin first read parameters from
    web.xml, thenoverload them with parameters defined here. All parameters
    are optional.
    The plugin should be declared in each struts-config file.
    - definitions-config: (optional)
    Specify configuration file names. There can be several comma
    separated file names (default: ?? )
    - moduleAware: (optional - struts1.1)
    Specify if the Tiles definition factory is module aware. If true
    (default), there will be one factory for each Struts module.
    If false, there will be one common factory for all module. In this
    later case, it is still needed to declare one plugin per module.
    The factory will be initialized with parameters found in the first
    initialized plugin (generally the one associated with the default
    module).
    true : One factory per module. (default)
    false : one single shared factory for all modules
    - definitions-parser-validate: (optional)
    Specify if xml parser should validate the Tiles configuration file.
    true : validate. DTD should be specified in file header (default)
    false : no validation

    Paths found in Tiles definitions are relative to the main context.
    -->
    <plug-in className="org.apache.struts.tiles.TilesPlugin" >
        <set-property property="definitions-config" value="/WEB-INF/tiles-defs.xml" />     
        <set-property property="moduleAware" value="true" />
    </plug-in>
   
    <!-- ========================= 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>
 
</struts-config>
Code-2.30: Modified struts-config.xml

                                                                                                   return to top of the exercise

(2.4) Write ActionForm class


<Learning points>  An ActionForm class captures input form data that is entered by an end user.  An ActionForm class is a JavaBean and each input form data field is mapped to a property of the ActionForm class. Consequently you write getter and setter methods for each of the properties.

In this example, there is only one ActionForm class defined and it is SubmitForm class. In the SubmitForm.java  code shown below in Code-12, you see getter and setter methods of lastname, address, sex, married, and age properties.

As was mentioned before, Struts framework creates ActionForm object instance and uses the setter methods to set the values of the properties with the input form data values that are received from the browser and then pass it as an argument to the execute() method of the Action class.

Another important piece of  code you could have inside your ActionForm class is the validate() method, in which you provide input validation logic.  In this example, the input validation logic is basically making sure the user entered something for each input field.  In other words, if nothing is entered for address field, an ActionErrors object is created and returned to Struts framework.


1. Right click struts-submit project node and select New->Java Class.
2. Observe that the New Java Class dialog box appears.
3. For the Class Name field, enter SubmitForm.
4. For the Package field, enter submit.  (Figure-2.40 below)
5. Click Finish.


Figure-2.40: Create SubmitForm.java

6. Replace the IDE generated SubmitForm.java with the one in Code-2.41 below.

package submit;

import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.*;

public final class SubmitForm extends ActionForm {
   
    /*  Getter and Setter methods of properties */
   
    /* Getter and Setter methods of Last Name property */
    private String lastName = "Your last name"; // default value
    public String getLastName() {
        return (this.lastName);
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
   
    /* Getter and Setter methods of  Address property */
    private String address = null;
    public String getAddress() {
        return (this.address);
    }
    public void setAddress(String address) {
        this.address = address;
    }
   
    /* Getter and Setter methods of  Sex property */
    private String sex = null;
    public String getSex() {
        return (this.sex);
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
   
    /* Getter and Setter methods of  Married status property */
    private String married = null;
    public String getMarried() {
        return (this.married);
    }
    public void setMarried(String married) {
        this.married = married;
    }
   
    /* Getter and Setter methods of  Age property */
    private String age = null;
    public String getAge() {
        return (this.age);
    }
    public void setAge(String age) {
        this.age = age;
    }
   
    /* Input validation */
   
    public ActionErrors validate(ActionMapping mapping,
            HttpServletRequest request) {
       
        // Log the forms data
        servlet.log("Lastname:" + lastName);
        servlet.log("Address:" + address);
        servlet.log("Sex:" + sex);
        servlet.log("Married:" + married);
        servlet.log("Age:" + age);
       
        // Check for mandatory data
        ActionErrors errors = new ActionErrors();
        if (lastName == null || lastName.equals("")) {
            errors.add("Last Name", new ActionError("error.lastName"));
        }
        if (address == null || address.equals("")) {
            errors.add("Address", new ActionError("error.address"));
        }
        if (sex == null || sex.equals("")) {
            errors.add("Sex", new ActionError("error.sex"));
        }
        if (age == null || age.equals("")) {
            errors.add("Age", new ActionError("error.age"));
        }
        return errors;
    }
   
}
Code-2.41: SubmitForm.java

                                                                                                   return to top of the exercise

(2.5) Write Action classes


<Learning points> As was mentioned before, for each request, the execute() method of the Action class get invoked by the Struts framework.  So the execute() method is the place where you want to provide business logic of your application.  In the example below, the business logic is basically changing the last name into upper case.  However, in practice, you could include more sophisticated business logic code that might access EJB's, backend database, or Web services.

Please note the arguments that are passed to the execute() method.  They are ActionMapping object, ActionForm object, and HttpServletRequest and HttpServletResponse objects.

* ActionMapping:  The ActionMapping class contains findForward("<outcome>") method that you can call within the execute() method of Action class in order to select the next page to display.   The findForward("<outcome>") method returns ActionForward object.  The Struts framework uses the returned ActionForward object and navigation rules specified in the struts-config.xml file to make a next page selection.  In the example below (Code-13), the outcome that gets returned from the execute() method is always "success".  And as you've seen above (in Step 3), in this example, the navigation rule in struts-config.xml says to display submit.jsp page when the outcome is "success" and display the same submit.jsp page when the outcome is "failure".  So in this struts-submit example, the next page that gets selected for display is always submit.jsp page.

* ActionForm: As was mentioned above, the ActionForm object captures the input data that are entered by the user. In this example, the ActionForm object is then cast to SubmitForm object. Then you can use getter methods of the SubmitForm object in order to access the data. 


1. Right click struts-submit project node and select New->Java Class.
2. Observe that the New Java Class dialog box appears.
3. For the Class Name field, enter SubmitAction.
4. For the Package field, enter submit
5. Click Finish.
6. Replace the IDE generated SubmitAction.java with the one in Code-2.51 below.

package submit;

import javax.servlet.http.*;
import org.apache.struts.action.*;

public final class SubmitAction extends Action {
   
    // The execute() method is where you provide your business logic
    public ActionForward execute(ActionMapping mapping,
            ActionForm form,
            HttpServletRequest request,
            HttpServletResponse response) {
       
        //  Cast ActionForm object to SubmitForm type
        SubmitForm f = (SubmitForm) form;
       
        //  Retrieve the value of lastname field
        String lastName = f.getLastName();
       
        //  Translate the lastname to upper case and save it Request scope
        request.setAttribute("lastName", lastName.toUpperCase());
       
        //  Create and return ActionForward object with "success" outcome
        return (mapping.findForward("success"));
    }
}
Code-2.51: SubmitAction.java

                                                                                                   return to top of the exercise

(2.6) Create ApplicationResource.properties


The ApplicationResource.properties file contains internationalized messages for this application.  These messages are used by Struts framework for displaying messages.

1. Right click com.myapp.struts package node and select New->File/Folder. (Figure-2.60 below)


Figure-2.60: Create new Properties file

2. Observe that Choose File Type pane of the New File dialog box appears.
3. Select Other on the left and select Properties File on the right.  (Figure-2.60 below)
4. Click Next.


Figure-2.60: Create Properties file

4. Observe that Name and Location pane appears.
5. For the File Name field, enter ApplicationResource. (Figure-2.61 below)
6. Click Finish.


Code-2.61: Give it name to the properties file

7. Add entries to the ApplicationResource.properties file as shown in Code-2.62 below.

# Sample ResourceBundle properties file
errors.header=<h4>Validation Error(s)</h4><ul>
errors.footer=</ul><hr>

error.lastName=<li>Enter your last name
error.address=<li>Enter your address
error.sex=<li>Enter your sex
error.age=<li>Enter your age
error.birthYear=<li>Enter the year you were born between 1900 and 2004 inclusive
Code-2.62: Modified ApplicationResource.properties file

                                                                                                   return to top of the exercise

(2.7) Write JSP pages


Now you also have to write JSP pages in which you are going to use Struts tags. In the struts-submit sample application, there is only one JSP page, submit.jsp, you have to create for now.

1. Right click struts-submit project node and select New->JSP.
2. Observe that Name and Location pane of the New JSP File dialog box appears.
3. For the JSP File Name field, enter submit.  (Figure-2.70 below)
4. Click Finish.


Figure-2.70: Create submit.jsp

5. Modified the IDE generated submit.jsp as shown in Code-2.71 below.

<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<html>
<head><title>Submit example</title></head>
<body>

<h3>Example Submit Page</h3>

<html:errors/>

<html:form action="submit.do">
Last Name: <html:text property="lastName"/><br>
Address:   <html:textarea property="address"/><br>
Sex:       <html:radio property="sex" value="M"/>Male
           <html:radio property="sex" value="F"/>Female<br>
Married:   <html:checkbox property="married"/><br>
Age:       <html:select property="age">
             <html:option value="a">0-19</html:option>
             <html:option value="b">20-49</html:option>
             <html:option value="c">50-</html:option>
           </html:select><br>
           <html:submit/>
</html:form>

<logic:present name="lastName" scope="request">
Hello
<logic:equal name="submitForm" property="age" value="a">
  young
</logic:equal>
<logic:equal name="submitForm" property="age" value="c">
  old
</logic:equal>
<bean:write name="lastName" scope="request"/>
</logic:present>

</body>
</html>
Code-2.71: Modified submit.jsp

                                                                                                   return to top of the exercise

(2.8) Build and run the application


1. Right-click struts-submit project node and select Properties
2. Observe that the Project Properties - struts-submit dialog box gets displayed.
2. Click Run under Categories.
3. For the Relative URL field, enter /submit.jsp.  (Figure-2.80 below) 
5. Click OK.


Figure-2.80: Set Relative URL

6. Right click sruts-submit and select Run Project.
7. Observe the same behavior you've seen in Exercise 1.

                                                                                                   return to top of the exercise


Summary

In this exercise, you have built and run "struts-submit" sample application step by step.
   
                                                                                                                   return to the top



Exercise 3: Add display pages and modify page navigation

In this exercise, you will add two new display pages (*.jsp files) to the struts-submit application you built in the previous exercise and also modify the page navigation rules as following.

    * For the sake of the this exercise, the execute() method of the submitAction class returns two different outcomes as following (as opposed to a single "success" outcome in the original application)
          o "success": when the lastname starts with "success"
          o "failure": all the other cases
    * For "success" outcome, the submitSuccess.jsp gets displayed next (as opposed to submit.jsp in the original application)
    * For "failure" outcome, the submitFailure.jsp gets displayed next

    1. Modify navigation rules in the "struts-config.xml" file
    2. Write submitSuccess.jsp and submitFailure.jsp files
    3. Modify SubmitAction.java
    4. Build and run the application

(3.1) Modify navigation rules in the "struts-config.xml" file


1. Right click struts-config.xml under struts-submit->Configuration Files.
2. Modify struts-config.xml as shown in Code-3.10 below.  The code fragements that need to be modified are highlighted in bold and blue-colored font.

 ...
 <action-mappings>
        <action path="/Welcome" forward="/welcomeStruts.jsp"/>
        <action   path="/submit"
                  type="submit.SubmitAction"
                  name="submitForm"
                  input="/submit.jsp"
                  scope="request"
                  validate="true">
             <forward name="success" path="/submitSuccess.jsp"/>        
             <forward name="failure" path="/submitFailure.jsp"/>        
        </action>
    </action-mappings>
...
Code-3.10: Modified struts-config.xml

                                                                                                   return to top of the exercise

(3.2) Write "submitSuccess.jsp" and "submitFailure.jsp" files


1. Create "submitSuccess.jsp"

Figure-3.20: Create submitSuccess.jsp

2. Repleace IDE generated submitSuccess.jsp with the one in Code-3.21 below. The only difference between submit.jsp and submitSuccess.jsp is highlighted in bold and blue-colored font.

<!-- Replace the contents of this file from the one in Code-15 -->
<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<html>
<head><title>Submit example</title></head>
<body>

<h3>Example Submit Success Page</h3>

<html:errors/>

<html:form action="submit.do">
Last Name: <html:text property="lastName"/><br>
Address:   <html:textarea property="address"/><br>
Sex:         <html:radio property="sex" value="M"/>Male
                <html:radio property="sex" value="F"/>Female<br>
Married:   <html:checkbox property="married"/><br>
Age:        <html:select property="age">
                  <html:option value="a">0-19</html:option>
                  <html:option value="b">20-49</html:option>
                  <html:option value="c">50-</html:option>
               </html:select><br>
           <html:submit/>
</html:form>

<logic:present name="lastName" scope="request">
Hello
<logic:equal name="submitForm" property="age" value="a">
  young
</logic:equal>
<logic:equal name="submitForm" property="age" value="c">
  old
</logic:equal>
<bean:write name="lastName" scope="request"/>
</logic:present>

</body>
</html>
Code-3.21: Modified submitSuccess.jsp

3. Create "submitFailure.jsp".
4. Repleace IDE generated submitFailure.jsp with the one in Code-3.22 below.  The only difference between submit.jsp and submitFailure.jsp is highlighted in bold and blue-colored font.

<!-- Replace the contents of this file from the one in Code-15 -->
<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<html>
<head><title>Submit example</title></head>
<body>

<h3>Example Submit Failure Page</h3>

<html:errors/>

<html:form action="submit.do">
Last Name: <html:text property="lastName"/><br>
Address:   <html:textarea property="address"/><br>
Sex:         <html:radio property="sex" value="M"/>Male
                <html:radio property="sex" value="F"/>Female<br>
Married:   <html:checkbox property="married"/><br>
Age:        <html:select property="age">
                  <html:option value="a">0-19</html:option>
                  <html:option value="b">20-49</html:option>
                  <html:option value="c">50-</html:option>
               </html:select><br>
           <html:submit/>
</html:form>

<logic:present name="lastName" scope="request">
Hello
<logic:equal name="submitForm" property="age" value="a">
  young
</logic:equal>
<logic:equal name="submitForm" property="age" value="c">
  old
</logic:equal>
<bean:write name="lastName" scope="request"/>
</logic:present>

</body>
</html>
Code-3.22: Modified submitFailure.jsp

                                                                                                   return to top of the exercise

(3.3) Modify SubmitAction.java


In this step, you are going to modify the SubmitAction.java as following:

    * If the lastName starts with "success", translate the name into uppercase and then save it in the request scope object (as it does right now in the original code) and return "success" outcome
    * Otherwise, do not save it in the request scope object and return "failure" outcome

1. Right-click SubmitAction.java under Source Packages->submit.
2. Modify SubmitAction.java as shown in Code-3.30 below.  The code fragments that need to be added are highlighted in bold and blue-colored font.

package submit;

import javax.servlet.http.*;
import org.apache.struts.action.*;

public final class SubmitAction extends Action {

  // The execute() method is where you provide your business logic
  public ActionForward execute(ActionMapping mapping,
                                              ActionForm form,
                                              HttpServletRequest request,
                                              HttpServletResponse response) {

    //  Cast ActionForm object to SubmitForm type
    SubmitForm f = (SubmitForm) form;

    //  Retrieve the value of lastname field
    String lastName = f.getLastName();

    /*************** commented out ************************
    //  Translate the lastname to upper case and save it Request scope
    request.setAttribute("lastName", lastName.toUpperCase());
      
    //  Create and return ActionForward object with "success" outcome
    return (mapping.findForward("success"));
    **************** end of the commented out code **********/

    //  If the lastName starts with "success", translate the name into uppercase and then
    //  save it in the request scope object (as it does right now in the original code) and return success.
    //  Otherwise, do not save it in the request scope object and return failure.

    if (lastName.startsWith("success") ){


         //  Translate the lastname to upper case and save it Request scope
         request.setAttribute("lastName", lastName.toUpperCase());
   
         //  Create and return ActionForward object with "success" outcome
         return (mapping.findForward("success"));
    }
    else{
         return (mapping.findForward("failure"));
    }

  }
}
Code-3.30: Modified SubmitAction.java

                                                                                                   return to top of the exercise

(3.4) Build and run the application


1. Right-click struts-submit and select Run Project.
2. Observe that browser gets displayed.
3. For the Last Name field, enter successIsMyLastname.
4. For other fields, enter appropriate values.
5. Click Submit button.


Figure-3.40: Enter last name that starts with success

6. Observe that submitSuccess.jsp page is displayed. (Figure-3.41 below)


Figure-3.41: sucessSuccess.jsp page is displayed

7. For the Last Name field, enter anyname.  (Figure-3.42 below)
8. For other fields, enter appropriate values.
9. Click Submit button.
10. Observe that successFailure.jsp page is displayed.


Figure-3.42: successFailure.jsp page is displayed

                                                                                                   return to top of the exercise

Summary


In this exercise, you learned how to add new JSP pages to the application and how to change the navigation rules in the struts-config.xml file and how to generate different outcomes from the execute() method of Action class.

                                                                                                                   return to the top


Exercise 4: Add another input form field

In this exercise, you will add another field using Struts tag and add an input validation logic for that field as following:

    * Add "Year you were born" field to the submit.jsp page
    * Perform input validation such that the number has to be between 1900 and 2004 inclusive

    1. Modify submit.jsp
    2. Modify SubmitForm.java
    3. Add error messages to the resource file
    4. Use a different error page for input validation error
    5. Modify struts-config.xml
    6. Build and run the application
Solution: The solution to this exercise is provided as a ready-to-open-and-run NetBeans project as part of hands-on lab zip file. You can find it under <LAB_UNZIPPED_DIRECTORY>/strutsbasics/samples/struts-submit-exercise4-solution.  You are welcome to just open it and run it and see how it works before doing this exercise.

(4.1) Modify submit.jsp


Since you now want to display a new text field, "The year you were born", you have to change the submit.jsp, submitSuccess.jsp, and submitFailure.jsp files. 

1. Modify submit.jsp as shown in Code-4.10 below.  The code fragements that need to be modified are highlighted in bold and blue-colored font.

<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<html>
    <head><title>Submit example</title></head>
    <body>
       
        <h3>Example Submit Page</h3>
       
        <html:errors/>
       
        <html:form action="submit.do">
            Last Name: <html:text property="lastName"/><br>
            Address:   <html:textarea property="address"/><br>
            Sex:       <html:radio property="sex" value="M"/>Male
            <html:radio property="sex" value="F"/>Female<br>
            Married:   <html:checkbox property="married"/><br>
            Age:       <html:select property="age">
                <html:option value="a">0-19</html:option>
                <html:option value="b">20-49</html:option>
                <html:option value="c">50-</html:option>
            </html:select><br>
            Year you were born:   <html:text property="birthYear"/><br>
            <html:submit/>
        </html:form>
       
        <logic:present name="lastName" scope="request">
            Hello
            <logic:equal name="submitForm" property="age" value="a">
                young
            </logic:equal>
            <logic:equal name="submitForm" property="age" value="c">
                old
            </logic:equal>
            <bean:write name="lastName" scope="request"/>
        </logic:present>
       
    </body>
</html>
Code-4.10: Modified submit.jsp

2. Make similar changes to submitSuccess.jsp and submitFailure.jsp.

                                                                                                   return to top of the exercise

(4.2) Modify SubmitForm.java


Now the newly added field, birthYear, has to have a corresponding property in the SubmitForm class.  So you need to add getter and setter methods of birthYear field.  You also want to modify the validate() method to add the validation logic of the field.

1.  Modify SubmitForm.java as shown in Code-4.20 below.  The code fragements that need to be modified are highlighted in bold and blue-colored font.

package submit;

import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.*;

public final class SubmitForm extends ActionForm {
   
    /*  Getter and Setter methods of properties */
   
    /* Getter and Setter methods of Last Name property */
    private String lastName = "Your last name"; // default value
    public String getLastName() {
        return (this.lastName);
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
   
    /* Getter and Setter methods of  Address property */
    private String address = null;
    public String getAddress() {
        return (this.address);
    }
    public void setAddress(String address) {
        this.address = address;
    }
   
    /* Getter and Setter methods of  Sex property */
    private String sex = null;
    public String getSex() {
        return (this.sex);
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
   
    /* Getter and Setter methods of  Married status property */
    private String married = null;
    public String getMarried() {
        return (this.married);
    }
    public void setMarried(String married) {
        this.married = married;
    }
   
    /* Getter and Setter methods of  Age property */
    private String age = null;
    public String getAge() {
        return (this.age);
    }
    public void setAge(String age) {
        this.age = age;
    }
   
    /* Getter and Setter methods of BirthYear property */
    private String birthYear = null;
    public String getBirthYear(){
        return (this.birthYear);
    }
    public void setBirthYear(String birthYear){
        this.birthYear = birthYear;
    }
   
    /* Input validation */
   
    public ActionErrors validate(ActionMapping mapping,
            HttpServletRequest request) {
       
        // Log the forms data
        servlet.log("Lastname:" + lastName);
        servlet.log("Address:" + address);
        servlet.log("Sex:" + sex);
        servlet.log("Married:" + married);
        servlet.log("Age:" + age);
        servlet.log("BirthYear:" + birthYear);
       
        // Check for mandatory data
        ActionErrors errors = new ActionErrors();
        if (lastName == null || lastName.equals("")) {
            errors.add("Last Name", new ActionError("error.lastName"));
        }
        if (address == null || address.equals("")) {
            errors.add("Address", new ActionError("error.address"));
        }
        if (sex == null || sex.equals("")) {
            errors.add("Sex", new ActionError("error.sex"));
        }
        if (age == null || age.equals("")) {
            errors.add("Age", new ActionError("error.age"));
        }
        if (birthYear == null || birthYear.equals("")) {
            errors.add("BirthYear", new ActionError("error.birthYear"));
        }
        else{
            int year = Integer.parseInt(birthYear);
            if ((year < 1900) || (year > 2004)){
                errors.add("BirthYear", new ActionError("error.birthYear"));
            }
        }
        return errors;
    }
   
}
Code-4.20: Modified SubmitForm.java

                                                                                                   return to top of the exercise

(4.3) Add error messages to the resource file


Now since you want to display a meaningful error message for input validation error for the birthYear field, you want to add a new message to the resource file.  The change you want to add is highlighted in bold and blue colored font.(Code-4.30 below) 

1.  Modify ApplicationResource.properties as shown in Code-4.30 below.  The code fragements that need to be modified are highlighted in bold and blue-colored font.

errors.header=<h4>Validation Error(s)</h4><ul>
errors.footer=</ul><hr>

error.lastName=<li>Enter your last name
error.address=<li>Enter your address
error.sex=<li>Enter your sex
error.age=<li>Enter your age
error.birthYear=<li>Enter the year you were born between 1900 and 2004 inclusive
Code-4.30: Modifies ApplicationResource.properties

                                                                                                   return to top of the exercise

(4.4) Use a different error page for input validation error


In this step, you are going to create a new JSP page that will get displayed when there is an input validation error.

1.  Write submitInputValidationError.jsp.
<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<html>
    <head><title>Submit example</title></head>
    <body>
       
        <h3>Example Submit Input Validation Error Page</h3>
       
        <html:errors/>
       
        <html:form action="submit.do">
            Last Name: <html:text property="lastName"/><br>
            Address:   <html:textarea property="address"/><br>
            Sex:         <html:radio property="sex" value="M"/>Male
            <html:radio property="sex" value="F"/>Female<br>
            Married:   <html:checkbox property="married"/><br>
            Age:        <html:select property="age">
                <html:option value="a">0-19</html:option>
                <html:option value="b">20-49</html:option>
                <html:option value="c">50-</html:option>
            </html:select><br>
            Year you were born:   <html:text property="birthYear"/><br>
            <html:submit/>
        </html:form>
       
        <logic:present name="lastName" scope="request">
            Hello
            <logic:equal name="submitForm" property="age" value="a">
                young
            </logic:equal>
            <logic:equal name="submitForm" property="age" value="c">
                old
            </logic:equal>
            <bean:write name="lastName" scope="request"/>
        </logic:present>
       
    </body>
</html>
Code-4.40: submitInputValidationError.jsp

                                                                                                   return to top of the exercise

(4.5) Modify struts-config.xml


1. Modify struts-config.xml as shown in Code-4.50 below.  The code fragements that need to be modified are highlighted in bold and blue-colored font.

<action   path="/submit"
              type="submit.SubmitAction"
              name="submitForm"
              input="/submitInputValidationError.jsp"
              scope="request"
              validate="true">
             <forward name="success" path="/submitSuccess.jsp"/>         
             <forward name="failure" path="/submitFailure.jsp"/>         
 </action>
Code-4.50: Input attribute of the <action> element is changed

                                                                                                   return to top of the exercise

(4.6) Build and run the application


1. Right click  struts-submit project node and select Run Project.
2. Observe that brower gets displayed.
3. Click Submit button without entering anything.
4. Observe that Example Submit Input Validation Error Page gets displayed with proper error message.  (Figure-4.60 below)

 
Figure-4.60: Example Submit Input Validation Error Page

5. For Last Name field, enter successIsMyLastname.
6. For Address field, enter whatever address you want.
7. For Sex field, choose either Male or Female.
8. For Age field, choose any.
9. For Year you were born field, enter 1800, which is not a valid year.
10.Click Submit.


Figure-4.61: Try invalid year

11. Observe that Example Submit Input Validation Error Page gets displayed with a proper error mesasge.


Figure-4.62: Example Submit Input Validation Error Page


                                                                                                   return to top of the exercise

Summary


In this exercise, you learned how to add another input form field and then how to perform input validation.

                                                                                                                   return to the top

Exercise 5: Implement DynaActionForm

The goal of this exercise is to implement DynaActionForm.  DynaActionForm is introduced in Struts 1.1 and can be used in replacement of ActionForm.  Now let's talk about why you want to use DynaActionForm instead of ActionForm.

Maintaining a separate concrete ActionForm class for each form in your Struts application is time-consuming. It is particularly so when all the ActionForm does is gathering and validating simple properties that are passed along to a business JavaBean. This bottleneck can be alleviated through the use of DynaActionForm classes. Instead of creating a new ActionForm class (actually a class that extends ActionForm class) and new getter/setter methods for each of your bean's properties, you can list its properties, type, and defaults in the Struts configuration file.

<to be provided in the future>


Homework Exercise (for people who are taking Sang Shin's "Java EE Programming online course")


1. The homework is to modify the hello1 project, which is not Struts-based yet, to use Struts framework as described below. The hello1 project is provided as part of hands-on lab zip file as <LAB_UNZIPPED_DIRECTORY>/strutsbasics/samples/hello1.  (You might want to create a new project by copying the hello1 project.  You can name the homework project in any way you want but here I am going to call it Myhello1.)
2. Send the following files to j2eehomeworks@sun.com with Subject as J2EEHomework-strutsbasics.

                                                                                                                     return to the top