Struts-2: Decorating With SiteMesh    - step 4 - previous    print     download     next

Step 4: Decorating the Address-Book Using SiteMesh
R. Kevin ColeApril 5, 2007

This experiment begins with the address-book application from step 4 in this site's Struts CRUD Tutorial. In that step, database access was added to the address book web application creating a basic address storage system.

This part of the tutorial will update the look and feel of the application using a page decorating technology called SiteMesh. SiteMesh enables the developer to produce a consistent look and feel across all pages in an application. The typical user interface elements of header, navigation panel and footer are added. You may also want to take a look at the article Decorating the Web with SiteMesh elsewhere on this site.

In this article the following steps will be performed:

  1. Add SiteMesh support to the Struts-2 Framework
  2. Create a decorator template
  3. Add Some New Style Elements to the Address Skin.
  4. Update unit tests to make sure the new elements are produced.
  5. Deploy the Application and Run all Tests

Add SiteMesh Support

Documentation and downloadable distributions of SiteMesh can be found at www.opensymphony.com. This step was performed using sitemesh-2.2.1.jar.

Installing SiteMesh involves the following steps:

Add the SiteMesh Jar Files to the Library

Adding support for SiteMesh to a Struts-2 project requires the addition of the following libraries to the lib directory:

  • sitemesh-2.2.1.jar
  • jstl.jar
  • standard.jar
The last two jars, jstl and standard, are the Java Standard Template libraries. These are not strictly necessary for running SiteMesh but are handy when declaring page context variables.

Declare SiteMesh in web.xml

SiteMesh is a a Servlet Filter. The SiteMesh filter must be declared in the filter section of the application's web.xml file.

    <filter> 
<filter-name>sitemesh</filter-name>
<filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
</filter>
.
.
. and in the filter-mapping section ...
.
.
<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>

In the filter-mapping for sitemesh all files as being pushed thru the sitemesh filter. There are of course many file-types that must never be decorated. These are excluded in the decorators.xml file that will be described later in this article.

Configure SiteMesh

<sitemesh> 
<property name="decorators-file" value="/WEB-INF/decorators.xml"/>
<excludes file="${decorators-file}"/>

<page-parsers>
<parser content-type="text/html"
class="com.opensymphony.module.sitemesh.parser.FastPageParser"/>
</page-parsers>

<decorator-mappers>
<mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
<param name="config" value="${decorators-file}"/>
</mapper>
</decorator-mappers>
</sitemesh>

Most of the lines in sitemesh.xml need not concern us. For the puroses of this article, the important line is the declaration of decorators-file. The decorators file is declared as WEB-INF/decorators.xml. That file is created next.

