To run this sample project Eclipse, download and install the WAR file:
StrutsNTiles.war.
In NetBeans, download the
StrutsNTiles.zip archive.
These JAR files are needed for NetBeans:
Tiles is a tool for specifying a general layout in which
there are parts, each a JSP file such that the parts
are rendered automatically without explicitly doing so
on each web page. The home page for tiles is
For our simple situation, what we have in mind is an automatic
rendering of the navigational links in a page in the
form of the JSP script nav.jsp,
without explicitly having to include it.
The initial preparation for tiles usage is in the
basic web.xml file:
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app ... >
<context-param>
<param-name>
org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG
</param-name>
<param-value>/WEB-INF/tiles.xml</param-value>
</context-param>
<listener>
<listener-class>org.apache.struts2.tiles.StrutsTilesListener</listener-class>
</listener>
...
</web-app>
In particular, this specifies the tiles definitions
to be found in /WEB-INF/tiles.xml:
tiles.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE ... >
<tiles-definitions>
<definition name="baseLayout" template="/layout.jsp">
<put-attribute name="nav" value="/nav.jsp"/>
</definition>
<definition name="welcome" extends="baseLayout">
<put-attribute name="title" value="Welcome"/>
<put-attribute name="content" value="/welcome.jsp"/>
</definition>
<definition name="first" extends="baseLayout">
<put-attribute name="title" value="First Page"/>
<put-attribute name="content" value="/first.jsp"/>
</definition>
<definition name="another" extends="baseLayout">
<put-attribute name="title" value="Second Page"/>
<put-attribute name="nav" value="/nav2.jsp"/>
<put-attribute name="content" value="/another.jsp"/>
</definition>
</tiles-definitions>
The most important feature is the layout, specified
by the file:
layout.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><tiles:insertAttribute name="title" /></title>
<link rel="stylesheet" href="css/common.css" type="text/css" />
</head>
<body>
<div id="nav">
<tiles:insertAttribute name="nav" />
</div>
<h1><tiles:insertAttribute name="title" /></h1>
<div id="content">
<tiles:insertAttribute name="content" />
</div>
</body>
</html>
The layout is specified by three attributes:
title, nav, content and
the layout is defined by the values of each using the
statement
<tiles:insertAttribute name="..." />
In tiles.xml,
the baseLayout definition indicates that,
unless overridden,
the nav attribute will be represented by the file
nav.jsp. The other three definitions are
used as result outcomes of action tags defined within
struts.xml:
struts.xml
<!DOCTYPE struts PUBLIC ... >
<struts>
<constant name="struts.action.extension" value="htm" />
<package name="default" extends="struts-default">
<result-types>
<result-type name="tiles"
class="org.apache.struts2.views.tiles.TilesResult" />
</result-types>
<action name="welcome" class="action.Welcome">
<result type="tiles">welcome</result>
</action>
<action name="first" method="first" class="action.Sample">
<result name="first" type="tiles">first</result>
</action>
<action name="another" method="another" class="action.Another">
<result name="another" type="tiles">another</result>
</action>
</package>
</struts>
In particular, when using Tiles, one must defer to
a new result type:
Using this as the type of a result, the view corresponding
to the response output is to be found as a "tiles" view
within the tiles.xml definitions file.
Setting the action extension
One of the things we've done in this example is to use
".htm" as the action extension, rather than the default
".action". This is easily changed by the line:
We want the initial behavior of the application to
be the effect of the Struts2 action call,
welcome.htm.
Presumably this can only be done by redirection from
some actual file, and so we do it as follows:
index.jsp
<meta http-equiv="Refresh" CONTENT="0; url=welcome.htm"/>
This call maps, through as the welcome action
through struts.xml and the Welcome action bean;
action/Welcome.java
package action;
public class Welcome {
public String execute() { return "success"; }
}
The result is the tiles welcome result using the
minimalistic content:
The s:property tag is similar to the JSTL c:out tag except that the value is presumed
to be a property access. If we wanted to use a literal string, say "testing", we
would use this:
<s:property value="%{'testing'}" />
The language used by Struts is called OGNL. It is similar, but not completely compatible
with EL. Note the usage of the "%" to create an immediate distinction between
with the EL format "${..}"
first.jsp
<%@taglib uri="/struts-tags" prefix="s"%>
<s:form action="first" cssClass="firstForm">
<s:textfield name="tf" label="textfield, tf" />
<s:textarea name="ta" rows="5" label="textarea, ta" />
<s:password name="pwd" label="password, pwd" size="40" />
<s:submit name="button" />
</s:form>
<s:if test="%{button != null}">
<div>
tf: <s:property value="tf" /> <br />
ta: <s:property value="ta" /> <br />
info: <s:property value="info" />
</div>
</s:if>
The associated action class is action.Sample. The entire form is reentrant and what
is being illustrated is this:
The most common usage is the way the textarea is handled with both get/set properties
done in a transparent way. Doing so creates a stable element.
Creating an unstable form element is more unusual. In particular, we undoubtedly want
to capture the data entered, and this is done by the setter method. The getter method
then, however, must return null to ensure that the field is cleared. In this example
we "prove" that the information from the field is actually sent to the action class
by way of the getInfo method, which returns the value capture by the setter.
action.Sample
package action;
public class Sample {
public String first() { return "first"; }
private String button;
public String getButton() { return button; }
public void setButton(String button) { this.button = button; }
private String ta;
public String getTa() { return ta; }
public void setTa(String ta) { this.ta = ta; }
private String tf;
public String getTf() { return null; }
public void setTf(String tf) { this.tf = tf; }
public String getInfo() { return tf; }
}
Another Bean & another.jsp
Observe the change of navigational menu when we activate this second example. This
is effected by the tiles definition (in tiles.xml) by changing the navigational
script to nav2.jsp:
The s:set tag is similar to the JSTL c:set tag with the difference in how a value is
expressed. As we indicated above this would have to be used:
<s:set var="x" value="%{'testing'}" />
to set the "variable" x to the literal value "testing". When x is accessed in a value
context, it must be distinguished from being a bean property by prefacing as "#x".
These elements are all generated by lists.
In most cases we uses the value of getChoices, a map,
to generate the list. Different from before, the iteration is implicitly done
by the list attribute, and stability is the norm.
Like we do
explicitly in other examples, the map's key becomes the underlying value and the map's
value becomes the visible content.
Note that the list choices can also be created literally as is done in
the s:radio group: