Resources

SAS® AppDev Studio 3.0 Developer's Site

Struts

Struts (struts.apache.org/) is an open-source project hosted by the Apache Software Foundation (ASF), which provides a framework for building Web applications. The prime architect, Craig R. McClanahan, based Struts on the "Model 2" architecture, in which Servlets are responsible for the "flow" and data access of the Web application and JavaServer Pages handle the visual presentation. This is basically a variation of the Model-View-Controller (MVC) pattern, in which Struts provides the Controller via an ActionServlet and supporting classes. Working in conjunction with a developer-provided XML file, struts-config.xml, the ActionServlet is responsible for packaging and routing HTTP traffic to appropriate handlers. A developer-provided class extending the Struts Action class provides access to the business logic.

The Struts framework focuses primarily on the controller portion of the MVC pattern, along with some useful view components. The model portion with the business logic is pretty much outside the Struts domain and is accessed through traditional Java techniques, such as Java beans and the Data Access Object (DAO) design pattern.

As a topic, Struts is worthy of an entire book, so only a few of the most commonly-used aspects of the framework will be introduced here.

Overview
Configuration Files
Form Validation
struts-config.xml
Declarative Form Validation
Tiles

Overview

In general, when a resource is requested from the client for a Struts Web application, the resource URL will specify logical name rather than, say, a JSP. All requests are handled by the ActionServlet. The ActionServlet looks up the logical resource name in the struts-config.xml file, where that name is mapped to a corresponding Action class that you provide. The Action class execute() method accesses the desired business logic, and then returns an ActionForward instance back to the ActionServlet to tell it what to do next. Usually this ActionForward will be obtained through another logical name mapped in the struts-config.xml file to a "view" component, such as a JSP, to render the results of the request. Or, the action class might decide that the request should be forwarded to another servlet for processing, again through a logical name given in the configuration file. Having the ActionServlet delegate indirectly through the struts-config.xml file makes it relatively easy to change the flow of the Web application as it evolves.

Struts provides a uniform way of handling HTTP form submission and validation by using an ActionForm. You can extend the abstract ActionForm class to perform validation of form input. Struts also supports declarative validation, in which the validating class instance is constructed by Struts, based on declarations in the struts-config.xml file and validation rules defined in the validation.xml file.

The View component of the framework is supported by a set of tag libraries:

Tag Library Descriptor (TLD) URIPrefix Description
http://jakarta.apache.org/struts/tags-bean beanJava bean access and creation
http://jakarta.apache.org/struts/tags-html htmlHTML Form creation
http://jakarta.apache.org/struts/tags-logic logicFlow control
http://jakarta.apache.org/struts/tags-nested nestedNested tags in the body of other Struts tags
http://jakarta.apache.org/struts/tags-template templateDynamic JSP templates
ttp://jakarta.apache.org/struts/tags-tiles tilesDefine the layout of a JSP

Of these tag libraries, the html, bean and logic libraries are most frequently used, and the nested and template libraries are seldom needed. The tiles library is useful for configuring a consistent and flexible appearance to pages throughout an application. There is some overlap in functionality between the Struts bean and logic libraries and the JSTL libraries. In cases where either technology could be used, you might prefer to use the JSTL since it is likely to become part of the JSP 2.0 standard.

In the webAF new project wizard, selecting Struts Framework Web Application as the template will include the necessary Struts "boilerplate" files and tag libraries:

WebApp Project wizard

The webAF palette will provide Drag and Drop support for the tag libraries listed above when you choose the Struts template option.

Configuration Files

These are the files that are added or modified by webAF when you select the Struts template:

FileIn Project? Description
ProjectPath\webapp\WEB-INF\struts-config.xml YesMain Struts configuration file
ProjectPath\webapp\WEB-INF\web.xml YesDeployment descriptor with standard Struts Action servlet and mappings
ProjectPath\webapp\WEB-INF\validation.xml NoDeclarative form validation
ProjectPath\webapp\WEB-INF\validator-rules.xml NoForm validation rules
ProjectPath\webapp\WEB-INF\tiles-defs.xml NoTiles definitions
ProjectPath\webapp\WEB-INF\classes\resources\application.properties YesMessage resource bundle

