A simple application
First, we explain the steps that we must perform when installing and configuring a Struts application. Then, we create a sample application that displays the components of a working Struts application. The goal of this chapter is to provide we with a quick introduction to the components of a Struts application.
Obtaining and Installing the Jakarta Struts Project Before we can get started with our Struts development, we need to obtain the latest release of the Struts archive and all of its supporting archives. We need to acquire:
The latest-release Jakarta Struts binary for our operating system. For these examples, we are using Struts 1.1, which can be found at http://jakarta.apache.org/ Once we have the latest Struts release, we need to complete the following steps to prepare for the remainderof the text. We will have to complete these steps for each Struts Web application that we intend to deploy.
1. Uncompress the Struts archive to our local disk.
2. Create a new Web application directory structure. For our example, the name of our Web application is wileystruts.
3. Copy the following JAR files, extracted from the Jakarta Struts archive, to the wileystruts/WEB-INF/lib directory:
struts.jar
commons-beanutils.jar
commons-collections.jar
commons-dbcp.jar
commons-digester.jar
commons-logging.jar
commons-pool.jar
commons-services.jar
commons-validator.jar
4. Create an empty web.xml file, and copy it to the wileystruts/WEB-INF/ directory. A sample web.xml file is shown in the following code snippet:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application
2.3//EN" "http://java.sun.com/j2ee/dtds/web-app_2_3.dtd">
<web-app>
</web-app>
5. Create a basic strut-config.xml file, and copy it to the wileystruts/WEB-INF/ directory. The struts-config.xml file is the deployment descriptor for Struts applications. It is the file that glues all of the MVC (Model-View-Controller) components together. Its normal location is in the WEB-INF/ directory. We will be using this file extensively throughout the remainder of this text.
An empty struts-config.xml file is listed here:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts
Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/strutsconfig_
1_1.dtd">
<struts-config>
<message-resources parameter="wiley.ApplicationResources"/>
</struts-config>
At this point, we have all of the necessary components to build the simplest of Struts applications. As we begin the design and development of our Struts application, we will need to install and configure further Struts components as necessary. In the next section, we take we through the steps that must be accomplished when developing a Struts application.
Obtaining and Installing the Jakarta Struts Project Before we can get started with our Struts development, we need to obtain the latest release of the Struts archive and all of its supporting archives. We need to acquire:
The latest-release Jakarta Struts binary for our operating system. For these examples, we are using Struts 1.1, which can be found at http://jakarta.apache.org/ Once we have the latest Struts release, we need to complete the following steps to prepare for the remainderof the text. We will have to complete these steps for each Struts Web application that we intend to deploy.
1. Uncompress the Struts archive to our local disk.
2. Create a new Web application directory structure. For our example, the name of our Web application is wileystruts.
3. Copy the following JAR files, extracted from the Jakarta Struts archive, to the wileystruts/WEB-INF/lib directory:
struts.jar
commons-beanutils.jar
commons-collections.jar
commons-dbcp.jar
commons-digester.jar
commons-logging.jar
commons-pool.jar
commons-services.jar
commons-validator.jar
4. Create an empty web.xml file, and copy it to the wileystruts/WEB-INF/ directory. A sample web.xml file is shown in the following code snippet:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application
2.3//EN" "http://java.sun.com/j2ee/dtds/web-app_2_3.dtd">
<web-app>
</web-app>
5. Create a basic strut-config.xml file, and copy it to the wileystruts/WEB-INF/ directory. The struts-config.xml file is the deployment descriptor for Struts applications. It is the file that glues all of the MVC (Model-View-Controller) components together. Its normal location is in the WEB-INF/ directory. We will be using this file extensively throughout the remainder of this text.
An empty struts-config.xml file is listed here:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts
Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/strutsconfig_
1_1.dtd">
<struts-config>
<message-resources parameter="wiley.ApplicationResources"/>
</struts-config>
At this point, we have all of the necessary components to build the simplest of Struts applications. As we begin the design and development of our Struts application, we will need to install and configure further Struts components as necessary. In the next section, we take we through the steps that must be accomplished when developing a Struts application.
Creating First Struts Application
Now that we have Struts downloaded and installed, we can begin the development of our own sample Struts application. Our application consists of a simple set of JSP screens that queries a user for a stock symbol, performs a simple stock lookup, and returns the current price of the submitted stock. We will use this example to describe the steps that must be performed when creating any Struts application. Because Struts is modeled after the MVC design pattern, we can follow a standard development process for all of our Struts Web applications. This process begins with the identification of the application Views, the Controller objects that will service those Views, and the Model components being operated on. This process can be described using the following steps:
Define and create all of the Views, in relation to their purpose, that will represent the user interface of our application. Add all ActionForms used by the created Views to the strutsconfig. xml file.
1. Create the components of the application’s Controller.
2. Define the relationships that exist between the Views and the Controllers (strutsconfig.xml).
3. Make the appropriate modifications to the web.xml file; describe the Struts components to the Web application.
4. Run the application.
5. These steps provide a high-level description of the Struts development process. In the sections that follow, we will describe each of these steps in much greater detail.
Define and create all of the Views, in relation to their purpose, that will represent the user interface of our application. Add all ActionForms used by the created Views to the strutsconfig. xml file.
1. Create the components of the application’s Controller.
2. Define the relationships that exist between the Views and the Controllers (strutsconfig.xml).
3. Make the appropriate modifications to the web.xml file; describe the Struts components to the Web application.
4. Run the application.
5. These steps provide a high-level description of the Struts development process. In the sections that follow, we will describe each of these steps in much greater detail.
Creating the Views
When creating Views in a Struts application, we are most often creating JSPs that are a combination of JSP/HTML syntax and prepackaged Struts tag libraries. The JSP/HTML syntax is similar to any other Web page and does not merit discussion, but the specialized Struts custom tag libraries do. Currently, there are three major Struts tag libraries: Bean, HTML, and Logic. To begin the development of our application, we need to first describe the Views that will represent the user interface of our application. Two Views are associated with our sample application: index.jsp and quote.jsp.
The Index View
The Index View, which is represented by the file index.jsp, is our starting View. It is the first page our application users will see, and its purpose is to query the user for a stock symbol and submit the inputted symbol to the appropriate action. The source for index.jsp is index.jsp.
<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html>
<head>
<title>Wiley Struts Application</title>
</head>
<body>
<table width="500"
border="0" cellspacing="0" cellpadding="0">
<tr>
<td> </td>
</tr>
<tr bgcolor="#36566E">
<td height="68" width="48%">
<div align="left">
<img src="images/hp_logo_wiley.gif" width="220" height="74">
</div>
</td>
</tr>
<tr>
<td> </td>
</tr>
</table>
<html:form action="Lookup"
name="lookupForm"
type="wiley.LookupForm" >
<table width="45%" border="0">
<tr>
<td>Symbol:</td>
<td><html:text property="symbol" /></td>
</tr>
<tr>
<td colspan="2" align="center"><html:submit /></td>
</tr>
</table>
</html:form>
</body>
</html>
As we look over the source for the Index View, we will notice that it looks much like any other HTML pagecontaining a form used to gather data, with the exception of the actual form tags.
Instead of using the standard TML Form tag, like most HTML pages, the index.jsp uses a Strutsspecific Form tag: <html:form />. This tag, with its child tags, encapsulates Struts form processing. The form tag attributes used in this example are action :- Represents the URL to which this form will be submitted. This attribute is also used to find the appropriate ActionMapping in the Struts configuration file, which we will describe later in this section. The value used in our example is Lookup, which will map to an ActionMapping with a path attribute equal to Lookup.
name :- Identifies the key that the ActionForm will be referenced by. We use the value LookupForm. An ActionForm is an object that is used by Struts to represent the form data as a JavaBean. It main purpose is to pass form data between View and Controller components.
type :- Names the fully qualified class name of the form bean to use in this request. For this example, we use the value wiley.LookupForm, which is an ActionForm object containing data members matching the inputs of this form.
This instance of the <html:form /> tag is also the parent to two other HTML tags. The first of the tags is the <html:text /> tag. This tag is synonymous with the HTML text input tag; the only difference is the property attribute, which names a unique data member found in the ActionForm bean class named by the form’s type attribute. The named data member will be set to the text value of the corresponding input tag.
The second HTML tag that we use is the <html:submit /> tag. This tag simply emulates an HTML submit button. The net effect of these two tags is
=> Upon submission, the ActionForm object named by the <html:form /> tag will be created, populated with the value of the <html:text /> tags, and stored in the session.
=> Once the ActionForm object is populated with the appropriate values, the action referenced by the <html:form /> will be invoked and passed a reference to the populated ActionForm.
To use the previous two HTML tags, we must first add a taglib entry in the wileystruts application’s web.xml file that references the URI /WEB-INF/struts-html.tld. This TLD describes all of the tags in the HTML tag library. The following snippet shows the <taglib> element that must be added to the web.xml file:
<taglib>
<taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
</taglib>
Second, we must copy the struts-html.tld from the lib directory of the extracted Struts archive to the wileystruts/ WEB_INF/ directory.
Note The previous two steps are used to deploy all of the Struts tag libraries. The only difference between each library's deployment is the name of the TLD.
private String symbol;
public void setSymbol(String symbol);
public String getSymbol();
In this example, we have a single data member symbol. To satisfy the JavaBean standard, the accessors used to set the data member must be prefixed with set and get, followed by the data member name with its first letter capitalized. Next Listing contains the source for our ActionForm.
Listing: The LookupForm implementation LookupForm.java.
package wiley;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
public class LookupForm extends ActionForm {
private String symbol = null;
public String getSymbol() {
return (symbol);
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public void reset(ActionMapping mapping,
HttpServletRequest request) {
this.symbol = null;
}
}
There is really nothing special about this class. It is a simple bean that extends org.apache.struts.action.ActionForm, as must all ActionForm objects, with get and set accessors that match each of its data members. It does have one method that is specific to an ActionForm bean: the reset() method. The reset() method is called by the Struts framework with each request that uses the LookupForm. The purpose of this method is to reset all of the LookupForm’s data members and allow the object to be pooled for reuse.
To deploy the LookupForm to our Struts application, we need to compile this class, move it to the wileystruts/WEB-INF/classes/wiley directory, and add the following line to the <formbeans> section of the wileystruts/WEB-INF/struts-config.xml file:
<form-bean name="lookupForm" type="wiley.LookupForm"/>
This entry makes the Struts application aware of the LookupForm and how it should be referenced.
Listing: quote.jsp.
<html>
<head>
<title>Wiley Struts Application</title>
</head>
<body>
<table width="500"
border="0" cellspacing="0" cellpadding="0">
<tr>
<td> </td>
</tr>
<tr bgcolor="#36566E">
<td height="68" width="48%">
<div align="left">
<img src="images/hp_logo_wiley.gif" width="220" height="74">
</div>
</td>
</tr>
<tr>
<td> </td>
</tr>
<tr>
<td> </td>
</tr>
<tr>
<td> </td>
</tr>
<tr>
<td>
Current Price : <%= request.getAttribute("PRICE") %>
</td>
</tr>
<tr>
<td> </td>
</tr>
</table>
</body>
</html>
As we look over this JSP, we will notice that it contains a single JSP functional line of code. This line of code retrieves the current price from the HttpServletRequest of the submitted stock symbol. This value is placed in the HttpServletRequest by the Action object that services this request, as shown in the next section.
Creating the Controller Components
In a Struts application, two components make up the Controller. These two components are the org.apache.struts.action.ActionServlet and the org.apache. struts.action.Action classes. In most Struts applications, there is one org. apache.struts.action.ActionServlet implementation and many org.apache.struts.action.Action implementations.
The org.apache.struts.action.ActionServlet is the Controller component that handles client requests and determines which org.apache.struts.action.Action will process the received request. When assembling simple applications, such as the one we are building, the default ActionServlet will satisfy our application needs, and therefore,we do not need to create a specialized org.apache.struts.action.ActionServlet implementation. When the need arises, however, it is a very simple process. For our example, we will stick with the ActionServlet as it is delivered in the Struts packages.
The second component of a Struts Controller is the org.apache.struts. action.Action class.
As opposed to the ActionServlet, the Action class must be extended for each specialized function in our application. This class is where our application’s specific logic begins.
For our example, we have only one process to perform: looking up the value of the submitted stock symbol. Therefore, we are going to create a single org.apache.struts.action.Action bean named LookupAction. The source for our Action is shown in next Listing. As we examine this listing, be sure to pay close attention to the execute() method.
Listing: The LookupAction bean.
package wiley;
import java.io.IOException;
import javax.servlet.ServletException;
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 LookupAction extends Action {
protected Double getQuote(String symbol) {
if ( symbol.equalsIgnoreCase("SUNW") ) {
return new Double(25.00);
}
return null;
}
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
Double price = null;
// Default target to success
String target = new String("success");
if ( form != null ) {
// Use the LookupForm to get the request parameters
LookupForm lookupForm = (LookupForm)form;
String symbol = lookupForm.getSymbol();
price = getQuote(symbol);
}
// Set the target to failure
if ( price == null ) {
target = new String("failure");
}
else {
request.setAttribute("PRICE", price);
}
// Forward to the appropriate View
return (mapping.findForward(target));
}}
After examining this class, we will notice that it extends the org.apache.struts.action.Action class and contains two methods: getQuote() and execute(). The getQuote() method is a simple method that will return a fixed price (if SUNW is the submitted symbol).
The second method is the execute() method, where the main functionality of the LookupAction is found. This is the method that must be defined by all Action class
implementations. Before we can examine how the logic contained in the execute() method works, we need to examine the four parameters passed to it. These parameters are
ActionMapping:- The ActionMapping class contains all of the deployment information for a particular Action bean. This class will be used to determine where the results of the LookupAction will be sent once its processing is complete.
ActionForm:- The ActionForm represents the form inputs containing the request parameters from the View referencing this Action bean. The reference being passed to our LookupAction points to an instance of
our LookupForm.
HttpServletRequest:- The HttpServletRequest attribute is a reference to the current HTTP request object.
HttpServletResponse:- The HttpServletResponse is a reference to the current HTTP response object.
Now that we have described the parameters passed to the execute() method, we can move on to describing the actual method body. The first notable action taken by this method is to create a String object named target with a value of success. This object will be used to determine the View that will present successful results of this action.
The next step performed by this method is to get the request parameters contained in the LookupForm. When the form was submitted, the ActionServlet used Java’s reflection mechanisms to set the values stored in this object. We should note that the reference passed to the execute() method is an ActionForm that must be cast to the ActionForm implementation used by this action. The following code snippet contains the source used to access the request parameters:
// Use the LookupForm to get the request parameters
LookupForm lookupForm = (LookupForm)form;
String symbol = lookupForm.getSymbol();
Once we have references to the symbol parameters, we pass these values to the getQuote() method. This method is a simple user-defined method that will return the Double value 25.00. If the symbol String contains any values other than SUNW, then null is returned, and we change the value of our target to failure. This will have the effect of changing the targeted View. If the value was not null, then we add the returned value to the request with a key of PRICE.
At this point, the value of target equals either success or failure. This value is then passed to the ActionMapping.findForward() method, which returns an ActionForward object referencing the physical View that will actually present the results of this action. The final step of the execute() method is to return the ActionForward object to the invoking ActionServlet, which will then forward the request to the referenced View for presentation. This step is completed using the following line of code:
return (mapping.findForward(target));
To deploy the LookupAction to our Struts application, we need to compile the
LookupAction class, move the class file to the wileystruts/WEB-INF/classes/wiley directory, and add the following entry to the <action-mappings> section of the wileystruts/ WEB-INF/strutsconfig.
xml file:
<action path="/Lookup" type="wiley.LookupAction" name="lookupForm"
input="/index.jsp">
<forward name="success" path="/quote.jsp"/>
<forward name="failure" path="/index.jsp"/>
</action>
This entry contains the data that will be stored in the ActionMapping object that is passed to the execute() method of the LookupAction. It contains all of the attributes required to use this instance of the LookupAction, including a collection of keyed <forward> subelements representing the possible Views that can present the results of the LookupAction.
The first change we must make is to tell the Web application about our ActionServlet
This is accomplished by adding the following servlet definition to the wileystruts/WEBINF/ web.xml file:
<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>
<load-on-startup>1</load-on-startup>
</servlet>
This entry tells the Web application that we have a servlet named action that is implemented by the class org.apache.struts.action.ActionServlet, which, as we stated earlier, is the default ActionServlet provided with Struts. The entry defines a single servlet initialization parameter, config, that tells the ActionServlet where to find the struts-config.xml file. It also includes a load-on-startup element that tells the JSP/servlet container that we want this servlet to be preloaded when the Web application starts. We must pre-load the ActionServlet, or our Struts Views will not load all of their necessary resources.
Once we have told the container about the ActionServlet, we need to tell it when the action should be executed. To do this, we have to add a <servlet-mapping> element to the wileystruts/WEB-INF/ web.xml file:
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
Note We will notice in the previously listed index.jsp that our action does not include a .do at the end of the URL. We do not have to append the .do because it is automatically appended if we use the <html:form /> tag. If we do not use the <html:form /> tag, then we will need to append .do to the action's URL.
This mapping tells the Web application that whenever a request is received with .do appended to the URL, the servlet named action should service the request.
To begin using this application, we need to restart Tomcat and open Web browser to the following URL:http://localhost:8080/wileystruts/
If everything went according to plan, we should see a page similar
When this page loads, the following actions occur:
1. The <html:form> creates the necessary HTML used to represent a form and then checks for an instance of the wiley.LookupForm in session scope. If there was an instance of the wiley.LookupForm, then the value stored in the ActionForm’s data member will be mapped to the input element value on the form and the HTML form will be written to the response. This is a very handy technique that can be used to handle errors in form data.
2. The Index View is then presented to the user.
To move on to the next step, enter the value SUNW into the Symbol text box, and click the Submit button. This will invoke the following functionality:
3. The Submit button will cause the browser to invoke the URL named in the <html:form /> tag’s action attribute, which in this case is Lookup. When the JSP/servlet container receives this request, it looks in the web.xml file for a <servlet-mapping> with a <urlpattern> that ends with .do. It will find the following entry, which tells the container to send the request to a servlet that has been deployed with a <servlet-name> of action:
<!-- Standard Action Servlet Mapping -->
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
4. The container will find the following <servlet> entry with a <servlet-name> of action that points to the ActionServlet, which acts as the Controller for our Struts application:
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>
org.apache.struts.action.ActionServlet
</servlet-class>
</servlet>
5. The ActionServlet then takes over the servicing of this request by retrieving the previously created LookupForm, populating its symbol data member with the value passed on the request, and adding the LookupForm to the session with a key of lookupForm.
6. At this point, the ActionServlet looks for an <ActionMapping> entry in the struts-config.xml file with a <path> element equal to Lookup. It finds the following entry:
<action path="/Lookup"
type="wiley.LookupAction"
name="lookupForm"
input="/index.jsp">
<forward name="success" path="/quote.jsp"/>
<forward name="failure" path="/index.jsp"/>
</action>
7. It then creates an instance of the LookupAction class named by the type attribute. It also creates an ActionMapping class that contains all of the values in the <ActionMapping> element. Note The Struts framework does pool instances of Action classes; therefore, if the wiley.LookupAction had already been requested, then it will be retrieved from the instance pool as opposed to being created with every request.
8. It then invokes the LookupAction.execute() with the appropriate parameters. The LookupAction.execute() method performs its logic, and calls the ActionMapping.findForward() method with a String value of either success or failure.
9. The ActionMapping.findForward() method looks for a <forward> subelement with a name attribute matching the target value. It then returns an ActionForward object containing the results of the lookup, which is the value of the path attribute /quote.jsp (upon success) or /index.jsp (upon failure).
10. The LookupAction then returns the ActionForward object to the ActionServlet, which in turn forwards the request object to the targeted View for presentation. The results of a successful transaction are shown in Figure.
Figure : The wileystruts Quote View.
Note: If we submit any value other than SUNW, we will be sent back index.jsp, which is the failure path of the LookupAction. If this does happen, we will see that the input value on the index page is prepopulated with our originally submitted value. This is one of the handy errorhandling techniques provided by the Struts application.
The Index View
The Index View, which is represented by the file index.jsp, is our starting View. It is the first page our application users will see, and its purpose is to query the user for a stock symbol and submit the inputted symbol to the appropriate action. The source for index.jsp is index.jsp.
<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html>
<head>
<title>Wiley Struts Application</title>
</head>
<body>
<table width="500"
border="0" cellspacing="0" cellpadding="0">
<tr>
<td> </td>
</tr>
<tr bgcolor="#36566E">
<td height="68" width="48%">
<div align="left">
<img src="images/hp_logo_wiley.gif" width="220" height="74">
</div>
</td>
</tr>
<tr>
<td> </td>
</tr>
</table>
<html:form action="Lookup"
name="lookupForm"
type="wiley.LookupForm" >
<table width="45%" border="0">
<tr>
<td>Symbol:</td>
<td><html:text property="symbol" /></td>
</tr>
<tr>
<td colspan="2" align="center"><html:submit /></td>
</tr>
</table>
</html:form>
</body>
</html>
As we look over the source for the Index View, we will notice that it looks much like any other HTML pagecontaining a form used to gather data, with the exception of the actual form tags.
Instead of using the standard TML Form tag, like most HTML pages, the index.jsp uses a Strutsspecific Form tag: <html:form />. This tag, with its child tags, encapsulates Struts form processing. The form tag attributes used in this example are action :- Represents the URL to which this form will be submitted. This attribute is also used to find the appropriate ActionMapping in the Struts configuration file, which we will describe later in this section. The value used in our example is Lookup, which will map to an ActionMapping with a path attribute equal to Lookup.
name :- Identifies the key that the ActionForm will be referenced by. We use the value LookupForm. An ActionForm is an object that is used by Struts to represent the form data as a JavaBean. It main purpose is to pass form data between View and Controller components.
type :- Names the fully qualified class name of the form bean to use in this request. For this example, we use the value wiley.LookupForm, which is an ActionForm object containing data members matching the inputs of this form.
This instance of the <html:form /> tag is also the parent to two other HTML tags. The first of the tags is the <html:text /> tag. This tag is synonymous with the HTML text input tag; the only difference is the property attribute, which names a unique data member found in the ActionForm bean class named by the form’s type attribute. The named data member will be set to the text value of the corresponding input tag.
The second HTML tag that we use is the <html:submit /> tag. This tag simply emulates an HTML submit button. The net effect of these two tags is
=> Upon submission, the ActionForm object named by the <html:form /> tag will be created, populated with the value of the <html:text /> tags, and stored in the session.
=> Once the ActionForm object is populated with the appropriate values, the action referenced by the <html:form /> will be invoked and passed a reference to the populated ActionForm.
To use the previous two HTML tags, we must first add a taglib entry in the wileystruts application’s web.xml file that references the URI /WEB-INF/struts-html.tld. This TLD describes all of the tags in the HTML tag library. The following snippet shows the <taglib> element that must be added to the web.xml file:
<taglib>
<taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
</taglib>
Second, we must copy the struts-html.tld from the lib directory of the extracted Struts archive to the wileystruts/ WEB_INF/ directory.
Note The previous two steps are used to deploy all of the Struts tag libraries. The only difference between each library's deployment is the name of the TLD.
The ActionForm
The ActionForm used in this example contains a single data member that maps directly to the symbol input parameter of the form defined in the Index View. As I stated in the previous section, when an <html:form /> is submitted, the Struts framework populates the matching data members of the ActionForm with the values entered into the <html:input /> tags. The Struts framework does this by using JavaBean reflection; therefore, the accessors of the ActionForm must follow the JavaBean standard naming convention. An example of this naming convention is shown here:private String symbol;
public void setSymbol(String symbol);
public String getSymbol();
In this example, we have a single data member symbol. To satisfy the JavaBean standard, the accessors used to set the data member must be prefixed with set and get, followed by the data member name with its first letter capitalized. Next Listing contains the source for our ActionForm.
Listing: The LookupForm implementation LookupForm.java.
package wiley;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
public class LookupForm extends ActionForm {
private String symbol = null;
public String getSymbol() {
return (symbol);
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public void reset(ActionMapping mapping,
HttpServletRequest request) {
this.symbol = null;
}
}
There is really nothing special about this class. It is a simple bean that extends org.apache.struts.action.ActionForm, as must all ActionForm objects, with get and set accessors that match each of its data members. It does have one method that is specific to an ActionForm bean: the reset() method. The reset() method is called by the Struts framework with each request that uses the LookupForm. The purpose of this method is to reset all of the LookupForm’s data members and allow the object to be pooled for reuse.
To deploy the LookupForm to our Struts application, we need to compile this class, move it to the wileystruts/WEB-INF/classes/wiley directory, and add the following line to the <formbeans> section of the wileystruts/WEB-INF/struts-config.xml file:
<form-bean name="lookupForm" type="wiley.LookupForm"/>
This entry makes the Struts application aware of the LookupForm and how it should be referenced.
The Quote View
The last of our Views is the quote.jsp. This View is presented to the user upon successful stock symbol lookup. It is a very simple JSP with no Struts specific functionality. Next Listing contains its source.Listing: quote.jsp.
<html>
<head>
<title>Wiley Struts Application</title>
</head>
<body>
<table width="500"
border="0" cellspacing="0" cellpadding="0">
<tr>
<td> </td>
</tr>
<tr bgcolor="#36566E">
<td height="68" width="48%">
<div align="left">
<img src="images/hp_logo_wiley.gif" width="220" height="74">
</div>
</td>
</tr>
<tr>
<td> </td>
</tr>
<tr>
<td> </td>
</tr>
<tr>
<td> </td>
</tr>
<tr>
<td>
Current Price : <%= request.getAttribute("PRICE") %>
</td>
</tr>
<tr>
<td> </td>
</tr>
</table>
</body>
</html>
As we look over this JSP, we will notice that it contains a single JSP functional line of code. This line of code retrieves the current price from the HttpServletRequest of the submitted stock symbol. This value is placed in the HttpServletRequest by the Action object that services this request, as shown in the next section.
Creating the Controller Components
In a Struts application, two components make up the Controller. These two components are the org.apache.struts.action.ActionServlet and the org.apache. struts.action.Action classes. In most Struts applications, there is one org. apache.struts.action.ActionServlet implementation and many org.apache.struts.action.Action implementations.
The org.apache.struts.action.ActionServlet is the Controller component that handles client requests and determines which org.apache.struts.action.Action will process the received request. When assembling simple applications, such as the one we are building, the default ActionServlet will satisfy our application needs, and therefore,we do not need to create a specialized org.apache.struts.action.ActionServlet implementation. When the need arises, however, it is a very simple process. For our example, we will stick with the ActionServlet as it is delivered in the Struts packages.
The second component of a Struts Controller is the org.apache.struts. action.Action class.
As opposed to the ActionServlet, the Action class must be extended for each specialized function in our application. This class is where our application’s specific logic begins.
For our example, we have only one process to perform: looking up the value of the submitted stock symbol. Therefore, we are going to create a single org.apache.struts.action.Action bean named LookupAction. The source for our Action is shown in next Listing. As we examine this listing, be sure to pay close attention to the execute() method.
Listing: The LookupAction bean.
package wiley;
import java.io.IOException;
import javax.servlet.ServletException;
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 LookupAction extends Action {
protected Double getQuote(String symbol) {
if ( symbol.equalsIgnoreCase("SUNW") ) {
return new Double(25.00);
}
return null;
}
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
Double price = null;
// Default target to success
String target = new String("success");
if ( form != null ) {
// Use the LookupForm to get the request parameters
LookupForm lookupForm = (LookupForm)form;
String symbol = lookupForm.getSymbol();
price = getQuote(symbol);
}
// Set the target to failure
if ( price == null ) {
target = new String("failure");
}
else {
request.setAttribute("PRICE", price);
}
// Forward to the appropriate View
return (mapping.findForward(target));
}}
After examining this class, we will notice that it extends the org.apache.struts.action.Action class and contains two methods: getQuote() and execute(). The getQuote() method is a simple method that will return a fixed price (if SUNW is the submitted symbol).
The second method is the execute() method, where the main functionality of the LookupAction is found. This is the method that must be defined by all Action class
implementations. Before we can examine how the logic contained in the execute() method works, we need to examine the four parameters passed to it. These parameters are
ActionMapping:- The ActionMapping class contains all of the deployment information for a particular Action bean. This class will be used to determine where the results of the LookupAction will be sent once its processing is complete.
ActionForm:- The ActionForm represents the form inputs containing the request parameters from the View referencing this Action bean. The reference being passed to our LookupAction points to an instance of
our LookupForm.
HttpServletRequest:- The HttpServletRequest attribute is a reference to the current HTTP request object.
HttpServletResponse:- The HttpServletResponse is a reference to the current HTTP response object.
Now that we have described the parameters passed to the execute() method, we can move on to describing the actual method body. The first notable action taken by this method is to create a String object named target with a value of success. This object will be used to determine the View that will present successful results of this action.
The next step performed by this method is to get the request parameters contained in the LookupForm. When the form was submitted, the ActionServlet used Java’s reflection mechanisms to set the values stored in this object. We should note that the reference passed to the execute() method is an ActionForm that must be cast to the ActionForm implementation used by this action. The following code snippet contains the source used to access the request parameters:
// Use the LookupForm to get the request parameters
LookupForm lookupForm = (LookupForm)form;
String symbol = lookupForm.getSymbol();
Once we have references to the symbol parameters, we pass these values to the getQuote() method. This method is a simple user-defined method that will return the Double value 25.00. If the symbol String contains any values other than SUNW, then null is returned, and we change the value of our target to failure. This will have the effect of changing the targeted View. If the value was not null, then we add the returned value to the request with a key of PRICE.
At this point, the value of target equals either success or failure. This value is then passed to the ActionMapping.findForward() method, which returns an ActionForward object referencing the physical View that will actually present the results of this action. The final step of the execute() method is to return the ActionForward object to the invoking ActionServlet, which will then forward the request to the referenced View for presentation. This step is completed using the following line of code:
return (mapping.findForward(target));
To deploy the LookupAction to our Struts application, we need to compile the
LookupAction class, move the class file to the wileystruts/WEB-INF/classes/wiley directory, and add the following entry to the <action-mappings> section of the wileystruts/ WEB-INF/strutsconfig.
xml file:
<action path="/Lookup" type="wiley.LookupAction" name="lookupForm"
input="/index.jsp">
<forward name="success" path="/quote.jsp"/>
<forward name="failure" path="/index.jsp"/>
</action>
This entry contains the data that will be stored in the ActionMapping object that is passed to the execute() method of the LookupAction. It contains all of the attributes required to use this instance of the LookupAction, including a collection of keyed <forward> subelements representing the possible Views that can present the results of the LookupAction.
Deploying our Struts Application
Now we have all of the necessary Struts components deployed and modified. Next, we need to tell the Web application itself about our application components. To do this, we must make some simple changes to the web.xml file.The first change we must make is to tell the Web application about our ActionServlet
This is accomplished by adding the following servlet definition to the wileystruts/WEBINF/ web.xml file:
<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>
<load-on-startup>1</load-on-startup>
</servlet>
This entry tells the Web application that we have a servlet named action that is implemented by the class org.apache.struts.action.ActionServlet, which, as we stated earlier, is the default ActionServlet provided with Struts. The entry defines a single servlet initialization parameter, config, that tells the ActionServlet where to find the struts-config.xml file. It also includes a load-on-startup element that tells the JSP/servlet container that we want this servlet to be preloaded when the Web application starts. We must pre-load the ActionServlet, or our Struts Views will not load all of their necessary resources.
Once we have told the container about the ActionServlet, we need to tell it when the action should be executed. To do this, we have to add a <servlet-mapping> element to the wileystruts/WEB-INF/ web.xml file:
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
Note We will notice in the previously listed index.jsp that our action does not include a .do at the end of the URL. We do not have to append the .do because it is automatically appended if we use the <html:form /> tag. If we do not use the <html:form /> tag, then we will need to append .do to the action's URL.
This mapping tells the Web application that whenever a request is received with .do appended to the URL, the servlet named action should service the request.
Walking through the wileystruts Web Application
At this point, we should have completed all of the steps described in the previous section and have a deployed wileystruts Web application. In this section, we will go through this sample application and discuss each of the steps performed by Struts along the way. The purpose of this section is to provide a walkthrough that ties together all of the previously assembled components.To begin using this application, we need to restart Tomcat and open Web browser to the following URL:http://localhost:8080/wileystruts/
If everything went according to plan, we should see a page similar
When this page loads, the following actions occur:
1. The <html:form> creates the necessary HTML used to represent a form and then checks for an instance of the wiley.LookupForm in session scope. If there was an instance of the wiley.LookupForm, then the value stored in the ActionForm’s data member will be mapped to the input element value on the form and the HTML form will be written to the response. This is a very handy technique that can be used to handle errors in form data.
2. The Index View is then presented to the user.
To move on to the next step, enter the value SUNW into the Symbol text box, and click the Submit button. This will invoke the following functionality:
3. The Submit button will cause the browser to invoke the URL named in the <html:form /> tag’s action attribute, which in this case is Lookup. When the JSP/servlet container receives this request, it looks in the web.xml file for a <servlet-mapping> with a <urlpattern> that ends with .do. It will find the following entry, which tells the container to send the request to a servlet that has been deployed with a <servlet-name> of action:
<!-- Standard Action Servlet Mapping -->
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
4. The container will find the following <servlet> entry with a <servlet-name> of action that points to the ActionServlet, which acts as the Controller for our Struts application:
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>
org.apache.struts.action.ActionServlet
</servlet-class>
</servlet>
5. The ActionServlet then takes over the servicing of this request by retrieving the previously created LookupForm, populating its symbol data member with the value passed on the request, and adding the LookupForm to the session with a key of lookupForm.
6. At this point, the ActionServlet looks for an <ActionMapping> entry in the struts-config.xml file with a <path> element equal to Lookup. It finds the following entry:
<action path="/Lookup"
type="wiley.LookupAction"
name="lookupForm"
input="/index.jsp">
<forward name="success" path="/quote.jsp"/>
<forward name="failure" path="/index.jsp"/>
</action>
7. It then creates an instance of the LookupAction class named by the type attribute. It also creates an ActionMapping class that contains all of the values in the <ActionMapping> element. Note The Struts framework does pool instances of Action classes; therefore, if the wiley.LookupAction had already been requested, then it will be retrieved from the instance pool as opposed to being created with every request.
8. It then invokes the LookupAction.execute() with the appropriate parameters. The LookupAction.execute() method performs its logic, and calls the ActionMapping.findForward() method with a String value of either success or failure.
9. The ActionMapping.findForward() method looks for a <forward> subelement with a name attribute matching the target value. It then returns an ActionForward object containing the results of the lookup, which is the value of the path attribute /quote.jsp (upon success) or /index.jsp (upon failure).
10. The LookupAction then returns the ActionForward object to the ActionServlet, which in turn forwards the request object to the targeted View for presentation. The results of a successful transaction are shown in Figure.
Figure : The wileystruts Quote View.
Note: If we submit any value other than SUNW, we will be sent back index.jsp, which is the failure path of the LookupAction. If this does happen, we will see that the input value on the index page is prepopulated with our originally submitted value. This is one of the handy errorhandling techniques provided by the Struts application.


No comments:
Post a Comment