1. 高级定义概念

扩展定义

几个 JSP 页面经常使用相同的默认参数。其他页面也使用相同的 tile 布局但使用不同的 tile 参数。无需再定义一个完全不同的定义,一个定义可以扩展另一个定义。extends 属性让一个定义扩展另一个定义。

下面是一个例子:

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>

<definition name="siteLayoutDef4" extends="siteLayoutDef3">
<put name="title" value="Rick Hightower Quote Sub System" />
<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/" />
</putList>
</definition>

<definition name="siteLayoutDef5" extends="siteLayoutDef4">
<putList name="items" >
</putList>
</definition>

<definition name="siteLayoutDef6" path="/siteLayout4.jsp"
extends
="siteLayoutDef4">
</definition>

注意 siteLayoutDef4 扩展了 siteLayoutDef3,覆盖了标题值,并定义了一个更短的导航列表。它从所覆盖的 siteLayoutDef4 继承了所有其他参数,即页眉、页脚和内容。此外,注意 siteLayoutDef5 也扩展了 siteLayout4,只是它清空了条目列表。一个定义继承了它的上层定义及更上一层定义(依此类推无限制)的所有属性。

除了覆盖属性之外,还可改变 tile 布局 JSP。看看 siteLayoutDef6,它扩展自 siteLayoutDef5,并指定了一个新的 tile 布局(siteLayout4.jsp)。


嵌套 tiles

一个 tile 布局可以插入到另一个 tile 布局中,依此类推。实际上,创建的 tile 布局如此之小,以至于它们本身并不是真正的模板。相反,它们是更类似于自定义标签的小型可视组件,而不是页面模板。

记住您实现的逻辑用于显示一条链接。可以检查链接是否以“/”开始,从而确定链接是否是相对的,然后再正确地显示它。如果想要在应用程序的多个地方使用同一例程,需要创建一个可视组件。


创建可视组件