To avoid an unnecessary initial clutter of editor frames, webAF does not include all these files in the project even though they exist. Those with a No in the In Project? column above are less frequently needed and are not initially displayed in the webAF files list. If you need to edit one of these files, just select Insert [arrow] File Into Project and navigate to the desired file.

Changes to the web.xml File

When you choose a Struts Web application template, the familiar deployment descriptor will contain the standard Struts action servlet declaration and action mappings, for example:

    <!-- Standard Action Servlet Configuration (with debugging) -->
    <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>
    ...
        <!-- Standard Action Servlet Mapping -->
        <servlet-mapping>
            <servlet-name>action</servlet-name>
            <url-pattern>*.do</url-pattern>
        </servlet-mapping>

The important thing to note here is that every request for a URL ending with a .do extension (the standard Struts extension) will be processed by the Struts ActionServlet. Though this class can be extended, for many applications this is not necessary and it is used "as-is". The ActionServlet will use information in the struts-config.xml file to decide which Action class will be called upon to actually execute the request for the specified resource.

Basic Form Validation

To illustrate basic Struts processing, suppose you wanted to create a Struts-based Web application with an initial JavaServer Page that has a form to search for studies (documents) on a certain topic, with a pull-down list of possible sources for the studies. When the form is submitted, if any documents from the specified source match the topic, then a page will list the studies found. The steps to accomplish this (given in more detail later) are:

  1. Create the new findstudy.jsp page, using Struts HTML tags to define the form.
  2. Create the FindStudyForm.java class that extends ActionForm, to hold the request parameter values and validate them.
  3. Create the FindStudyAction.java class that extends Action, to check the submitted topic and source against the database.
  4. Modify the default application.properties file to add error messages.
  5. Add a forward in the initial index.jsp page to reach the findstudy.jsp page.
  6. Add a found.jsp file that will be displayed after a successful search, using Struts logic and iterate tags to display the results.
  7. Modify the struts-config.xml file to define the global forward, declare FindStudyForm as a form bean, and to add the action mappings for:
    • accessing the findstudy.jsp page initially to display the form.
    • delegating validation of the submitted form to FindStudyForm.java.
    • re-displaying findstudy.jsp with error messages if validation fails.
    • performing the business logic search for the topic if validation succeeds.
    • accessing the found.jsp page if the search was successful.

Note: For simplicity, the "business logic" is simulated internally in FindStudyAction.java for this example. In an actual application, it would be external.

Creating the findstudy.jsp File

The Struts HTML tags are preferred over ordinary HTML form tags, because they are tightly integrated with the Struts framework. This is the code for findstudy.jsp:

    <%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html" %>

    <html><head><title>Our Web Application - Locate Study</title></head>
    <body>
    <h1>Our Web Application</h1>
    <p><font color="red"><html:errors /></font>
    <h3>Locate a Study</h3>
    <table>
     <html:form action="findstudy" focus="topic">
      <tr><td>Topic:</td><td><html:text property="topic"/></td></tr>
      <tr><td>Source:</td>
        <td><html:select property="source" >
           <html:options property="sources"/>
           </html:select></td></tr>
      <tr><td><html:submit value="Go" /></tr>
     </html:form>
    </table>
    </body>
    </html>

The html:errors tag will display errors after validation (described later). When initially displaying the form, it will do nothing.

The action attribute on the form specifies a logical name for the action that should take place when the button is pushed to submit the form. The findstudy name will be mapped to our form validation Java class by an entry in struts-config.xml.

Creating the FindStudyForm.java File

When a form is submitted, Struts will instantiate a form bean extending the ActionForm class, which will encapsulate the form request parameters and perform validation. Struts will call each setter method that corresponds to the name of a request parameter, and will then call the validate() method. This method is expected to return an ActionErrors instance, which encapsulates a collection of error keys. Each error key will later be used to retrieve a corresponding error message from the application.properties file.

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

    public class FindStudyForm extends ActionForm
    {
        private String topic;
        private String source;

        // Simulated sources - replace with actual external bean for business logic:
        private static String[] sources =
        {
            "- Please choose a source -",
            "Duke Medical Center",
            "Johns Hopkins Hospital"
        };

        public String getTopic()
            {return topic; }
        public void setTopic(String topic)
            {this.topic = topic; }

        public String getSource()
            {return source; }
        public void setSource(String source)
            {this.source = source; }

        public String[] getSources()
            {return sources; }

        public ActionErrors validate(ActionMapping mapping, HttpServletRequest request)
        {
            ActionErrors errors = new ActionErrors();
            ActionError newError = null;

            if (getTopic() == null || getTopic().length() < 1)
                errors.add("topic", new ActionError("errors.required", "Topic"));

            if (getSource() == null || getSource().length() < 1 || getSource().startsWith("- "))
                errors.add("source", new ActionError("errors.required", "Source"));

            return errors;
        }
    }

Here, the errors.required key is used to retrieve the desired error message from the application.properties file, which is described later.

Creating the FindStudyAction.java File

After the form bean is validated to ensure that values for both fields were supplied, Struts will instantiate a class extending Action to perform the business logic. The execute() method should be overridden, and returns an ActionForward to indicate what Struts should invoke next. In the example, this class will simulate searching the selected source for documents on the given topic. If any are found, the method will save the collection of matches in a scoped attribute named results, and will look up and return the ActionMapping for the logical name success. If the selected source is not found, the method will return the ActionMapping corresponding to logical name failure. These logical names will be defined for the action in struts-config.xml later.

	    package app;
	    import org.apache.struts.action.*;
	    import javax.servlet.http.*;
	    import java.io.*;

	    public class FindStudyAction extends Action
	    {

	        public ActionForward execute(ActionMapping mapping,
	                    ActionForm form,
	                    HttpServletRequest req, HttpServletResponse res)
	                    throws Exception
	        {
	            FindStudyForm findStudyForm = (FindStudyForm) form;
	            ActionErrors errors = new ActionErrors();
	            ActionError newError = null;

	            String topic = findStudyForm.getTopic();
	            String source = findStudyForm.getSource();

	            // Simulated 'search' - replace with actual external bean with business logic:
	            if (topic.equals("Cancer") && source.equals("Duke Medical Center"))
	            {
	                String[] results = new String[]
	                {
	                    "'Non-traditional Treatement of Leukemia', 1977",
	                    "'Relation of Smoking and Ovarian Cancer', 1982"
	                };
	                req.setAttribute("results", results);

	                return mapping.findForward("success");
	            }

	            newError = new ActionError("errors.not.found");
	            errors.add(ActionErrors.GLOBAL_ERROR, newError);

	            saveErrors(req, errors);
	            return  mapping.findForward("failure");
	        }
    }

For this example, only the combination of topic="Cancer" and source="Duke Medical Center" will be recognized as a match, but in a real application you would replace this with an external database query. If no match is found for the topic and source, then a new ActionError is constructed using the key errors.not.found to extract the desired message text from the application.properties file. This error is added to the errors collection and saved for later display when findstudy.jsp is re-executed.

Modifying the application.properties File

The application.properties file that is generated by webAF will have lines defining default standard messages. You can add additional key=value lines as needed. For this example, one line needs to be added, so the resulting file looks like this:

# -- standard errors --
    errors.header=<UL>
    errors.prefix=<LI>
    errors.suffix=</LI>
    errors.footer=</UL>
    # -- validator --
    errors.required={0} is required.
    errors.byte={0} must be an byte.
    errors.date={0} is not a date.
    errors.double={0} must be an double.
    errors.float={0} must be an float.
    errors.integer={0} must be an integer.
    errors.long={0} must be an long.
    errors.short={0} must be an short.
    errors.creditcard={0} is not a valid credit card number.
    errors.email={0} is an invalid e-mail address.
    # -- other --
    errors.cancel=Operation cancelled.
    errors.detail={0}
    errors.general=The process did not complete. Details should follow.
    errors.token=Request could not be completed. Operation is not in sequence.

    # -- application-specific messages --
    errors.not.found=Sorry, no study was found for this topic and source.<br>
            <i>Hint: Try 'Cancer' and 'Duke Medical Center'</i>

Note: The last two lines shown above are actually a single line.

Here the two keys that are actually used in the application are errors.required (used by FindStudyForm.java) and errors.not.found (used by FindStudyAction.java). The {0} parameter will be replaced by the optional argument passed in to the ActionError constructor.

Defining the initial index.jsp File

For this example you would really like to have the initial entry point to the Web application, index.jsp, contain the form. However, this will not work because the welcome-file defined in web.xml cannot be set up to use a Struts action. This problem is solved by having index.jsp forward to the Struts action corresponding to the findstudy.jsp page:

   <%@ taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %>

   <html><body>
     <logic:forward name="start"/>
   </body></html>

