Tiles 框架增强了基于组件的 Web UI 开发的设计,它和 Struts 框架的组合工作得很好。您可以很容易的协同 WebShpere Studio 使用 Tiles 和 Struts 框架以显著降低您的 Web 开发工程的开发时间和维护代价。
© Copyright International Business Machines Corporation 2003. All rights reserved.
引言
Struts 是有名的模型-视图-控制器(Model-View-Controller,MVC)框架方面的开放源码体现之一,它提供了一种便利的方式,可以用于将模块化应用程序清楚地分解成逻辑、表示和数据。Java 服务器页面(Java™Server Pages,JSP)在 MVC 框架中的作用通常是作为视图(View),它根据业务逻辑和数据生成动态的用户界面(UI)。
在另一方面,Tiles 框架增强了基于组件的设计和 Web UI 设计中的模板概念。它可以帮助开发人员解除 Web UI 组件之间的耦合并重用它们。另外,Tiles 模板及其继承特征使您能够以最小量的工作为 Web 应用程序设计出一致的外观。
IBM® WebSphere® Studio Application Developer Version 5(以下简称为 Application Developer)有内置的对 Struts 1.02 和 1.1(Beta 测试版 2)的工具和运行时支持。Tiles 可以独立于 Struts 使用,也可以与 Struts framework 集成以支持高级特征。
重用 Web UI 组件的需要
本文假定您具有 Struts 和 Application Developer 中的 Struts 工具的基本知识。如果您对本主题的一些基本信息感兴趣,请参阅 用WebSphere Studio V5 编写一个简单的 Struts 应用。
为了更好地理解可以如何重用 Web UI 组件,让我们先来看一下图 1 和 2 中的两个 Web 页面(JSP):
图 1. IBM 解决方案页面
图 2. IBM 新闻页面
您可以看到,这两个页面在页头、左侧的导航条和页脚中有很多组件是共有的。您可以不共享任何组件而为每一个页面创建单独的 JSP 来负责它的布局并且使用重复的页头、左侧导航条和页脚。当然,这种解决方案的效率是非常低的,因为对相同的 UI 组件(比如左侧导航条)的更改要求您改动每个相关的页面。
在上面的示例中,有大量的 HTML 和 JSP 代码是重复的,而 UI 组件是紧耦合的。众所周知,在软件工程中紧耦合的组件将导致高额的维护成本。一个更好的解决方案是解除 UI 组件(页头、导航、页脚和主体)之间的耦合并在不同的页面中重用它们。
<jsp:include> 标签为重用 Web UI 组件提供了一种解决方案。通过使用 <jsp:include> 标签,Solutions 页面和 News 页面可以分解成由四个 JSP 页面,如图 3 和 4 所示:
图 3. Solutions.jsp
图 4. News.jsp
Solutions 页面的 JSP 代码显示在示例 1 中,News 页面的 JSP 代码显示在示例 2 中:
示例 1. Solutions.jsp 使用了 JSP 包含标签(SimpleJSPWeb)
<HTML>
<HEAD>
<TITLE>IBM Solutions</TITLE>
</HEAD>
<BODY>
<TABLE border="0">
<TBODY>
<TR>
<TD colspan="2"><jsp:include page="/Header.jsp" /></TD>
</TR>
<TR>
<TD width="20%" valign="top"><jsp:include page="/Navigation.jsp" /></TD>
<TD width="80%" valign="top">
<jsp:include
page="/Fragment-Solutions.jsp" /></TD>
<TR>
<TD colspan="2"><jsp:include page="/Footer.jsp" /></TD>
</TR>
</TBODY>
</TABLE>
</BODY>
</HTML>
示例 2. News.jsp 使用了 JSP 包含标签(SimpleJSPWeb)
<HTML>
<HEAD>
<TITLE>IBM Solutions</TITLE>
</HEAD>
<BODY>
<TABLE border="0">
<TBODY>
<TR>
<TD colspan="2"><jsp:include page="/Header.jsp" /></TD>
</TR>
<TR>
<TD width="20%" valign="top"><jsp:include page="/Navigation.jsp" /></TD>
<TD width="80%" valign="top">
<jsp:include
page="/Fragment-News.jsp" /></TD>
<TR>
<TD colspan="2"><jsp:include page="/Footer.jsp" /></TD>
</TR>
</TBODY>
</TABLE>
</BODY>
</HTML>
Solutions.jsp and News.jsp 的样本代码在 StrutsTiles.zip 下载文件 的 SimpleJSPWeb 项目中。下载并解压 StrutsTiles.zip 后将 EAR 文件导入到一个工作区中:
在 Workbench 菜单中选择 File => Import => EAR file。
单击 Browse选择 EAR 文件。
输入 StrutsTiles 作为项目名称。
要运行任何一个样本,可以遵循下列操作步骤:
右键单击 News.jsp和 Solutions.jsp,然后选择 Run on Server。
Tiles 插入标签提供和 JSP 包含标签相同的功能。下面的 JSP 代码反映包含使用 Tiles 插入标签的解决方案:
示例 3. Solutions.jsp 带有 Tiles 插入标签(SimpleTilesWeb)
<HTML>
<HEAD>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<TITLE>IBM Solutions</TITLE>
</HEAD>
<BODY>
<TABLE border="0">
<TBODY>
<TR>
<TD colspan="2">
<tiles:insert page="/Header.jsp" flush="true"/>
</TD>
</TR>
<TR>
<TD width="20%" valign="top">
<tiles:insert page="/Navigation.jsp" flush="true"/>
</TD>
<TD width="80%" valign="top">
<tiles:insert page="/Fragment-Solutions.jsp" flush="true" />
</TD>
</TR>
<TR>
<TD colspan="2">
<tiles:insert page="/Footer.jsp" flush="true"/>
</TD>
</TR>
</TBODY>
</TABLE>
</BODY>
</HTML>
示例 4. News.jsp 带有 Tiles 插入标签(SimpleTilesWeb)
<HTML>
<HEAD>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<TITLE>IBM Solutions</TITLE>
</HEAD>
<BODY>
<TABLE border="0">
<TBODY>
<TR>
<TD colspan="2">
<tiles:insert page="/Header.jsp" flush="true"/>
</TD>
</TR>
<TR>
<TD width="20%" valign="top">
<tiles:insert page="/Navigation.jsp" flush="true"/>
</TD>
<TD width="80%" valign="top">
<tiles:insert page="/Fragment-News.jsp" flush="true" />
</TD>
</TR>
<TR>
<TD colspan="2">
<tiles:insert page="/Footer.jsp" flush="true"/>
</TD>
</TR>
</TBODY>
</TABLE>
</BODY>
</HTML>
JSP 包含标签和 Tiles 插入标签都解除了 Web UI 组件的耦合。改变一个单独的 UI 组件只需要改变负责该页面的组件,例如 Header.jsp ,而其他页面并不需要改变。示例 3 和 4 的代码位于 SimpleTilesWeb 中。
然而,在以上示例中,如果 Web 应用的 UI 布局需要从图 5 改变到图 6,在后者中主体组件可能是 fragment-Solutions.jsp 或 fragment-News.jsp ,那么有多少页面需要修改呢?如果有 N 个页面有相同的布局,您将需要修改所有的 N 个页面。因此,如果仅仅使用一个 JSP 包含标签或 Tiles 插入标签,Web 应用 UI 的布局仍然是各 JSP 彼此紧耦合的。我们需要找到一个方法来将 JSP 进行更深层的解耦合。
图 5
图 6
使用 Tiles 创建模板
我们面临的新的挑战是找到一个便捷的方法将 Web UI 从一个布局转换到另一个布局。Tiles 模板的特征满足该要求。
什么是 Tiles 模板?
Tiles 模板是一个一般不包含任何实际内容的布局。它包含一些占位符属性使得页面 URI 和字符串可以在将来被插入。内容页面如 News.jsp 和 Solutions.jsp 可以引用该模板并通过这些占位符属性插入 URI。
为创建一个模板页面,您可以使用 Tiles 插入标签。不像示例 3 中的插入标签,在 Tiles 模板中使用的插入标签仅有一个名为 attribute 的属性,它将变成 JSP 页面 URI 插入的占位符。创建页头占位符的模板代码为 <tiles:insert attribute="header" /> 。
该模板定义了具体的页面可以引用的 Web UI 组件的共同布局。以下 JSP 代码就是使用 Tiles 的一个样本模板:
示例 5. Layout.jsp 是 Tiles 模板 (TemplatingTilesWeb)
<HTML>
<HEAD>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<TITLE>IBM Solutions</TITLE>
</HEAD>
<BODY>
<TABLE border="0">
<TBODY>
<TR>
<TD colspan="2"><tiles:insert attribute="header"/></TD>
</TR>
<TR>
<TD width="20%" valign="top">
<tiles:insert attribute="navigation"/></TD>
<TD width="80%" valign="top">
<tiles:insert attribute="body"/></TD>
</TR>
<TR>
<TD colspan="2"><tiles:insert attribute="footer"/></TD>
</TR>
</TBODY>
</TABLE>
</BODY>
</HTML>
在定义完一个模板之后,它本身是不可以使用的。实际的 JSP 页面必须引用该模板并且为其属性提供页面 URI。 <tiles:insert page="/Layout.jsp"flush="true"> 行可用于引用该模板。
具体的 JSP 页面将布局组合委托给模板 Layout.jsp 。它们需要为使用 Tiles put 标签的 attribute 指定页面实现名称。代码 <tiles:put name="header" value="/Header.jsp"/> 将页面 /Header.jsp 插入名为 header 的属性。下面是使用 Tiles 模板特征的 Solutions.jsp 和 News.jsp 的 JSP 代码:
示例 6. 具有 Tiles 模板特征(TemplatingTilesWeb)的 Solutions.jsp
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<tiles:insert page="/Layout.jsp" flush="true">
<tiles:put name="header" value="/Header.jsp"/>
<tiles:put name="navigation" value="/Navigation.jsp"/>
<tiles:put name="body"
value="/Fragment-Solutions.jsp"/>
<tiles:put name="footer" value="/Footer.jsp"/></tiles:insert>
示例 7. 具有 Tiles 模板特征(TemplatingTilesWeb)的 News.jsp
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<tiles:insert page="/Layout.jsp" flush="true">
<tiles:put name="header" value="/Header.jsp"/>
<tiles:put name="navigation" value="/Navigation.jsp"/>
<tiles:put name="body"
value="/Fragment-News.jsp"/>
<tiles:put name="footer" value="/Footer.jsp"/></tiles:insert>
示例 5、6 和 7 的代码在 TemplatingTilesWeb 中。
如果想将布局从图 5 改变到图 6,您所需要做的只是如示例 8 中所示修改模板 Layout.jsp ,而不需要改动具体页面,比如 Solutions.jsp 和 News.jsp 。相比较未使用模板时需要修改 N 个页面,使用了 Tiles 模板特征可以显著地降低维护成本。
示例 8. 修改模板以创建新的布局
<HTML>
<HEAD>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<TITLE>IBM Solutions</TITLE>
</HEAD>
<BODY>
<TABLE border="0">
<TBODY>
<TR>
<TD colspan="2"><tiles:insert attribute="header"/></TD>
</TR>
<TR>
<TD width="80%" valign="top">
<tiles:insert attribute="body"/></TD>
<TD width="20%" valign="top">
<tiles:insert attribute="navigation"/></TD>
</TR>
<TR>
<TD colspan="2"><tiles:insert attribute="footer"/></TD>
</TR>
</TBODY>
</TABLE>
</BODY>
</HTML>
© Copyright International Business Machines Corporation 2003. All rights reserved.
引言
Struts 是有名的模型-视图-控制器(Model-View-Controller,MVC)框架方面的开放源码体现之一,它提供了一种便利的方式,可以用于将模块化应用程序清楚地分解成逻辑、表示和数据。Java 服务器页面(Java™Server Pages,JSP)在 MVC 框架中的作用通常是作为视图(View),它根据业务逻辑和数据生成动态的用户界面(UI)。
在另一方面,Tiles 框架增强了基于组件的设计和 Web UI 设计中的模板概念。它可以帮助开发人员解除 Web UI 组件之间的耦合并重用它们。另外,Tiles 模板及其继承特征使您能够以最小量的工作为 Web 应用程序设计出一致的外观。
IBM® WebSphere® Studio Application Developer Version 5(以下简称为 Application Developer)有内置的对 Struts 1.02 和 1.1(Beta 测试版 2)的工具和运行时支持。Tiles 可以独立于 Struts 使用,也可以与 Struts framework 集成以支持高级特征。
重用 Web UI 组件的需要
本文假定您具有 Struts 和 Application Developer 中的 Struts 工具的基本知识。如果您对本主题的一些基本信息感兴趣,请参阅 用WebSphere Studio V5 编写一个简单的 Struts 应用。
为了更好地理解可以如何重用 Web UI 组件,让我们先来看一下图 1 和 2 中的两个 Web 页面(JSP):
图 1. IBM 解决方案页面
图 2. IBM 新闻页面
您可以看到,这两个页面在页头、左侧的导航条和页脚中有很多组件是共有的。您可以不共享任何组件而为每一个页面创建单独的 JSP 来负责它的布局并且使用重复的页头、左侧导航条和页脚。当然,这种解决方案的效率是非常低的,因为对相同的 UI 组件(比如左侧导航条)的更改要求您改动每个相关的页面。
在上面的示例中,有大量的 HTML 和 JSP 代码是重复的,而 UI 组件是紧耦合的。众所周知,在软件工程中紧耦合的组件将导致高额的维护成本。一个更好的解决方案是解除 UI 组件(页头、导航、页脚和主体)之间的耦合并在不同的页面中重用它们。
<jsp:include> 标签为重用 Web UI 组件提供了一种解决方案。通过使用 <jsp:include> 标签,Solutions 页面和 News 页面可以分解成由四个 JSP 页面,如图 3 和 4 所示:
图 3. Solutions.jsp
图 4. News.jsp
Solutions 页面的 JSP 代码显示在示例 1 中,News 页面的 JSP 代码显示在示例 2 中:
示例 1. Solutions.jsp 使用了 JSP 包含标签(SimpleJSPWeb)
<HTML>
<HEAD>
<TITLE>IBM Solutions</TITLE>
</HEAD>
<BODY>
<TABLE border="0">
<TBODY>
<TR>
<TD colspan="2"><jsp:include page="/Header.jsp" /></TD>
</TR>
<TR>
<TD width="20%" valign="top"><jsp:include page="/Navigation.jsp" /></TD>
<TD width="80%" valign="top">
<jsp:include
page="/Fragment-Solutions.jsp" /></TD>
<TR>
<TD colspan="2"><jsp:include page="/Footer.jsp" /></TD>
</TR>
</TBODY>
</TABLE>
</BODY>
</HTML>
示例 2. News.jsp 使用了 JSP 包含标签(SimpleJSPWeb)
<HTML>
<HEAD>
<TITLE>IBM Solutions</TITLE>
</HEAD>
<BODY>
<TABLE border="0">
<TBODY>
<TR>
<TD colspan="2"><jsp:include page="/Header.jsp" /></TD>
</TR>
<TR>
<TD width="20%" valign="top"><jsp:include page="/Navigation.jsp" /></TD>
<TD width="80%" valign="top">
<jsp:include
page="/Fragment-News.jsp" /></TD>
<TR>
<TD colspan="2"><jsp:include page="/Footer.jsp" /></TD>
</TR>
</TBODY>
</TABLE>
</BODY>
</HTML>
Solutions.jsp and News.jsp 的样本代码在 StrutsTiles.zip 下载文件 的 SimpleJSPWeb 项目中。下载并解压 StrutsTiles.zip 后将 EAR 文件导入到一个工作区中:
在 Workbench 菜单中选择 File => Import => EAR file。
单击 Browse选择 EAR 文件。
输入 StrutsTiles 作为项目名称。
要运行任何一个样本,可以遵循下列操作步骤:
右键单击 News.jsp和 Solutions.jsp,然后选择 Run on Server。
Tiles 插入标签提供和 JSP 包含标签相同的功能。下面的 JSP 代码反映包含使用 Tiles 插入标签的解决方案:
示例 3. Solutions.jsp 带有 Tiles 插入标签(SimpleTilesWeb)
<HTML>
<HEAD>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<TITLE>IBM Solutions</TITLE>
</HEAD>
<BODY>
<TABLE border="0">
<TBODY>
<TR>
<TD colspan="2">
<tiles:insert page="/Header.jsp" flush="true"/>
</TD>
</TR>
<TR>
<TD width="20%" valign="top">
<tiles:insert page="/Navigation.jsp" flush="true"/>
</TD>
<TD width="80%" valign="top">
<tiles:insert page="/Fragment-Solutions.jsp" flush="true" />
</TD>
</TR>
<TR>
<TD colspan="2">
<tiles:insert page="/Footer.jsp" flush="true"/>
</TD>
</TR>
</TBODY>
</TABLE>
</BODY>
</HTML>
示例 4. News.jsp 带有 Tiles 插入标签(SimpleTilesWeb)
<HTML>
<HEAD>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<TITLE>IBM Solutions</TITLE>
</HEAD>
<BODY>
<TABLE border="0">
<TBODY>
<TR>
<TD colspan="2">
<tiles:insert page="/Header.jsp" flush="true"/>
</TD>
</TR>
<TR>
<TD width="20%" valign="top">
<tiles:insert page="/Navigation.jsp" flush="true"/>
</TD>
<TD width="80%" valign="top">
<tiles:insert page="/Fragment-News.jsp" flush="true" />
</TD>
</TR>
<TR>
<TD colspan="2">
<tiles:insert page="/Footer.jsp" flush="true"/>
</TD>
</TR>
</TBODY>
</TABLE>
</BODY>
</HTML>
JSP 包含标签和 Tiles 插入标签都解除了 Web UI 组件的耦合。改变一个单独的 UI 组件只需要改变负责该页面的组件,例如 Header.jsp ,而其他页面并不需要改变。示例 3 和 4 的代码位于 SimpleTilesWeb 中。
然而,在以上示例中,如果 Web 应用的 UI 布局需要从图 5 改变到图 6,在后者中主体组件可能是 fragment-Solutions.jsp 或 fragment-News.jsp ,那么有多少页面需要修改呢?如果有 N 个页面有相同的布局,您将需要修改所有的 N 个页面。因此,如果仅仅使用一个 JSP 包含标签或 Tiles 插入标签,Web 应用 UI 的布局仍然是各 JSP 彼此紧耦合的。我们需要找到一个方法来将 JSP 进行更深层的解耦合。
图 5
图 6
使用 Tiles 创建模板
我们面临的新的挑战是找到一个便捷的方法将 Web UI 从一个布局转换到另一个布局。Tiles 模板的特征满足该要求。
什么是 Tiles 模板?
Tiles 模板是一个一般不包含任何实际内容的布局。它包含一些占位符属性使得页面 URI 和字符串可以在将来被插入。内容页面如 News.jsp 和 Solutions.jsp 可以引用该模板并通过这些占位符属性插入 URI。
为创建一个模板页面,您可以使用 Tiles 插入标签。不像示例 3 中的插入标签,在 Tiles 模板中使用的插入标签仅有一个名为 attribute 的属性,它将变成 JSP 页面 URI 插入的占位符。创建页头占位符的模板代码为 <tiles:insert attribute="header" /> 。
该模板定义了具体的页面可以引用的 Web UI 组件的共同布局。以下 JSP 代码就是使用 Tiles 的一个样本模板:
示例 5. Layout.jsp 是 Tiles 模板 (TemplatingTilesWeb)
<HTML>
<HEAD>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<TITLE>IBM Solutions</TITLE>
</HEAD>
<BODY>
<TABLE border="0">
<TBODY>
<TR>
<TD colspan="2"><tiles:insert attribute="header"/></TD>
</TR>
<TR>
<TD width="20%" valign="top">
<tiles:insert attribute="navigation"/></TD>
<TD width="80%" valign="top">
<tiles:insert attribute="body"/></TD>
</TR>
<TR>
<TD colspan="2"><tiles:insert attribute="footer"/></TD>
</TR>
</TBODY>
</TABLE>
</BODY>
</HTML>
在定义完一个模板之后,它本身是不可以使用的。实际的 JSP 页面必须引用该模板并且为其属性提供页面 URI。 <tiles:insert page="/Layout.jsp"flush="true"> 行可用于引用该模板。
具体的 JSP 页面将布局组合委托给模板 Layout.jsp 。它们需要为使用 Tiles put 标签的 attribute 指定页面实现名称。代码 <tiles:put name="header" value="/Header.jsp"/> 将页面 /Header.jsp 插入名为 header 的属性。下面是使用 Tiles 模板特征的 Solutions.jsp 和 News.jsp 的 JSP 代码:
示例 6. 具有 Tiles 模板特征(TemplatingTilesWeb)的 Solutions.jsp
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<tiles:insert page="/Layout.jsp" flush="true">
<tiles:put name="header" value="/Header.jsp"/>
<tiles:put name="navigation" value="/Navigation.jsp"/>
<tiles:put name="body"
value="/Fragment-Solutions.jsp"/>
<tiles:put name="footer" value="/Footer.jsp"/></tiles:insert>
示例 7. 具有 Tiles 模板特征(TemplatingTilesWeb)的 News.jsp
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<tiles:insert page="/Layout.jsp" flush="true">
<tiles:put name="header" value="/Header.jsp"/>
<tiles:put name="navigation" value="/Navigation.jsp"/>
<tiles:put name="body"
value="/Fragment-News.jsp"/>
<tiles:put name="footer" value="/Footer.jsp"/></tiles:insert>
示例 5、6 和 7 的代码在 TemplatingTilesWeb 中。
如果想将布局从图 5 改变到图 6,您所需要做的只是如示例 8 中所示修改模板 Layout.jsp ,而不需要改动具体页面,比如 Solutions.jsp 和 News.jsp 。相比较未使用模板时需要修改 N 个页面,使用了 Tiles 模板特征可以显著地降低维护成本。
示例 8. 修改模板以创建新的布局
<HTML>
<HEAD>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<TITLE>IBM Solutions</TITLE>
</HEAD>
<BODY>
<TABLE border="0">
<TBODY>
<TR>
<TD colspan="2"><tiles:insert attribute="header"/></TD>
</TR>
<TR>
<TD width="80%" valign="top">
<tiles:insert attribute="body"/></TD>
<TD width="20%" valign="top">
<tiles:insert attribute="navigation"/></TD>
</TR>
<TR>
<TD colspan="2"><tiles:insert attribute="footer"/></TD>
</TR>
</TBODY>
</TABLE>
</BODY>
</HTML>