1. 高级 tile 主题

理解和使用 tile 范围

记住 Tiles 框架定义了一个称为“tile 范围”的附加范围,它与页面范围类似。像页面范围一样,tile 范围比请求范围更私有。Tile 范围允许 tile 用户给 tile 传递变量(称为参数)。本质上,它使得页面像函数一样可调用。

记住,jsp:include 允许您调用一个页面,同时传递给它一个请求参数(jsp:param)。tiles:insert 标签类似 jsp:include,不过前者更强大。 tiles:insert 标签允许您调用一个页面,同时向它传递子页面(称为 tile)和属性。Tile 范围本质上允许您传递仅对该 tile 布局可用的变量。

如果知道 tile 范围是如何实现的,您就能够理解它。我曾创建过一个名为 listTileScope 的调试实用程序,它允许我打印出 tile 范围中的变量,如下面的代码片段所示:

View Code
 import org.apache.struts.taglib.tiles.ComponentConstants;
import org.apache.struts.tiles.ComponentContext;

public static void listTileScope(PageContext context)
throws JspException, IOException {

JspWriter out
= context.getOut();
ComponentContext compContext
=
(ComponentContext)context.getAttribute(
ComponentConstants.COMPONENT_CONTEXT,
PageContext.REQUEST_SCOPE);

out.println(
"--- TILE Attributes --- <br />");

if (compContext!=null){

Iterator iter
= compContext.getAttributeNames();
while(iter.hasNext()){
String name
= (String)iter.next();
Object value
= compContext.getAttribute(name);
printNameValueType(name, value, out);
}
}
else{
out.println(
"---TILE Attributes NOT FOUND---<br />");
}

out.println(
"--------------------------- <br />");

}

private static void printNameValueType(
String name,
Object value,
JspWriter out)
throws IOException{

if (value !=null){

out.println(
name
+ " = " + value +
" type (" +
value.getClass().getName()
+ ") " +
"<br /><br />");

}
else{
out.println(name
+ " = " + value +
"<br /><br />");

}
}

注意 ComponentContext 类实现了 tile 范围ComponentContext 类位于 ComponentConstants.COMPONENT_CONTEXT 键下面的请求范围中。这种 tile 机制确保每个 tile 获得它自己的组件环境。

嵌套的 tile 不会和它们的父亲共享相同的 tile(我费了好大的劲才了解到这点)。当前 tile 的 tile 范围已在显示嵌套的 tile 之前得到保存。在嵌套的 tile 结束之后,父亲的 tile 范围将恢复到请求中。这个神奇的特性是在 InsertTag (org.apache.struts.taglib.tiles.InsertTag) 类的嵌套类 InsertHandler 中实现的。


使用 bean 属性作为参数

到目前为止,您已经向对应于子 tile 的 tile 布局传递过属性或传递简单的字符串。可以将您希望的任意 bean 类型作为属性传入 tile 布局。然后在那个 tile 布局内使用该属性。

假设您的应用程序具有这样一个操作,它将一个 User对象放入会话范围,或许是在用户登录系统之后:

View Code
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)

throws IOException, ServletException {

// Default target to success
String target = new String("success");

// If login successful.
UserDomainObject user = new UserDomainObject();
...
request.getSession().setAttribute(
"user", user);
return (mapping.findForward(target));
}

接下来您将该用户传递到您正在插入的 tile。这个例子将使用您在 tile 布局(siteLayout2.jsp)内所使用的那个 tile:

View Code
<tiles:insert attribute="header" ignore="true">
<tiles:put name="title" beanName="title" beanScope="tile"/>
<tiles:put name="user" beanName="user"
beanScope
="session"/>
</tiles:insert>

该 tile 布局通过指定 session 的范围和 user 的 bean 名称,从而将 userbean 传递给页眉 tile。使用这项技术,您可以在任何 JSP 范围中将任意 bean 传递给 tile 或 tile 布局,这样该 tile 范围就变成了另一个范围。这与以前并没有什么不同。

为了在 header.jsp 中使用这个 userbean,可把它从 tile 范围复制到一个其他 bean 能够理解的范围。这可以使用 tiles:useAttribute 标签来实现。 tiles:useAttribute 标签类似于 jsp:useBean 操作,只不过仅适用于 tile 范围(header2.jsp):

View Code
<tiles:useAttribute id="user" name="user"   classname="rickhightower.UserDomainObject"  />

因此 tiles:useAttribute将把 user 对象从 tile 范围复制到页面范围。一旦 bean 得到定义,您就能够像使用页面范围中定义的任何 bean 一样使用它:

View Code
<bean:write name="user" property="userName"/>

接下来,让我们看一下新的 header2.jsp文件的完整清单:

View Code
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<center>
<table>
<tr>

<tiles:useAttribute id="user"
name
="user"
classname
="rickhightower.UserDomainObject"
/>

<td width="33%" bgcolor="#36566E">

<div align='left'>
<font size="1" color="orange">