Here start is a logical name that will be mapped to findstudy.jsp in the struts-config.xml file.

Adding the found.jsp File

After the form fields have been validated and one or more matches has been found for the topic and source, control will be transferred to a JSP serving as the view component for our action. In our example, this will be a found.jsp file that displays a list of documents matching our search criteria:

    <%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean" %>
    <%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html" %>
    <%@ taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %>

      <html><head><title>Our Web Application - Studies Found</title></head>
      <body>
       <h3>Results Found:</h3>
       <ol>
        <logic:iterate id="item" name="results">
         <li><bean:write name="item"/></li>
        </logic:iterate>
       </ol>
      </body></html>

Here the Struts logic:iterate tag will loop throught the collection stored in the scoped attribute results, successively assinging each item in the collection to the item scripting variable for display by the bean:write tag.

The struts-config.xml file

The struts-config.xml file is the "glue" that binds the components of a Struts-based application together. Its DTD (Document Type Definition) defines a variety of elements. For this example Web application, changes will be needed in these main areas:

Adding the Global Forward

The index.jsp file contains a forward to start. You need to map this logical resource name to a Struts action, by adding the line in bold below to the struts-config.xml file:

   <global-forwards>
    ...
    <forward name="start" path="viewfindstudy.do" />
   </global-forwards>

The viewfindstudy.do action will be defined later in the file.

Adding the Form-Bean Definition

You need to assign a logical name for the FindStudyForm class and define its type, so Struts will be able to instantiate it. This is done by adding the line in bold below to the struts-config.xml file:

   </form-beans>
    ...
    <form-bean name="findStudyForm" type="app.FindStudyForm" />
   </form-beans>

The findStudyForm name will be used as an attribute value for an action defined later in the file.

Adding the Action Mappings

The action element is perhaps the most important element in the struts-config.xml file, and has these attributes:

Attribute Description
attribute A Request- or Session-scoped attribute name to use to retrieve the form bean instance if different from the name attribute value. Optional with no default.
className The name of a subclass of org.apache.struts.action.ActionMapping that should be used to configure this action. Optional, defaulting to org.apache.struts.action.ActionMapping.
forward The application-relative path to a resource that should receive the forwarded request. Exactly one of the forward, include or type attributes must be specified. If forward is specified, the Action class will not be instantiated.
include The application-relative path to a resource that should serve this request via an include. Exactly one of the forward, include or type attributes must be specified. If sinclude is pecified, the Action class will not be instantiated.
input The application-relative path to the input form for input validation. Required if the name attribute is specified.
name The logical name of the form-bean associated with this action. Optional with no default. If specified, it must match a previous form-bean element name.
path The logical name of the action, specified with a leading slash ("/") character and without the extension (typically .do). Required.
parameter A parameter used to pass information to the this Action class instance, which can be retrieved using the getParameter() method of the ActionMapping passed as an argument to the execute() method. Optional.
prefix A prefix used to match request parameter names to form-bean property names. Optional.
roles A comma-delimited list of security role names authorized to perform this action. Optional.
scope The scope for the form-bean, either request or session. Optional, defaulting to session.
suffix A suffix used to match request parameter names to form-bean property names. Optional.
type A fully-qualified Java class name of a class that extends org.apache.struts.action.Action. Exactly one of the forward, include or type attributes must be specified.
unknown A flag set to true if this is the default mapping for the application, which will process requests for URIs not matching any mapping. Optional and may only be specified true on one mapping in the application.
validate A flag set to true if the validate() method for the form-bean should be called. Optional, defaulting to true.

For this example, two actions need to be added to the struts-config.xml file:

   <action-mappings>
    ...
    <action
        path="/viewfindstudy"
        parameter="/findstudy.htm"
        type="org.apache.struts.actions.ForwardAction"
        name="findStudyForm"
        input="/findstudy.htm"
        validate="false" />

    <action
        path="/findstudy"
        type="app.FindStudyAction"
        name="findStudyForm"
        input="/findstudy.htm"
        validate="true">
            <forward name="success" path="found.htm" redirect="false"/>
            <forward name="failure" path="/findstudy.htm" />
    </action>

   </action-mappings>

