作者:Prakash Malani
原文:http://www.javaworld.com/javaworld/jw-01-2002/jw-0104-tilestrut.html
译者:sunnyrainy
Email: sunnyrainy5@hotmail.com
QQ: 273771372
MSN: yo13579@sohu.com
摘要每
个web应用开发者一定组织视图组件,例如页首,正文体和页尾。 有许多技术可以组织这些组件,
但每个都有优缺点。这篇文章包括了7个可用的解决方案并让你了解
Tiles框架和Struts框架的灵活性。从一个简单的说明组织视图组件的例子开始,然后使用 JSP内建的机制,像include,
彻底地解决问题。继续看其他的使用Tiles框架的替换方案,然后学会平衡Tiles框架和Struts框架的协作。 (2,000个字;2002
年1月 4 日)
在Web应用软件开发中,一般用户界面负责站点的外观感觉,它可以让人产生真切的感受。通过界面的展现,来展示应用程序功能和导
航。基于Servlet和JSP技术实现用户界面时,当HTML页面被转换为servlets和JSPs时,UI开发人员必须识别哪些是公共的普通
HTML页面,哪些是JSP页面组件,如标题、页脚,主体,菜单和搜索等。这篇文章提供了多种有效的解决方案来组织HTML和JSP视图组件。每个方案都
使用了特定的标准,像页数、编码重复和布局控制等。
为了探究模板和布局方案,我们使用Tiles 框架.Tiles 框架的视图组件叫做tiles。框架 使用XML配置文件来组织这些tiles.框架不仅能让你再次使用tiles,而且还可以对他们进行设计组织。
为了探寻更强大和灵活的方案,我们研究Tiles框架和Struts 框架之间的协作。Struts是一个使用流行的MVC或者Model 2结构模式的用于开发web 应用软件的开源框架.Struts 有着强大标签库,Tile框架的标签库加入使其更加完善。
评价标准评价每个方案有如下标准。标准是兼容的。对于特定的情况和特殊的应用,必须经常均衡每个方案中这些因素的优势与缺陷。
页数(Page number)方案必须尽量使HTML and JSP的页数减到最小。因为页数增加,开发、管理、维护一个应用程序的复杂性将会急剧增加。
代码重复(Code repetiton)在大多数情况下,重复是不好的。HTML and JSP编码越是重复,开发和维护应用程序就越困难。一个简单变化可能在许多不同页面上导致一连串不可预期结果的改变。具体和实际的获得重新使用的方式应避免编码重复。
布局控制(Layout comtrol)尽管编码重复是不好的,但是布局逻辑和编码重复的会更糟。在几个JSPs中的扩展视图组件结构的逻辑和行为可以是一个解决灾难的方法。获得模板的设计逻辑的重复使用是一种比仅仅重复使用视图组件更好的形式。因此,你可以通过有效的布局控制达到一个更高的重复使用的水平。
耦合(Coupling)耦
合是个实体间的兼容性的一个度。软件工程师被重复教育要使不相干的类、包等等之间的耦合减到最小。我们可以对视图组件应用相同的原理。尽管从一个使用者角
度讲视图组件之间是有区别的,但在JSP执行中,组建可能被杂乱的连接。一种解决方案使必须减少不相干视图组件之间的耦合.
复杂性(Complexity)复杂性导致了更多的开发和维护费用,也使得更多的复杂方案不合适。当你增加更多的部分时,复杂性同时也在增加,这将使原本看起来简单的和无害的东西很快转变为大混乱。
解决方案我将使用基本的JSPs例子。通过像header ,footer这样的普通的视图组件来评价一些方案。我将按增加复杂性的顺序给出这些方案,然后相对于评价标准详细的评价每一个。
方案1:基本的JSP假如a.jsp如下:
<html>
<body>
Header<p>
a's body...<p>
Footer<p>
</body>
</html>
假如b.jsp如下:
<html>
<body>
Header<p>
b's body...<p>
Footer<p>
</body>
</html>
在
许多情况,开发者从UI类中直接获取编码,并根据需要直接将他转换成JSP代码。如上所示,每个JSP有重复的HEADER
和FOOTER。方案1是不合需求的,原因是HEADER和
FOOTER视图组件改变,因每页都为所放置的组件负责,所以需要在所有相关页上改变。简单的方案1缺乏远见。有着如此多HTML和JSP
代码重复,我们虽然减少了页的数量,但是需要一个很大的维护费用。就像前面所解释的,不同的视图组件间有着很大的耦合 ,所以这是不合需要的。
方案2:JSP include假如 a.jsp如下:
<html>
<body>
<%-- include header --%>
<jsp:include page="/header.jsp" />
a's body...
<p>
<%-- include footer --%>
<jsp:include page="/footer.jsp" />
</body>
</html>
假如b.jsp如下:
html>
<body>
<%-- include header --%>
<jsp:include page="/header.jsp" />
b's body...
<p>
<%-- include footer --%>
<jsp:include page="/footer.jsp" />
</body>
</html>
注意到普通的诸如header和footer这样的视图组件,使用JSP 的include结构使其分开来了。
假如 header.jsp如下:
Header
<p>
假如footer.jsp如下:
Footer
<p>
方
案2很好的处理了方案1中的一些重要的缺陷。你仅需要改变一次通用的视图组件。因此,这个方案在很大程度上消除了HTML和JSP
CODE重复,尤其是提高了应用程序的可维护性。他增加了一些页数,但他彻底的减少了普通视图组件和其他页之间的轻微的耦合.在复杂度上,这个方案可以很
简单和容易的使用在现有应用程序中。但是,他有一个最主要的缺点:如果你改变了如何组织和哪里放置视图组件(例如,改变组件的布局),你必须更新每一页
--导致了额外的、禁止的改变。方案2成功的使视图组件可以重复使用,但是不能重复使用布局和模板逻辑。
方案3 Tiles insert
假如a.jsp如下:
<%@ taglib uri="/WEB-INF/tiles.tld" prefix="tiles" %>
<html>
<body>
<%-- include header --%>
<tiles:insert page="/header.jsp" flush="true"/>
a's body...
<p>
<%-- include footer --%>
<tiles:insert page="/footer.jsp" flush="true"/>
</body>
</html>
假如b.jsp如下:
<%@ taglib uri="/WEB-INF/tiles.tld" prefix="tiles" %>
<html>
<body>
<%-- include header --%>
<tiles:insert page="/header.jsp" flush="true"/>
b's body...
<p>
<%-- include footer --%>
<tiles:insert page="/footer.jsp" flush="true"/>
</body>
</html>
方案3 使用Tiles insert 机制来代替JSP include 结构。使用Tiles insert 标签,你可将视图组件放置到恰当的位置。在其它所以方面,方案精确的镜像了JSP include方案(方案2),包括了优点和缺点。
方案4:Spiltting bodies
假如 a.jsp如下:
<%@ taglib uri="/WEB-INF/tiles.tld" prefix="tiles" %>
<html>
<body>
<%-- include header --%>
<tiles:insert page="/header.jsp" flush="true"/>
<%-- include body --%>
<tiles:insert page="aBody.jsp" flush="true"/>
<%-- include footer --%>
<tiles:insert page="/footer.jsp" flush="true"/>
</body>
</html>
假如b.jsp如下:
<%@ taglib uri="/WEB-INF/tiles.tld" prefix="tiles" %>
<html>
<body>
<%-- include header --%>
<tiles:insert page="/header.jsp" flush="true"/>
<%-- include body --%>
<tiles:insert page="bBody.jsp" flush="true"/>
<%-- include footer --%>
<tiles:insert page="/footer.jsp" flush="true"/>
</body>
</html>
方案4与Tiles insert方案有些小的不同。方案4将核心主体分隔成几个单独页面,如aBody.jsp and aBody.jsp.
假如 aBody.jsp如下:
a's body...
<p>
假如bBody.jsp如下:
b's body...
<p>
方案4
的优点:他限制了body转变到各个页。同时,在其他地方他也让你能重复使用bodies,消除了重复的需要。因此,这个方案更加减少了通用视图组件于其
他应用软件组件间的coupling
。产生和管理每个body组件引进了一个附加的复杂度。因为用其它的方案的话,每页依旧是他自己的布局。因此,没有过多的布局法则或模式。
方案5:Templating tiles使用Tiles的框架特性,我们可将下面的布局作为模板定义(来自下面所示的layout.jsp文件)。因为这个布局,所以用Tiles tag来插入标识符代替实际的视图组件。因此,对于所有组件而言,这页定义了一个可重复使用的布局:
<%@ taglib uri="/WEB-INF/tiles.tld" prefix="tiles" %>
<html>
<body>
<%-- include header --%>
<tiles:insert attribute="header"/>
<%-- include body --%>
<tiles:insert attribute="body"/>
<%-- include footer --%>
<tiles:insert attribute="footer"/>
</body>
</html>
其它的内容页,像a.jsp and b.jsp使用如上布局来放置组件。在实际的页面里,使用Tiles insert tag来插入布局。使用Tiles put tag可以为布局中特定的标识符指定实际的视图组件。
假如a.jsp如下:
<%@ taglib uri="/WEB-INF/tiles.tld" prefix="tiles" %>
<tiles:insert page="/layout.jsp" flush="true">
<tiles:put name="header" value="/header.jsp"/>
<tiles:put name="body" value="/aBody.jsp"/>
<tiles:put name="footer" value="/footer.jsp"/>
</tiles:insert>
假如b.jsp如下:
<%@ taglib uri="/WEB-INF/tiles.tld" prefix="tiles" %>
<tiles:insert page="/layout.jsp" flush="true">
<tiles:put name="header" value="/header.jsp"/>
<tiles:put name="body" value="/bBody.jsp"/>
<tiles:put name="footer" value="/footer.jsp"/>
</tiles:insert>
方案5最突出的优势是他封装了布局原理图或结构方式,彻底的减少了通用视图组件和其他内容主体间的coupling。然而,他引入了其他布局页面增加了复杂性。首先,理解与执行模块就有困难。
方案6:Struts and Tiles上
面的layout.jsp布局页面,包含了组织组件的HTML and JSP code.内容页a.jsp and b.jsp不包含任何的HTML
code;仅仅包括了Tiles
tags来插入必需的组件。在一个XML文件中指定所有的内容页面会好一点吗?让我们来tileDefinitions.xml文件,指定其页面如下:
<?xml version="1.0" encoding="ISO-8859-1"?>
<component-definitions>
<definition name="aDef" path="/layout.jsp">
<put name="header" value="/header.jsp"/>
<put name="footer" value="/footer.jsp"/>
<put name="body" value="/aBody.jsp"/>
</definition>
<definition name="bDef" path="/layout.jsp">
<put name="header" value="/header.jsp"/>
<put name="footer" value="/footer.jsp"/>
<put name="body" value="/bBody.jsp"/>
</definition>
<definition name="cDef" path="/layout.jsp">
<put name="header" value="/header.jsp"/>
<put name="footer" value="/footer.jsp"/>
<put name="body" value="/cBody.jsp"/>
</definition>
</component-definitions>
方案6把定义放置在XML文件中,消除了就像a.jsp and b.jsp一样的所有内容页。因像a.jsp and b.jsp这样的程序不再存在,我们怎样请求他?更重要的是,如何在tileDefinitions.xml文件中请求定义?
Struts and Tiles强大和协作的整体可被挽回。除了常规的配置参数以外,我们在web.xml文件中作为另一个参数指定配置文件的地址。如下所示。指定参数definitions_config使Struts能找到并知道关于Tiles 的定义。
<!-- Standard Action Servlet Configuration (with debugging) -->
<servlet>
<servlet-name>action</servlet-name>
<!--
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
-->
<servlet-class>org.apache.struts.tiles.ActionComponentServlet</servlet-class>
<init-param>
<param-name>definitions-config</param-name>
<param-value>/WEB-INF/tileDefinitions.xml</param-value>
</init-param>
...
</servlet>
我们现在定义一个Struts action,他将返回一个成功的在配置文件中指定的定义。Struts action DoFirst 是一个不运行的行为,如下所示:
package com.malani.struts.action;
import org.apache.struts.action.*;
import javax.servlet.http.*;
public class DoFirst extends Action {
public ActionForward perform(
ActionMapping aMapping,
ActionForm aForm,
HttpServletRequest aRequest,
HttpServletResponse aResponse
) {
return aMapping.findForward("success");
}
}
你不能使用直接来自浏览器的定义,但是 你可以使用来自Struts的就像实际程序一样的一个。在struts-config.xml的文件中定义Struts actions如下:
<action path="/a"
type="com.malani.struts.action.DoFirst"
>
<forward name="success" path="aDef"/>
</action>
<action path="/b"
type="com.malani.struts.action.DoFirst"
>
<forward name="success" path="bDef"/>
</action>
<action path="/c"
type="com.malani.struts.action.DoFirst"
>
<forward name="success" path="cDef"/>
</action>
现在通过分别请求a.do and b.do actions来返回所需的程序。
方案6的主要优点是他把所有的定义都统一到一个XML配置文件里。减少内容页很彻底的减少了总的页数。通过引进Struts,在另个方法上增加了复杂性。
方案7:Tiles inheritance在
定义配置文件中,可观察到每页定义看起来是一样的。每个定义有三个组件,两个被固定为header and
footer.强大的Tiles特性使得定义间有了继承性。因此,你可以定义一个基础定义,让原始定义从那个定义上继承来。原始的定义必须仅支持他们的单
一部分。下面显示了带有定义间继承性的XML配置文件:
<?xml version="1.0" encoding="ISO-8859-1"?>
<component-definitions>
<definition name="baseDef" path="/layout.jsp">
<put name="header" value="/header.jsp"/>
<put name="footer" value="/footer.jsp"/>
<put name="body" value=""/>
</definition>
<definition name="aDef" extends="baseDef">
<put name="body" value="/aBody.jsp"/>
</definition>
<definition name="bDef" extends="baseDef">
<put name="body" value="/bBody.jsp"/>
</definition>
<definition name="cDef" extends="baseDef">
<put name="body" value="/cBody.jsp"/>
</definition>
</component-definitions>
这个方案的优势是消除了配置文件理重复和多余的信息。总之,这个方案的优点和缺点与Struts and Tiles方案的一样。
方案总结 如下表格总结了各个方案的评价指标方面的内容。我鼓励你增加其他的有创造性的方案,和其他重要的,像可延展性、可维护性、可操作性这样的评价指标。
各种解决方案的每项评估指标:
IMG ../upload/article/a20031128150959.gif[/IMG]
表格表明每个方案的复杂度是逐渐上升的。同时他也表明当你增加复杂度时,减少了编码复制,增加了设计控制的灵活性,减少了不相干视图组件的Coupling.页数最初是当视图组件分开时增加的,但当你在一个定义结构之中定义了更多页的时候,合并会发生。
那个方案是最好的?
最
好的方案是要依据你项目所需和你在开发和维护一个web应用程序中的技能和知识。基本的方案太简单;我并不推荐他,因为他不支持好的软件工程师的实践经验
的思路。如果你的web应用程序是复杂的,模板给你提供了一个很好的布局控制。因此你可能想研究和使用一个像Tiles一样的模板框架。如果你已经使用了
Struts,接着你必须为一个强大的方案调节Tiles and Struts之间的协作。
Divine design
在这篇文章里,评价了不同的在HTML and JSPs中组织视图组件的方案。同时也研究了Struts and Tiles框架之间的协作性。这些策略和方案可以帮助你做一个有关于你的web应用程序的设计和结构的决定。
对审阅这篇文章的Max Cooper, Stephen Ditlinger, Dru Jensen, Phillip Lindsay, Roshni Malani, Danny Trieu, and Clare Zhang致以最诚挚的谢意。资源:方案1-7源代码:
http://www.javaworld.com/javaworld/jw-01-2002/tilestrut/1_basic.zip
http://www.javaworld.com/javaworld/jw-01-2002/tilestrut/2_JSPinclude.zip
http://www.javaworld.com/javaworld/jw-01-2002/tilestrut/3_tilesInsert.zip
http://www.javaworld.com/javaworld/jw-01-2002/tilestrut/4_bodies.zip
http://www.javaworld.com/javaworld/jw-01-2002/tilestrut/5_templatingTiles.zip
http://www.javaworld.com/javaworld/jw-01-2002/tilestrut/6_struts.zip
http://www.javaworld.com/javaworld/jw-01-2002/tilestrut/7_inheritance.zip
Tiles框架:
http://www.lifl.fr/~dumoulin/tiles/
相关推荐
《精通Struts:基于MVC的JavaWeb设计与开发》是由孙卫琴编著的一本经典书籍,专门探讨了如何使用Struts框架进行高效的JavaWeb应用程序开发。这本书深入浅出地介绍了Struts的核心概念、架构以及实践应用,帮助开发者...
在JSP中,界面框架扮演着至关重要的角色,它帮助开发者高效地组织和管理代码,提供可重用的组件,以及增强应用程序的用户体验。下面我们将深入探讨JSP界面框架的关键知识点。 1. **MVC模式**:许多JSP界面框架,如...
它提供了一种组织和重用网页内容的方法,使得开发者可以创建可复用的模板,提高UI设计的效率和一致性。Tiles的核心概念是“定义”(definitions),这些定义描述了页面的布局和组成,包括多个部分(或称为“部件”)...
《精通Struts:基于MVC的Java Web设计与开发》是由孙卫琴女士撰写的一本专业书籍,旨在帮助读者深入理解和应用Struts框架进行Java Web应用程序的开发。这本书的源代码是作者为了辅助读者实践书中的示例和案例而提供...
Struts2框架是一款基于Model-View-Controller(MVC)设计模式的开源Java Web应用程序框架。它是Apache软件基金会的一个项目,旨在提供一个用于构建企业级Web应用的强大平台。Struts2框架是在Struts1的基础上发展起来...
本压缩包中的"ssh之struts包"可能包含了Struts框架的基础组件、配置文件示例以及相关的JSP页面和Action类。使用这些文件,开发者可以快速搭建起一个基础的Struts应用,然后根据实际需求添加额外的功能,如服务层...
标签是Struts2中的一个重要部分,它们是JSP页面上的UI组件,可以帮助开发者更方便地创建动态界面。例如,s:form、s:textfield、s:submit等标签简化了表单处理,而s:if和s:iterator则提供了条件判断和循环功能。 总...
Struts框架是Java Web开发中的一个关键组件,它是一个基于MVC(Model-View-Controller)设计模式的开源框架。这个框架的主要目的是提供一个结构化的、可维护的、可扩展的方式来构建Web应用程序。通过使用Struts,...
Struts框架是一个强大的Java EE平台上的MVC框架,它的出现是为了应对传统JSP或Servlet开发中的挑战,如代码与UI的耦合问题,以及项目的可维护性和效率问题。Struts框架提供了一种结构化的方式来组织应用程序,使得...
6. **用户界面(UI)组件**:Struts 2支持多种视图技术,如JSP、FreeMarker或 Velocity。教师和学生交互的界面应当简洁易用,通常会包含表单元素(如文本框、文件输入)和链接,这些可以通过Struts 2标签库轻松实现...
1. **Tiles插件集成**:Struts2.0.9支持Tiles框架,允许开发者创建可重用的页面布局,提高了UI设计的灵活性。 2. **OGNL(Object-Graph Navigation Language)表达式语言**:OGNL是Struts2的默认表达式语言,用于在...
JSF是一种组件化的Web开发框架,通过UI组件处理用户交互。配合Facelets视图技术,可以创建动态页面。可以使用内置的Managed Beans进行业务逻辑处理,登录验证。对于安全,可以集成Apache Shiro或Spring Security。 ...
- **Struts Tiles**:用于管理页面布局和组合多个组件,提升UI设计的灵活性。 4. **Struts与其它技术的结合**: - **Struts与Hibernate整合**:将持久层框架Hibernate引入,简化数据库操作。 - **Struts与Spring...
通过以上内容可以看出,Struts框架通过实现MVC设计模式,极大地简化了Web应用程序的开发过程,并且提供了一系列丰富的工具和组件来支持开发者的日常开发工作。尽管它有一些局限性,但对于那些需要构建结构清晰、易于...
Struts2是一个强大的Java web应用程序框架,它基于Model-View-Controller(MVC)设计模式,为开发者提供了构建可维护性高、结构清晰且易于扩展的Web应用的工具。Struts2的核心在于它能有效地分离业务逻辑、数据模型...
7. **Tiles框架集成**:Struts可以与Tiles框架集成,用于创建可重用和模块化的页面布局,提高UI设计的灵活性。 8. **国际化和本地化**:Struts支持多语言环境,通过资源文件实现国际化,方便不同地区的用户使用。 ...
13. **Tiles框架集成**:Struts 2可以与Tiles框架结合,实现布局和复用视图组件。 综上所述,"struts-2.3.8 doc"文档将深入讲解这些概念,帮助开发者熟练掌握Struts 2框架的使用,从而高效地构建和维护Java Web应用...
9. **Struts Tiles**:Tiles是一个扩展组件,允许开发者创建可重用的页面布局和组合视图,提高UI设计的效率。 10. **Struts ActionServlet**:这是Struts框架的入口点,负责解析请求,调用相应的Action,处理结果等...
Struts是Apache软件基金会Jakarta项目的一个子项目,它是一个基于MVC(Model-View-Controller)设计模式的Java Web框架,用于简化开发出结构清晰且易于维护的Web应用程序。 在JavaEE平台上,Struts提供了以下核心...