currently logged in as
<bean:write name="user" property="userName"/>
</font>

</div>

</td>


<td width="33%">

<font color="#36566E">
<tiles:getAsString name="title" ignore="true"/>
</font>

</td>
<td width="33%" bgcolor="#36566E">

<div align='left'>

<font size="1" color="white">

<blockquote>

<bean:write name="user" property="firstName"/>

<br />

<bean:write name="user" property="lastName"/>

<br />

</blockquote>

</font>

</div>



</td>

</tr>

</table>

</center>

可以看到,页眉现在显示了关于当前登录站点的用户信息 ―― 这是一个强大的特性。可以创建专门用于显示域对象的 tile,然后在应用程序的许多部分重用那些 tile。考虑到这点,弄清为什么人们原先考虑将 Tiles 框架称为“组件”就很容易了:您事实上能够创建显示组件。与自定义标签(JSP 2.0 之前的版本)不同,这些组件全都是在 JSP 页面中创建的。

2. 列表

理解列表

经常会遇到必须传递多个参数的情况。例如,您可能想要传递一个参数列表,以显示 tile 布局的导航区域中的链接。

回顾前面的“雇员清单”例子,您可能有一个 Web 应用程序需要显示公司的分公司、部门和雇员。当在雇员名单视图中时,employeeListing.jsp 将处于 tile 布局的内容区域,而当前分公司的部门链接将处于导航区域中。当用户单击某个部门链接时,该部门的雇员的新名单将会显示出来。当在部门视图中时, deptListing.jsp 将处于 tile 布局的内容区域,而当前公司的分公司链接列表将处于导航区域中。当用户单击某个分公司链接时,新的部门名单就会显示出来。因此,每个页面(employeeListing.jspdeptListing.jsp)都将传入一个新的链接列表。您可以使用 putList 来完成这个任务。


在 XML 中使用 putList

Tile 允许用户使用 putList 子元素传入链接 ―― 适合于在 XML 和 JSP 定义中使用,或在对定义的调用或 JSP 中的 tile 布局中使用。

假设您想使用一组标准导航链接作为站点布局。可以在 tile 配置文件中使用 putList 子元素来指定这样的链接,如下所示(tiles-def.xml):

View Code
<definition name="siteLayoutDef3" path="/siteLayout3.jsp">
<put name="title" value="Rick Hightower Stock Quote System" />
<put name="header" value="/header2.jsp" />
<put name="footer" value="/footer.jsp" />
<put name="content" type="string">
Content goes here
</put>

<putList name="items" >
<item value="Home"
link
="/index.html" />
<item value="Wiley"

link
="http://www.wiley.com" />
<item value="Trivera Technologies"
link
="http://www.triveratech.com/" />
<item value="Virtuas"
link
="http://www.virtuas.com/" />
<item value="Rick Hightower"
link
="http://www.rickhightower.com" />
<item value="Rick's Blog"
link
="http://rickhightower.blogspot.com/" />
</putList>
</definition>

putList 元素允许您指定与链接相关联的项的一个列表。在上面的清单中,putList 定义了六个链接。

items 列表(java.util.List)被放入 tile 范围。名称 items 使用 putList 元素的 name 属性来设置。

item 元素通过把 org.apache.struts.tiles.beans.MenuItem 的一个实例插入该列表来定义一个链接。value 属性对应于链接上的标签(label),而 link 则指向链接的 URL。

图标与工具提示

item 元素还有为链接指定工具提示和图标的元素。通过查看 Struts 源代码中的 DTD (tiles-config_1_1.dtd),可以了解有关 item 元素和 putList 的更多内容。


使用 tile 布局中的列表

要使用这种链接列表,必须修改 tile 布局,如下所示(siteLayout3.jsp):

View Code
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<tiles:importAttribute />

<html>
<head>
<logic:present name="title">
<title>
<tiles:getAsString name="title" ignore="true"/>
</title>
</logic:present>
</head>

<body>
<table width="500" border="0" cellspacing="0" cellpadding="0">

<tr bgcolor="#36566E">
<td height="68" width="70%">
<div align="left">
<img src="images/hp_logo_rickhightower.gif" width="220" height="74">
</div>
</td>
</tr>

<tr>
<td height="68" width="2000">
<tiles:insert attribute="header" ignore="true">
<tiles:put name="title"
beanName
="title" beanScope="tile"/>
<tiles:put name="user"
beanName
="user" beanScope="session"/>
</tiles:insert>
</td>

</tr>

<table>
<tr>
<td width="50%">
<ul>
<logic:iterate id="item" name="items"
type
="org.apache.struts.tiles.beans.MenuItem" >
<li>

<bean:define id="link" name="item" property="link"
type
="java.lang.String"/>

<logic:match name="link"
location
="start" value="/" >
<html:link page="<%=link%>" >
<bean:write name="item"
property
="value"/>
</html:link>
</logic:match>
<logic:notMatch name="link"
location
="start" value="/" >
<html:link href="<%=link%>">
<bean:write name="item"
property
="value"/>
</html:link>
</logic:notMatch>