The first action defines the viewfindstudy action, which simply forwards the request to findstudy.jsp without validating. This mapping initially displays the form. The second action defines the findstudy action, which calls the validate() method of the form-bean named findStudyForm. If validation fails, control is returned to findstudy.jsp. If validation succeeds, then the FindStudyAction class will be instantiated and its execute() method called. The two nested forward elements specify the configuration of the ActionFoward objects that this method can search for and return. The success forward will forward the request to found.jsp. The failure forward will return control to findstudy.jsp, so the user can try a different search.

This completes the steps necessary for building the example Struts form validation application. This is how the application would appear after validation has failed because the Go button was pressed without entering any value for Topic or Source:

Browsing with validation failure

If validation succeeds and two matching results are found, the found.jsp page would look like this:

Browsing results

Declarative Form Validation

In the preceding section, a form-bean was implemented by explicitly coding a Java class extending org.apache.struts.action.ActionForm. As an alternative, Struts can automatically create a suitable class to validate form request parameters based on information that you provide in the validation.xml file. Here you specify which fields are required, and typically provide a regular expression defining valid field content. The DynaActionForm class provides the implementation. Using declarative validation can significantly reduce the amount of Java code you have to write for a Web application.

For a description of a complete example using this technique, including the full source code and step-by-step build instructions, see the About the Struts Declarative Validation Example.

Struts Tiles

As the name suggests, Struts Tiles are rectangular areas of a JSP, typically used to define the layout of a Web site, so that pages will have a consistent look and feel throughout the application. A tile can be constructed from other tiles, so complex layouts are possible.

As a simple example, suppose you want your application to use a classic layout with a header, menu, body and footer region:

 
Header
 
M
e
n
u
 
Body
Footer

Each content page of the application will be displayed in the body region (not to be confused with the HTML <body> tag - the entire layout will be rendered between the HTML <body> and </body> tags). The header and footer regions will always be the same. The menu region will show a menu bar, with vertically-arranged links to the "Home", "Products", "Services", "Mission" and "Contact Us" tile pages. Clicking link in the menu will display the corresponding content page in the body region. For simplicity, in the example, body region content pages will only be provided for the "Home" and "Products" links. Clicking the other links will bring up an "Under construction" JSP in the body region.

For this example, the layout conceptually illustrated above will be displayed by a layout.jsp page. This file will use an HTML table to define each of the four regions. Inside the <td> tag for each region in the table, there will be a Struts tiles tag to render the actual content. For instance, the body region table cell would contain:

     <tiles:insert attribute="body" />

This will render the page specified by the body scoped attribute. This attribute will have been previously set to the desired basic body-content JSP, either directly or by a default set in the tiles-config.xml file.

For example, when a user clicks on the "Products" link in the menu, a request for tile tiles/products.jsp will be generated. This file only needs to contain a few lines:

    <tiles:insert definition="layout" flush="true">
      <tiles:put name="body"   value="/content/productsPage.htm" />
    </tiles:insert>

Here the insert tag first specifies that layout (a logical name defined in the tiles-defs.xml file, that in turn maps to shared/layout.jsp) should be used for the default layout for this request. Then the nested tiles:put tag specifies that the body attribute should be set to content/productsPage.jsp, which is the file that will render the body region content for this request. Finally, the end tag will trigger rendering of the entire layout by shared/layout.jsp, which will use the scoped attributes to render the correct content for each region.

Thus, each resource associated with a menu item (home page, products, and so on) will actually have a pair of JSP files:

One advantage of this scheme is that you can change the layout without having to make any change at all to the basic content JSP files.

To help distinguish the types of JSP files in our example, the web application will be organized to place the JSP files in three subdirectories:

For our example, these are the tile JSPs and associated basic content JSPs:

TileCorresponding basic content Description
tiles/home.jsp content/homePage.jsp Body region "Home" page
tiles/products.jsp content/productsPage.jsp Body region "Products" page
tiles/unimplemented.jsp content/unimplementedPage.jsp Body region "Services" page
Body region "Mission" page
Body region "Contact Us" page

As mentioned previously, the last three menu items all display the same "stub" JSP for simplicity in the example.