<decorators defaultdir="/WEB-INF/decorators"> 
<excludes>
<pattern>/styles/*</pattern>
<pattern>/scripts/*</pattern>
<pattern>/images/*</pattern>
<pattern>/index.html</pattern>
</excludes>

<decorator name="layout" page="layout.jsp">
<pattern>/*</pattern>
</decorator>
</decorators>

As promised, the excludes section in the listing above lists the file patterns that must never be decorated.

Create a Decorator Template

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="decorator" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>


<c:set var="ctx" value="${pageContext.request.contextPath}"/>
<%@page contentType="text/html; charset=UTF-8" %>

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title><decorator:title default="Struts-2 CRUD Tutorial: Decorating with SiteMesh"/></title>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<link rel="stylesheet" type="text/css" href="http://www.rkcole.com/crud/skin.css"/>
<decorator:head/>
</head>

<body>
<table id="page-container" cellpadding="0" cellspacing="0">
<tr>
<td colspan="2" id="page-header">
<%@ include file="/includes/header.jsp"%>
</td>
</tr><tr>
<td id="nav-container">
<%@ include file="/includes/navigation.jsp" %>
</td>
<td id="content-container">
<decorator:body/>
</td>
</tr><tr>
<td colspan="2" id="page-footer">
<%@ include file="/includes/pagefooter.jsp" %>
</td>
</tr></table>
</body>
</html>

The decorator template above is a basic table-based layout of a web page with a header on top, a navigation panel to the left, a content area and a footer below. The tag &lgt;decorator:body> is replaced with the current target page being decorated. That is, the individual decorators header.jsp, navigation.jsp and pagefooter.jsp are wrapped around AddressForm.jsp with the page structure under control of the table element.

<!--   includes/header.jsp --> 

<h1>Address Book</h1>
<!--   includes/navigation.jsp --> 

<table cellpadding="0" cellspacing="0">
<tr>
<td>
<a href="<s:url value="AddressBook.action"/>"> Form View</a>
</td>
</tr>
</table>

Note the use of the strut-2  s:url tag.  This formats the URL properly for calling an action directly from a link. Clicking on this link will cause the AddressForm to redisplay.

<!--   includes/pagefooter.jsp --> 

<span class="tm">All Content &copy; Copyright 2007 R. Kevin Cole</span>

Add Some New Style Elements to the AddressBook Skin

The following stylesheet changes to crud&nbs;/ skin.css are optional. They add a bit of finish to the table that structures the address-book application.

#page-container { 
width: 785px;
border: 2px solid black;
background-color: #003399;
}
#content-container {
height: 100%;
text-align: left;
}
#page-header {
width: 100%;
border-bottom: 1px solid gray;
border-top: 1px solid gray;
border-color: #3366ff #000033 #000033 #3366ff;
text-align: center;
vertical-align: middle;
background-color: black;
}
#nav-container {
height: 300px;
width: 20%;
border-right: 1px solid black;
border-color: #666666 #cccccc #cccccc #666666;
padding-top: 20px;
padding-left: 10px;
vertical-align: top;
}
#nav-container a {
color: white;
text-decoration: none;
}
#nav-container a:visited {
color: white;
}
#nav-container a:hover {
color: yellow;
}
#page-footer {
width: 100%;
padding: 5px;
font-size: x-small;
vertical-align: middle;
border-top: 1px solid black;
border-color: #666666 #cccccc #cccccc #666666;
text-align: center;
}

Update Unit Tests

There is no out-of-container test that can be performed on the actions, dao or model elements that would test that the decorator rules have been applied to the address-book. That's how it should be! There is no coupling between the application's controller and model elements to the decoration of the view.

In-Container Test - AddressBookWebTest

Modifications to the in-container test are not as extensive. Add the testDecoration element to AddressBookWebTest. The testDecoration method simply looks for the presence of the HTML elements added by decorator template.

    /** Test that the web page is decorated by looking for 
* decorator elements.
*/
public void testDecoration() throws Exception
{
beginAt("/");
assertTablePresent("page-container");
assertElementPresent("page-header");
assertElementPresent("nav-container");
assertElementPresent("content-container");
assertElementPresent("page-footer");
}

Deploy the Application and Run All Tests

step4>ant test-all 
Buildfile: build.xml

init:

compile:
[javac] Compiling 1 source file to X:\demo\Struts2Crud\step4\build\test\classes

compile-tests:
[javac] Compiling 1 source file to X:\demo\Struts2Crud\step4\build\test\classes

test-web:

init:

compile:
[javac] Compiling 1 source file to X:\demo\Struts2Crud\step4\build\test\classes

compile-tests:
[javac] Compiling 1 source file to X:\demo\Struts2Crud\step4\build\test\classes

test:
[junit] Testsuite: crud.AddressBookWebTest
[junit] Tests run: 6, Failures: 0, Errors: 0, Time elapsed: 6.688 sec
[junit]

BUILD SUCCESSFUL
Total time: 11 seconds

This completes step 4 in the Struts Tutorial. In this step, the address-book web application was decorated with a header, navigation panel, a footer and a content area using SiteMesh.

ScreenShot: The Decorated Address-Book

Decorated Address-Book