</li>
</logic:iterate>
</ul>
</td>
<td width="50%">
<div align="center">
<tiles:insert attribute="content"/>
</div>
</td>
</tr>
</table>

<tr>
<td>
<tiles:insert attribute="footer" ignore="true"/>
</td>
</tr>

</table>

</body>
</html>

特别要注意在列表上进行迭代的代码段:

View Code
<ul>
<logic:iterate id="item" name="items"
type
="org.apache.struts.tiles.beans.MenuItem" >
<li>
<bean:define id="link" name="item" property="link" type="java.lang.String"/>
<logic:match name="link" location="start" value="/" >
<html:link page="<%=link%>" >
<bean:write name="item" property="value"/>
</html:link>
</logic:match>
<logic:notMatch name="link" location="start" value="/" >
<html:link href="<%=link%>">
<bean:write name="item" property="value"/>
</html:link>
</logic:notMatch>
</li>
</logic:iterate>
</ul>

后面会对此进行简化。


使用 tiles:importAttribute

tiles:importAttribute 标签将 tile 范围中的属性导入到页面范围。它类似于 tiles:useAttrribute 标签,但它更接近猎枪而不是解剖刀。它是懒散的、肮脏的和便宜的;我一直用它(这说明了我什么呢?)。这有效地将条目列表从 tile 范围拷贝到页面范围。

注意: tiles:importAttribute 可拷贝到任何指定的范围。

默认情况下,tiles:importAttribute 将所有这些属性拷贝到页面范围。你也可以通过使用范围属性将这些属性拷贝到其他范围。

一旦条目列表在页面范围中,您就可以使用标准 Struts 标签访问它,如下所示(siteLayout3.jsp):

View Code
<logic:iterate id="item" name="items" 
type
="org.apache.struts.tiles.beans.MenuItem" >
...
</logic:iterate>

注意使用 logic 标签实现的逻辑用于显示链接可以检查链接是否以“/”开始,从而确定链接是否是相对的。如果链接 相对的,使用 html:link 标签的 page 属性。否则,如果链接指向绝对 URL 的话,使用 html:link 标签的 href 属性,如下所示(siteLayout3.jsp):

View Code
<bean:define id="link" name="item" property="link"    type="java.lang.String"/>
<logic:match name="link" location="start" value="/" >
<html:link page="<%=link%>" >
<bean:write name="item" property="value"/>
</html:link>
</logic:match>
<logic:notMatch name="link" location="start" value="/" >
<html:link href="<%=link%>">
<bean:write name="item" property="value"/>
</html:link>
</logic:notMatch>

如您所想到的那样,您可能想要使用这一显示逻辑来在不止一个位置显示菜单项。这就是说,您可能想要在这个页面的范围之外重用它。在稍后部分,您将看到如何通过将一个 tile 布局嵌套进另一个 tile 布局来实现这一点。


在 JSP 中使用 putList

除了能向 tile 定义中的列表添加条目之外,还可以使用 tiles:putList 元素和它的 tiles:add 子元素向 JSP 中的列表添加条目(index6.jsp):

View Code
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>

<%@ page import="org.apache.struts.tiles.beans.SimpleMenuItem" %>
<tiles:insert definition="siteLayoutDef4">
<tiles:put name="title" type="string"
value
="Get Rick Hightower Stock Quote6" />
<tiles:put name="content" value="indexContent5.jsp"/>

<tiles:putList name="items" >
<jsp:useBean id="item1" class="SimpleMenuItem"/>
<jsp:setProperty name="item1" property="link"
value
="/index.html"/>
<jsp:setProperty name="item1" property="value"
value
="Home" />
<tiles:add beanName="item1"/>
</tiles:putList>
</tiles:insert>

上面的清单使用 jsp:useBean 来创建 SimpleMenuItem 的实例。然后使用 jsp:setProperty 来设置 SimpleMenuItem bean 的链接和值属性。最后,使用 tiles:add 将这个 bean 添加到列表中。

在上面的例子中,添加了一个 SimpleMenuItem,它细分了 tile 布局使用的 MenuItem。然而,您可以添加任何 bean 类型。

注意: 在 XML 中添加任何类型的 bean。

要在 tiles XML 定义中添加任何类型的 bean,可使用 putList 的子元素 bean。这个 bean 元素带有一个 idclasstype。对于简单类型,您也可以使用 putListadd 子元素。请参阅 tiles configuration DTD (tiles-config_1_1.dtd) 以获取更多信息。

                                                                (前一篇) 掌握Tiles框架 (二)-- Tiles布局和定义    (后一篇)掌握Tiles 框架(四) --高级定义概念,结束,参考资料及作者

posted on 2011-07-21 20:16  老杨HJ  阅读(3724)  评论(0编辑  收藏  举报