The basic steps to building our Tiles example Web application (given in more detail later) are:

  1. Create the layout.jsp file to define the overall layout.
  2. Create the shared header and footer JSP files.
  3. Create the shared menu.jsp file.
  4. Create the JSP files for the basic content pages.
  5. Create a tile JSP file corresponding to each content page to be displayed in the body region.
  6. Modify the tiles-defs.xml file to define the default layout definition.
  7. Create a cascading style sheet Layout.css to specify common formatting for the Web application.

Creating the shared/layout.jsp File

An HTML table defines the four regions of the overall layout, where each region's content will be rendered according to the JSP file specified by the value of the given attribute name. The tiles:getAsString tag is used to render the correct title (which is displayed in the browser's window caption) for the request. The link tag in the HTML header references the cascading style sheet which will define the color scheme and font information for the layout of the Web application. The class attributes on the various table data (td) elements specify which style should be used for each region. The menu region will be 120 pixels wide, and the body region will use the rest of the available browser width.

    <%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html" %>
    <%@ taglib uri="http://jakarta.apache.org/struts/tags-tiles" prefix="tiles" %>

    <html>
    <head>
      <title><tiles:getAsString name="title"/></title>
      <link rel=stylesheet type="text/css"
              href="<html:rewrite page='/styles/Layout.css'/>" title="MyStyle"/>
    </head>

    <body>
    <table width="100%">
      <tr>
        <td class="header" colspan="2"><tiles:insert attribute="header" /></td>
      </tr>
      <tr>
        <td class="menu" width="120" valign="top"><tiles:insert attribute="menu" /></td>
        <td valign="top"><tiles:insert attribute="body" /></td>
      </tr>
      <tr>
        <td class="footer" colspan="2"><tiles:insert attribute="footer" /></td>
      </tr>
    </table>
    </body>
    </html>

Creating the shared/header.jsp File

For this example, the header style will be used to specify a font color and background color in the style sheet. The company name will be left-aligned and the slogan right-aligned.

    <table width=100%>
      <tr>
        <td class="header" ><h2>MyCompany</h2></td>
        <td class="header" align="right" valign="top"><i>The finest products since 2003</i></td>
      </tr>
    </table>

Creating the shared/footer.jsp File

Since the footer has no explicit color information, it will use the background and font color for the style inherited from the td element (in shared/layout.jsp) that contains it. The copyright notice will be explicitly centered and italicized. In practice, this might better be specified in the style sheet too.

    <div align="center">
      <i>Copyright &copy; 2003, MyCompany</i>
    </div>

Creating the shared/menu.jsp File

The following code defines the menu bar, with links to the Home, Products, Services, Mission and Contact Us tile pages (the last three being unimplemented). Since we are focusing exclusively on tiles in this example, the links go directly to the tile JSP files instead of using a logical name to be processed by the ActionServlet. The Struts html:rewrite tag takes care of correctly constructing the URL for the application-relative path to the desired page.

    <%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean" %>
    <%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html" %>
    <%@ taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %>
    <%@ taglib uri="http://jakarta.apache.org/struts/tags-tiles" prefix="tiles" %>

    <table >
      <tr><td class="menu" >
        <a class="menu" href="<html:rewrite page='/tiles/home.htm'/>">Home</a>
      </td></tr>

      <tr><td class="menu" >
        <a class="menu" href="<html:rewrite page='/tiles/products.htm'/>">Products</a>
      </td></tr>

      <tr><td class="menu" >
         <a class="menu" href="<html:rewrite page='/tiles/unimplemented.htm'/>">Services</a>
      </td></tr>

      <tr><td class="menu" >
        <a class="menu" href="<html:rewrite page='/tiles/unimplemented.htm'/>">Mission</a>
      </td></tr>

      <tr><td class="menu" >
        <a class="menu" href="<html:rewrite page='/tiles/unimplemented.htm'/>">Contact Us</a>
      </td></tr>
    </table>

Creating the Home Page Content (content/homePage.jsp)

Note that this page does not contain any <html>, <head> or <body> tags. These tags should only be present in the shared/layout.jsp page, which provides the content for the overall layout.

    <h3>Welcome to MyCompany</h3>

    At MyCompany, we do lots of good stuff.
    <p>To find out more, click on one of the menu topics at the left.

Creating the Products Page Content (content/productsPage.jsp)

