Home

This Chapter
-Chapter 1: Model 2 and Struts
-Transfer Objects
-A Primitive Model 2 Application
-Employing View Manager and Action Manager
-Enter Struts
-A Struts Example
-The MVC-ness of Struts
-Summary

Table of Contents
-Introduction
-Chapter 1: Model 2 and Struts
-Chapter 2: Input Validation with Action Forms
-Chapter 3: The HTML Tag Library
-Chapter 4: Input Validation and Data Conversion
-Chapter 5: The Validator Plugin
-Chapter 6: The Expression Language
-Chapter 7: JSTL
-Chapter 8: The Bean Tag Library
-Chapter 9: The Logic Tag Library
-Chapter 10: Struts-EL, Nested, selectLabel
-Chapter 11: Message Handling and Internationalization
-Chapter 12: The Tiles Framework
-Chapter 13: Securing Struts Applications
-Chapter 14: The Config Object
-Chapter 15: The Persistence Layer
-Chapter 16: Object Caching
-Chapter 17: File Upload and File Download
-Chapter 18: Paging and Sorting
-Chapter 19: Preventing Double Submits
-Chapter 20: Early HttpSession Invalidation
-Chapter 21: Decorating Request Objects
-Chapter 22: How Struts Works

Previous
Next

 

Enter Struts

I know what you are going to say about the second example. Instead of fattening the controller servlet with code, we moved the code to the ActionManager class. Now, it’s the ActionManager class that is bloated with code! Also, in the previous applications we hardcoded the path and forward information, i.e. in the controller servlet or the action manager/view manager. This means, any modification to the action path or any name change to a JSP will require recompilation. Clearly, we need a better solution.

Fortunately, Struts comes to the rescue.

Struts solves many of the problems in MVC application development by providing the following features:

Note

The controller servlet in Struts is called “action servlet”, a term I will use throughout the rest of the book.

In this section, you will see how Struts can help you write Model 2 applications more rapidly. The first subsection discusses the Struts configuration file. The next subsection explains how to configure your deployment descriptor (web.xml file) to use Struts, followed by a rewrite of the previous sample applications using Struts.

The Struts Configuration File

A Struts application must have a configuration file, which by default is an XML file named struts-config.xml and resides in the WEB-INF directory. The root element of this XML file is struts-config. For now, we will focus on the configuration settings related to action and view management. Other aspects of configuration will be explained in the next chapters.

Note

A complete reference of the Struts configuration file is given in Appendix A.

The element for managing actions and views is action-mappings, which groups all actions in the Struts application. The action-mappings element can have one or many action elements. An action element represents an action and must have a path attribute, which uniquely identifies the action. For example, the previous applications had two actions, displayAddProductForm and saveProduct. In Struts, you would have the following action elements for those two actions.

<struts-config>
  <action-mappings>
    <action path="/displayAddProductForm" ... />
    <action path="/saveProduct" ... />
  </action-mappings>
</struts-config>

Just like in non-Struts Model 2 applications, a Struts action may or may not have code to execute when the action is invoked. If there is no code to run, you can simply tell Struts to forward control to a JSP. For example, the displayAddProductForm action in the app01a and app01b applications did not have any code to execute, so you could forward control to the displayAddProductForm.jsp page. In Struts, you use the forward attribute of an action element to skip the action manager and forward control directly to a view. For the displayAddProductForm action in app01a and app01b, you would have the following action element in the configuration file.

<action path="/displayAddProductForm"
  forward="/jsp/displayAddProductForm.jsp"/>

If there is code to run, you must write the code in a separate class called an action class. You then specify the fully qualified name of the action class in the type attribute of the corresponding action element. For instance, if the action class for saveProduct is myPackage.SaveProductAction, you would have the following action element.

<action path="/saveProduct"
  type="myPackage.SaveProductAction" ... />

Upon invocation of the action, Struts will instantiate the myPackage.SaveProductAction class and execute the code in it. More information on action classes can be found in the next subsection.

After the invocation of the code in an action object, Struts must forward control to a view. You use the forward child element inside an action element to specify the view:

<action path="/readConfig"
  type="myPackage.SaveProductAction">
  <forward name="success" path="/jsp/displayConfig.jsp"/>
</action>

Warning

Do not confuse the forward attribute with the forward element.

The forward element has two attributes, name and path. The name attribute specifies an identifier or a logical name for the forward element and can be any string. The path attribute specifies the path to a resource (normally a JSP) to which control will be forwarded.

An action element can have more than one forward subelement, each specifying a possible forward destination. Why you may need more than one forward element is because the code execution in your action object may branch. For example, the insert product operation in the saveProduct action may be successful or it may fail. If you want control to be forwarded to the displaySavedProduct.jsp upon a successful insert and to the error.jsp page upon a failed attempt, you would have the following action element.

