基于Tiles框架Struts框架的UI 设计—几种组织HTML和JSP视图组件

本文探讨了Struts与Tiles框架下组织HTML和JSP视图组件的有效方法,对比了多种方案,最终展示了Tiles框架与Struts框架结合使用的强大能力。

基于Tiles框架Struts框架的UI 设计—几种组织HTML和JSP视图组件

javaduke 发表于 2003-11-28 15:11:00
作者:sunnyrainy 评论数:0 点击数:5,987 投票总得分:14 投票总人次:8
关键字:Tiles Struts
<!-- end of div title -->

作者: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/
基于实时迭代的数值鲁棒NMPC双模稳定预测模型(Matlab代码实现)内容概要:本文介绍了基于实时迭代的数值鲁棒非线性模型预测控制(NMPC)双模稳定预测模型的研究与Matlab代码实现,重点在于通过数值方法提升NMPC在动态系统中的鲁棒性与稳定性。文中结合实时迭代机制,构建了能够应对系统不确定性与外部扰动的双模预测控制框架,并利用Matlab进行仿真验证,展示了该模型在复杂非线性系统控制中的有效性与实用性。同时,文档列举了大量相关的科研方向与技术应用案例,涵盖优化调度、路径规划、电力系统管理、信号处理等多个领域,体现了该方法的广泛适用性。; 适合人群:具备一定控制理论基础Matlab编程能力,从事自动化、电气工程、智能制造等领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①用于解决非线性动态系统的实时控制问题,如机器人控制、无人机路径跟踪、微电网能量管理等;②帮助科研人员复现论文算法,开展NMPC相关创新研究;③为复杂系统提供高精度、强鲁棒性的预测控制解决方案。; 阅读建议:建议读者结合提供的Matlab代码进行仿真实践,重点关注NMPC的实时迭代机制与双模稳定设计原理,并参考文档中列出的相关案例拓展应用场景,同时可借助网盘资源获取完整代码与数据支持。
UWB-IMU、UWB定位对比研究(Matlab代码实现)内容概要:本文介绍了名为《UWB-IMU、UWB定位对比研究(Matlab代码实现)》的技术文档,重点围绕超宽带(UWB)与惯性测量单元(IMU)融合定位技术展开,通过Matlab代码实现对两种定位方式的性能进行对比分析。文中详细阐述了UWB单独定位与UWB-IMU融合定位的原理、算法设计及仿真实现过程,利用多传感器数据融合策略提升定位精度与稳定性,尤其在复杂环境中减少信号遮挡漂移误差的影响。研究内容包括系统建模、数据预处理、滤波算法(如扩展卡尔曼滤波EKF)的应用以及定位结果的可视化与误差分析。; 适合人群:具备一定信号处理、导航定位或传感器融合基础知识的研究生、科研人员及从事物联网、无人驾驶、机器人等领域的工程技术人员。; 使用场景及目标:①用于高精度室内定位系统的设计与优化,如智能仓储、无人机导航、工业巡检等;②帮助理解多源传感器融合的基本原理与实现方法,掌握UWB与IMU互补优势的技术路径;③为相关科研项目或毕业设计提供可复现的Matlab代码参考与实验验证平台。; 阅读建议:建议读者结合Matlab代码逐段理解算法实现细节,重点关注数据融合策略与滤波算法部分,同时可通过修改参数或引入实际采集数据进行扩展实验,以加深对定位系统性能影响因素的理解。
本系统基于MATLAB平台开发,适用于2014a、2019b及2024b等多个软件版本,并提供了可直接执行的示例数据集。代码采用模块化设计,关键参数均可灵活调整,程序结构逻辑分明且附有详细说明注释。主要面向计算机科学、电子信息工程、数学等相关专业的高校学生,适用于课程实验、综合作业及学位论文等教学与科研场景。 水声通信是一种借助水下声波实现信息传输的技术。近年来,多输入多输出(MIMO)结构与正交频分复用(OFDM)机制被逐步整合到水声通信体系中,显著增强了水下信息传输的容量与稳健性。MIMO配置通过多天线收发实现空间维度上的信号复用,从而提升频谱使用效率;OFDM方案则能够有效克服水下信道中的频率选择性衰减问题,保障信号在复杂传播环境中的可靠送达。 本系统以MATLAB为仿真环境,该工具在工程计算、信号分析与通信模拟等领域具备广泛的应用基础。用户可根据自身安装的MATLAB版本选择相应程序文件。随附的案例数据便于快速验证系统功能与性能表现。代码设计注重可读性与可修改性,采用参数驱动方式,重要变量均设有明确注释,便于理解与后续调整。因此,该系统特别适合高等院校相关专业学生用于课程实践、专题研究或毕业设计等学术训练环节。 借助该仿真平台,学习者可深入探究水声通信的基础理论及其关键技术,具体掌握MIMO与OFDM技术在水声环境中的协同工作机制。同时,系统具备良好的交互界面与可扩展架构,用户可在现有框架基础上进行功能拓展或算法改进,以适应更复杂的科研课题或工程应用需求。整体而言,该系统为一套功能完整、操作友好、适应面广的水声通信教学与科研辅助工具。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值