This is the JSP file that renders the content listing product information in a table. It contains no tiles-specific content. A separate Java bean, app.Products.java provides access to the business logic, exposing a collection of products through its getProducts() method. A helper class, app.Product.java, in turn exposes properties for the part number, name, description and price of each product. For simplicity, the source code for these classes will not be shown. The Struts logic:iterate and bean:write tags handle the rendering of the table cell contents.

    <%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean" %>
    <%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html" %>
    <%@ taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %>
    <%@ taglib uri="http://jakarta.apache.org/struts/tags-tiles" prefix="tiles" %>

    <h3>Products</h3>

    <table border="2">
      <tr>
        <th>Part No.</th><th>Name</th><th>Description</th><th>Price</th>
      </tr>
      <jsp:useBean id="prods" class="app.Products" scope="request" />
      <logic:iterate id="theprod" name="prods" property="products">
        <tr>
          <td width="10%"><bean:write name="theprod" property="part" /></td>
          <td><bean:write name="theprod" property="name" /></td>
          <td><bean:write filter="false" name="theprod" property="description" /></td>
          <td align="right">$<bean:write name="theprod" property="price" /></td>
        </tr>
      </logic:iterate>
    </table>

    <p>We'll have many other great products Real Soon Now.

Creating the Services, Mission, and Contact Us Pages (content/unimplementedPage.jsp)

As discussed previously, this is the "stub" content for the three menu topics that are not actually implemented in this example.

    <h3>Under Construction</h3>
    Sorry, this page has not been implemented yet.
    Please choose another topic.

Creating the Tile for the Home Page (tiles/home.jsp)

This JSP file simply inserts the default layout named layout, which will be defined in the tiles-config.xml file.

    <%@ taglib uri="http://jakarta.apache.org/struts/tags-tiles" prefix="tiles" %>

    <tiles:insert definition="layout" flush="true">
    </tiles:insert>

Creating the tile for the Products page (tiles/products.jsp)

Here, the JSP inserts the same default layout as was used for the Home page, but then sets the title and body values to meet the needs of the Products page. As a result, the body region will be rendered by content/productsPage.jsp instead of the default JSP.

    <%@ taglib uri="http://jakarta.apache.org/struts/tags-tiles" prefix="tiles" %>

    <tiles:insert definition="layout" flush="true">
      <tiles:put name="title"  value="MyCompany Products Page" />
      <tiles:put name="body"   value="/content/productsPage.htm" />
    </tiles:insert>

Creating the Tile for the Services, Mission and Contact Us Pages (tiles/unimplemented.jsp)

Since requests for menu items Services. Mission and Contact Us are not implemented for the example, this tile will serve for all three. The tiles:put tags replace the default attribute values with those needed for the stub JSP content page and the corresponding title.

    <%@ taglib uri="http://jakarta.apache.org/struts/tags-tiles" prefix="tiles" %>

    <tiles:insert definition="layout" flush="true">
      <tiles:put name="title"  value="MyCompany Future Page" />
      <tiles:put name="body"   value="/content/unimplementedPage.htm" />
    </tiles:insert>

Modifying the tiles-defs.xml File to Define the Default Layout

Insert the existing ...ProjectName\webapp\WEB-INF\tiles-defs.xml into the project and open it in the webAF editor.

Insert the default definition in the tiles-definitions element body:

    <definition name="layout" path="/shared/layout.htm">
      <put name="title"  value="MyCompany" />
      <put name="header" value="/shared/header.htm" />
      <put name="menu"   value="/shared/menu.htm" />
      <put name="footer" value="/shared/footer.htm" />
      <put name="body"   value="/content/homePage.htm" />
    </definition>

This specifies that the logical tile name layout will be handled by the shared/layout.jsp file. It then specifies the default title and the four default JSPs for rendering the respective regions of the tile. These values are the Home page values.

Creating the Cascading Style Sheet (styles/Layout.css)

This sets the background color for the header and footer to blue, using a white font, and specifies a silver color for the menu region. The title displayed at the top of the body region for each content page will be blue.

    td.menu {font-size: 80%; }
    td.header {background-color: blue; color: white}
    td.footer {background-color: blue; color: white; font-size:80%}
    td.menu {background-color: silver}

    h3 {color: blue}

This completes the steps necessary to build the Struts Tiles example Web application. This is the Home page output in the browser:

Struts Tiles example Home page

This is what appears if you click Products in the menu tile at the left:

Struts Tiles example Products page

For more information, see the About the Struts Declarative Validation Example.