<action path="/saveProduct"
  type="myPackage.SaveProductAction">
  <forward name="success" path="/jsp/displayConfig.jsp"/>
  <forward name="failed" path="/jsp/error.jsp"/>
</action>

If a forward element is used by more than one action, you can write it within the global-forwards element. For example, a Struts application may have a common error page, to which control will always be forwarded if an error occur upon the invocation of any action. In this case, you would have:

<global-forwards>
  <forward name="failed" path="/jsp/error.jsp"/>
</global-forwards>

Action, ActionForward, and ActionMapping

Let’s now look at some of the classes in the Struts Application Programming Interface (API). Of particular interest are three classes in the org.apache.struts.action package: Action, ActionForward, and ActionMapping. Struts employs the Commons Digester library to create instances of these classes based on the settings in the configuration file.

The Action class represents action objects. If your action has some code that needs to be executed upon the action invocation, you must write an action class that extends Action. You must override its execute method and write your action code there.

Suppose you have a saveProduct action that is defined as follows in the configuration file.

<action path="/saveProduct"
  type="myPackage.SaveProductAction">
  <forward name="success"
    path="/jsp/displaySavedProduct.jsp"/>
  <forward name="failed" path="/jsp/error.jsp"/>
</action>

When the action is invoked, Struts creates an instance of myPackage.SaveProductAction and calls its execute method, thus running whatever you have written in the method. Here is the signature of the execute method:

public ActionForward execute(ActionMapping mapping,
  ActionForm form, javax.servlet.ServletRequest request,
  javax.servlet.ServletResponse response) throws
    java.lang.Exception

The method returns an ActionForward, which represents a destination to which control will be forwarded. How do you create the correct ActionForward object for your execute method?

In the background, Struts reads all the forward subelements of an action element and those under the global-forwards element, if any, and creates an ActionMapping object that encapsulates this forward information. For each forward subelement in an action element, Struts creates a corresponding ActionForward object and stores it in a java.util.HashMap inside the ActionMapping object. The value of the name attribute of the forward element is used as the key for the ActionForward object. Check this action element again:

<action path="/saveProduct" type="myPackage.SaveProductAction">
  <forward name="success" path="/jsp/displaySavedProduct.jsp"/>
  <forward name="failed" path="/jsp/error.jsp"/>
</action>

For this action element, Struts creates two ActionForward objects. The first ActionForward can be used to forward control to the displaySavedProduct.jsp page. The key used for this ActionForward is success. The second ActionForward object is used to forward control to the error.jsp page. The key used for this ActionForward is failed.

When Struts calls the execute method on the corresponding Action object (i.e. an instance of myPackage.SaveProductAction), it also passes an ActionMapping object that encapsulates the two ActionForward objects. You can obtain an ActionForward by calling the findForward method on the ActionMapping object, passing the appropriate key. Here is the signature of findForward.

public ActionForward findForward(java.lang.String name);

Therefore, in your action class’s execute method, you would have something like this that returns an ActionForward object:

return mapping.findForward(key);

This will become clearer as we study the sample Struts application in the next section. For now, let’s have a look at the thing you need to do in your deployment descriptor to make Struts work.

Editing the Deployment Descriptor (web.xml)

Your web.xml file must be configured in such a way for Struts to work. First and foremost, Struts comes with a controller servlet of type org.apache.struts.action.ActionServlet. You must register this in your deployment descriptor using the following servlet element.

<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>
  <load-on-startup>1</load-on-startup>
</servlet>

The first init-param element tells Struts where to find the configuration file.

Secondly, Struts does not use a request parameter in a URL to store the action path information. Instead, it uses the servlet path. By convention, it uses the following format:

*.do

in which * is the path name.

For example, if you have decided that the path for an action is saveProduct, you will need the following URL to invoke the action:

http://domain/appName/saveProduct.do

To direct all requests whose servlet path is *.do to the Struts action servlet, use the following servlet-mapping element in your web.xml file.

<servlet-mapping>
  <servlet-name>action</servlet-name>
  <url-pattern>*.do</url-pattern>
</servlet-mapping>

Also, if you are using Struts tag libraries in your application and are referring to them indirectly, you must have tag-lib elements in your deployment descriptor. We will discuss this further in Chapter 2 and subsequent chapters.

Finally, Struts API comes packaged in the struts.jar file and some of the classes depend on the Jakarta Commons libraries. You must have all these JAR files in your WEB-INF/lib directory. This has been briefly discussed in Introduction.

Previous
Next