可视组件只是另一种 tile 布局。tile 布局是一个可视组件还是一个模板,只取决于您的观点(旁观者清)。下面的 tile 布局定义了一个可视组件,用于显示一个链接(linkLayout.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:useAttribute id="item"
name
="item"
classname
="org.apache.struts.tiles.beans.MenuItem"
/>

<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>

这种方法与 JSP Custom 标签相比,允许您使用其他自定义标签。另外,与 Java 类(比如 Custom 标签)相比,它是一个以文档为中心的 JSP,这使得使用 HTML 标签和自定义标签更容易。

注意: JSP 2.0 标签文件。

您可能认识到 JSP 2.0 及其后续版本中 JSP 标签文件的 tile 布局的许多优点。如果您使用的 JSP 版本太老,不支持标签文件,那么您现在就可以使用这种技术。然而,如您很快就要看到的那样,按我的观点,Tiles 框架更好地实现了控制器与视图的分离。


使用可视组件

一旦定义了可视组件,就应该为它创建一个定义,如下所示:

View Code
 <definition name="linkLayoutDef" path="/linkLayout.jsp">
</definition>

现在您已经定义好这个定义,通过使用 tiles:insert 标签 ,您可以在任何页面使用这个可视组件。甚至可以在另一个 tile 中使用这个可视组件。下面的代码示例展示了在前面定义的 tile 布局中使用这个可视组件 (siteLayout4.jsp)。

View Code
 <td width="50%">
<ul>
<logic:iterate id="item" name="items" type="org.apache.struts.tiles.beans.MenuItem" >
<li>
<tiles:insert definition="linkLayoutDef">
<tiles:put name="item" beanName="item" beanScope="page"/>
</tiles:insert>
</li>
</logic:iterate>
</ul>
</td>

上面的代码在条目列表上进行迭代,然后调用 tiles:insert,将当前条目传递给可视组件 (linkLayoutDef)以用于显示。可视组件知道如何显示一个域对象(一个菜单项)。如果您觉得自己需要再三重复编写相同的 JSP 代码,就应该考虑使用 tile 布局编写一个可视组件了。


将 tile 作为参数传递给另一个 tile

上面的例子显式地调用定义好的可视组件。如果您使用的 tile 布局根据几个因素而变化该怎么办呢?(即这个用户是否登录,他是否处于某个特定的角色,您位于站点的哪个部分)。在这种情况下,将 tile 作为一个参数传递将是个好主意。

使用 put 元素可以完成这件事,如下所示(tiles-def.xml):

View Code
<definition name="link.layout.def" path="/linkLayout.jsp">
</definition>

<definition name="siteLayoutDef7" path="/siteLayout5.jsp" extends="siteLayoutDef4">
<put name="title" value="Rick Hightower Quote System 9" />
<putList name="items" >
</putList>
<put name="linkDisplay" value="link.layout.def"/>
</definition>

注意 siteLayoutDef7linkDisplay 属性的值等于 link.layout.def。现在在 tile 布局(siteLayout5.jsp)的内部,您可以指定 linkDisplay属性,而不是明确地调用一个特殊的 tile 布局定义:

View Code
<ul>
<logic:iterate id="item" name="items" type="org.apache.struts.tiles.beans.MenuItem">
<li>
<tiles:insert attribute="linkDisplay">
<tiles:put name="item" beanName="item" beanScope="page"/>
</tiles:insert>
</li>
</logic:iterate>
</ul>

这样的话,您的站点布局不知道它所使用的是哪种可视组件。通过切换站点布局使用哪一种可视组件,您可以通过编程切换布局部分的显示方式。


控制器

如果您觉得需要向 tile 布局中放入太多的 Java 代码,或者必须在每个指向使用特定 tile 布局的页面的操作中放相同的 Java 代码,那么应该使用 tile 控制器。在使用 controllerClass属性插入 tile 之前,您可以指定一个进行调用的控制器类:

View Code
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<tiles:insert definition="siteLayoutDef5" controllerClass="rickhightower.SimpleController">
<tiles:put name="content" value="indexContent5.jsp" />
</tiles:insert>

控制器类类似于一个操作。在控制器中,可以将模型对象映射到某个范围中,以便 tile 能够显示条目。

要编写一个 tile 控制器,必须执行以下操作:

  1. 创建一个实现 org.apache.struts.tiles.Controller的类。
  2. 实现 perform()方法。
  3. perform() 方法中,执行一些模型操作,并将结果映射到范围中,这样 tile 就能使用它

下面的清单展示了实现一个控制器的方法(rickhightower.SimpleController):

View Code
package rickhightower;

import java.io.IOException;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.tiles.ComponentContext;
import org.apache.struts.tiles.Controller;


import org.apache.struts.tiles.beans.MenuItem;
import org.apache.struts.tiles.beans.SimpleMenuItem;

import java.util.ArrayList;
import java.util.List;

/**
* @author rhightower
*/
public class SimpleController implements Controller{


private MenuItem createMenuItem(String label, String link){
SimpleMenuItem item = new SimpleMenuItem();
item.setLink(link);
item.setValue(label);
return item;
}

private List getLinks(){
List list = new ArrayList();

list.add(createMenuItem("Home", "/index.html"));

list.add(createMenuItem("Rick's", "http://www.rickhightower.com"));

list.add(createMenuItem("Trivera", "http://www.triveratech.com"));

return list;

}
/* (non-Javadoc)
*
*/
public void perform(ComponentContext context,
HttpServletRequest request,
HttpServletResponse response,
ServletContext servletContext)
throws ServletException,package rickhightower; import java.io.IOException; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts.tiles.ComponentContext; import org.apache.struts.tiles.Controller; import org.apache.struts.tiles.beans.MenuItem; import org.apache.struts.tiles.beans.SimpleMenuItem; import java.util.ArrayList; import java.util.List; /** * @author rhightower */ public class SimpleController implements Controller{ private MenuItem createMenuItem(String label, String link){ SimpleMenuItem item = new SimpleMenuItem(); item.setLink(link); item.setValue(label); return item; } private List getLinks(){ List list = new ArrayList(); list.add(createMenuItem("Home", "/index.html")); list.add(createMenuItem("Rick's", "http://www.rickhightower.com")); list.add(createMenuItem("Trivera", "http://www.triveratech.com")); return list; } /* (non-Javadoc) * */ public void perform(ComponentContext context, HttpServletRequest request, HttpServletResponse response, ServletContext servletContext) throws ServletException, IOException { List items = (List)getLinks(); context.putAttribute("items",items); } IOException {
List items = (List)getLinks();
context.putAttribute("items",items);
}
}

注意 perform() 方法获得传递过来的组件上下文。组件上下文带有 tile 范围的属性。将东西放进组件上下文中可将它们放进 tile 范围中。在这个简单的例子中,调用 getLinks,它返回一个简单的映射到 tile 范围的 MenuItems 列表。一个真实的例子很可能会涉及到模型――也许是一个面(facade),它与数据库进行通信,查找特定于登录进系统的用户类型的链接。

注意:使用操作作为控制器。

您也可以使用操作作为 tile 的控制器。要完成这项任务,请指定带有 controllerUrl 属性的操作的路径。


将 tile 定义用作 ActionForward

您可能还未觉察到,在您安装 Tiles 插件时,它安装了一个自定义请求处理程序,扩展了 Struts 处理 ActionForward 的方式。因此,您应该转到 tile 定义而不是 JSP 页面。

假设您有一个定义类似这样:

View Code
<definition name="main.index" extends="siteLayoutDef7">
<put name="content" value="/indexContent.jsp"/>
</definition>

在您的 struts 配置文件中,您可以定义一个 forward 以转到 main.index定义,而不是指定一个 JSP 页面:

View Code
  <action path="/Lookup" type="rickhightower.SimpleLookupAction"
name
="lookupForm" input="/index.jsp">
<forward name="success" path="/quote.jsp"/>
<!-- forward name="failure" path="/index.jsp"/ -->
<forward name="failure" path="main.index" />
</action>

可以转到定义已证实是一项强大的工具,消除了 JSP 中无关的逻辑。例如,如果用户以经理身份而不是以常规用户身份登录,您可以将该用户转到一个定义,它定义了只有经理才能使用的特殊参数 tiles。

经理的定义可以在常规用户定义的基础上进行扩展。如果 tile 布局使用带有 ignore 属性的 insert 标签的话,它们甚至可以使用相同的 tile 布局。这个操作将选择正确的 forward。您根本无需使用 logic:* 标签。

将逻辑从 JSP 中取出并置入控制器中,是正确方向的一步,并且使用 Tiles 框架来执行这一步是如此地容易。

2. 结束语

结束语

如果您是 Tiles 框架的初学者,并且已经阅读了本教程,那么您已经迈出了重要一步。在相对短的时间中,我们介绍了:

  • Tiles 框架和架构。
  • 如何构建和使用 tile 布局作为站点模板。
  • 如何在 XML 和 JSP 中使用 tile 定义。
  • 如何在 tile 范围中移出和移入对象。
  • 如何使用属性列表。
  • 如何嵌套 tiles。
  • 如何构建和使用 tile 布局作为小型可视组件。
  • 如何细分定义。
  • 如何创建 tile 的控制器。
  • 如何使用 tile 作为一个 ActionForward

Tiles 框架使得创建可重用页面和可视组件更加容易。通过组装可重用 tiles,开发人员能够构建 Web 应用程序。可以使用 tiles 作为模板或者可视组件。

在某些方面,tile 布局更类似于一个显示函数。首先您传递需要使用的 tile 布局参数。参数可以是简单的字符串、bean 或者 tiles。参数是 tile 的属性,存储在 tile 的 tile 范围中。对于它的一部分,tile 范围类似于页面范围,比请求范围更少见。tile 范围允许 tile 的用户传递参数(也称为属性)给 tile。

定义允许您定义 tiles 的默认参数。定义能够在 JSP 或者 XML 中进行定义。定义能够扩展其他定义,这类似于类可以扩展另一个类。此外,定义可以覆盖它所扩展的定义的一部分。

Tiles 框架包括了它自己的 RequestProcessor,以便作为 ActionForward 处理 tile 布局。因此如果您安装了 Tiles 插件的话,可以转到 tile 定义而不是 JSP 。

如果您正在使用 Struts 而不是 Tiles,那么您不能从 Struts 获得完全受益,并且很可能进行不必要的自我重复。Tiles 框架使得创建可重用的站点布局和可视组件变得切实可行。

3. 参考资料

4. 关于作者

Rick Hightower喜欢使用 Java 技术、Ant、Struts、IBM Emerging Technologies Toolkit(ETTK)以及 XDoclet。 Rick 最近担任ArcMind Inc.的 CTO,这是一家主要从事企业开发方面的顾问、咨询和培训服务的公司。作为 IBM developerWorks 的积极投稿者,Rick 已编写了 10 多个教程,涵盖从 EJB (Enterprise JavaBeans) 技术到 Web 服务以至 XDoclet 的广泛内容。

在 eBlox 工作的同时,Rick 和 eBlox 团队使用 Struts 构建了用于在线电子商店的两个框架和一个 ASP(application service provider,应用服务提供程序)。 他们远在 1.0 版发布之前就在使用 Struts。 Rick 最近帮助 Trivera Technologies 整理了一套很受欢迎的课程,这些课程讲授运行在 Tomcat、Resin EE、WebSphere Studio Application Developer 以及其他平台上的 Structs。

Rick 与 James Goodwill 合著了Mastering Struts, 2nd edition 一书(Wrox Press 出版)。他还参与编写了 Java Tools for Extreme Programming 一书(John Wiley& Sons 出版,2001 年),这本书于 2002 年在 Amazon.com 网站上连续三个月被评为“畅销软件开发书籍”。它介绍了如何把 Ant、JUnit、Cactus 等应用于 J2EE(Java 2 Platform, Enterprise Edition)开发。 Rick 还为Mastering Tomcat Development 一书(John Wiley & Sons,2002 年)撰写了两章的内容,并参与编写过其他许多出版物。

Rick 在 2003 JavaOne 开发人员大会上作了关于 EJB CMP/CMR 和 XDoclet 的演讲,在 TheServerSide.com 软件座谈会上作了关于使用 XDoclet 进行 J2EE 开发的演讲。此外,Rick 还在 JDJEdge 和 WebServicesEdge 大会上作过演讲。而且,Rick 还在 Complete Programmer Network 座谈会(跨越美国 6 个不同城市)上作了关于高级 Struts 主题的演讲。

当不在全国各地讲授 Trivera Struts 课程、在大会上作关于 Struts 的演讲,或从事 Struts 咨询的时候,Rick 喜欢在通宵咖啡馆喝咖啡,编写关于 Struts 和其他主题的文章,以及以第三人称写关于他自己的事情。

注: 以上四篇文章来自http://www.ibm.com/developerworks/cn

原文地址: http://www.ibm.com/developerworks/cn/education/java/j-tiles/index.html

                                                                                     (前一篇) 掌握Tiles 框架 (三)—高级 tile 主题和列表

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