原创作者: marszgl   阅读:4110次   评论:1条   更新时间:2011-05-26    

Web显示层技术评估

 
buaawhl 发表于 2006-07-14 16:59
关键字: Webwork  
   



Web显示层技术评估
名词界定
显示层的意思就是Presentation Layer,也翻译成表现层、展现层、展示层。
本文讨论的范围只包括采用HTML Template的显示层技术,不包括Echo,GWT(google web toolkit)等根据代码产生HTML的工具。
本文主要讨论Server Side (针对Java Language)的显示层技术,然后进一步讨论Browser Side(Ajax)的显示层技术(一个典型的Ajax应用也分为Model, View, Controller – Data, HTML/CSS, JavaScript)。注意,本文关于Ajax的讨论只有很少一部分,因为我不擅长这个领域。只是一个顺便的扩展比较。
一个很有趣的现象。Server Side和Browser Side的显示层技术格局恰好相反。Server Side的Scripted Template技术比较多,比较流行;而Browser Side的HTML DOM Manipulation技术、HTML View Model技术比较多,比较流行。
本文会提到一些技术、或者框架的名称,但只局限于讨论该技术、该框架的显示相关部分的内容,而不涉及评估其他方面的特性。比如,本文不讨论Link URL Generation, Action URL Generation,Button Script Generation这些页面组件事件机制的方面。
本文是一个深度讨论。不讨论简单的替换个字符串的Hello World案例,而是穷尽各种显示层技术的能力极限,探索它们在复杂布局(动态include等)、复杂显示逻辑(条件、循环、嵌套、递归)等方面的功能。

对了,(考虑到Site Mesh,Struts Tiles Taglib等技术广泛的群众基础),可能需要专门提一下,本文将不讨论Site Mesh,Tiles等布局技术(named include)。
Site Mesh相当于XSL的一个简化版本,只保留了根据(name->file)配置替换某个HTML Node的能力,其余的如Tiles,也大致如此,由于多了一个(name->file)配置文件,比直接include file高级了不少。
由于使用简单(功能自然也简单),这类技术获得了广大群众的支持,呼声很高。本文为忽略了这一类技术感到很遗憾。

另外需要指出的是,并不存在一个十全十美的方案。
工作总是要做的,不是在Template里面做,就是在Java Code里面做,总之,总要找个地方做这个工作,天下没有免费的午餐。一方面特性增强了,自然影响到另一方面。
正如,代码的耦合实际上并不能完全消除,我们只能把这些耦合点移动来移动去,今天我看这里不舒服了,把耦合点移动到另一个地方;明天另一个人看到那里不舒服了,又移动回来。而且各自都能说出一大堆道理。
所以,需要注意的是,并不存在一个绝对的优胜方案。本文只是列出各种技术指标的参考评估数据,以便帮助读者根据自己的需要,做出比较准确的评估。(是的,准确的量化评估,而不是广告语或者口号)

理论模型
一个显示的整个过程,如果用一个函数来描述,那么看起来大概是这样。
F(Data, Template, Display Logic) => Result HTML
其中的Display Logic,就是显示逻辑。Display Logic操作Data和Template,产生最终结果。
这个Display Logic可能以各种形式出现在任何地点。
比如,可能作为Server Side Script存在于Template里面,把Data取出来输出;也可能存在于后台Java里面,根据Data操作Template Node。
针对前一种情况,函数公式表达是:Template Script (Data) => Result
针对后一种情况,函数公式表达是:Logic (Data, Template) => Result

这个模型可以作为显示层技术的划分标准。
(1) Scripted Template
HTML和Server Side Script混杂在一起的显示层技术。
包括JSP, Velocity, Freemarker, Taglib, Tapestry, XSL等。
肯定有人对这个划分有异议。XSL里面有choose, if, for。这还好说。尤其是对Taglib, Tapestry,反映可能更加强烈。我似乎已经看到,Taglib or Tapestry Fans已经跳起来了,高叫着,Taglib or Tapestry明明是组件技术,组件技术,组件技术….
这里我还是表示很遗憾。在目前定义的这个狭义模型下,任何Template中包含Logic的显示技术都划为Script这一类。而且在表示逻辑的时候,这类组件技术表现的更加突出一些。
比如Tapestry的 等逻辑标签。尤其是这个if not,是专门多出来的一个条件语句,一般的编程语言里面都不具备这样的对应语法。当然,Tapestry并不专美,Taglib的Logic Tag也是如此。

(2)Template Manipulation
Java代码直接操作Template(比如,HTML DOM)产生结果的显示层技术。
包括XMLC, JDynamiTe, Rife等。
大家对这一类技术可能不是很熟悉。后面进行特性分析的时候,会举出一些典型的例子,来说明各自的用法。
一个很有意思的现象是,在Browser Side(Ajax),由于Java Script操作HTML DOM非常方便,这类显示技术非常普遍。相反的,Scripted Template的技术,在Browser Side却不多见。后面讨论Browser side的时候,会列举一些典型的例子。

(3) Model Match
Java代码负责提供符合显示层要求的Data Model,显示层框架本身把Data Model和Template进行匹配,产生结果。
包括Wicket, Fastm, DOMPlus, 等。
Wicket如同Swing的用法,需要为不同的UI Component提供不同的View Model,比如Table, List, Label等。Fastm, DOMPlus支持POJO,但同样需要满足一些框架特有的约定。
也许有人会说,某些Display Tag Lib, Tapestry Components可能也需要Java Code提供特殊的View Data Model。
不过,需要特殊的View Data Model,并不是一个好的特性,意味着不支持POJO。

数据寻址
在正式开始之前,先说明一下数据寻址的概念。
数据寻址,意思是数据访问、属性获取等。主要包括两类风格。
(1) OGNL Style
http://www.ognl.org/
OGNL (Object Graph Navigation Language)如此著名和深入人心,以至于我在这里用OGNL Style代表Java Bean属性寻址的方式。
比如,a.b[1].c.d[2].name
另一类当然是
(2)XPath Style
比如,a/b[1]/c/[d]/@name
XPath Style主要应用在XSL中。
一个JXPath项目能够按照XPath的方式访问Java Bean属性。
http://jakarta.apache.org/commons/jxpath/

简单的寻址,OGNL和XPath能够对应起来。但是,OGNL和XPath都各自是功能很强大的语言,复杂的用法并不能对应。

评估指标

下面列出一系列比较详细的、能够落到实处的、能够客观量化的、可操作的评估硬指标。
排名不分先后。大家可以参考各自关心的选项。
虽然下面主要针对的都是Java Web 显示技术,但这些指标同样适用于其他语言的Web显示技术。
评分采取10分作为满分。
(1) Host Language Consistency宿主语言一致性
Server Side Template Script和Server Host Language是同一种语言。这应该是专门针对JSP的优势来说了。JSP能够获得10分。
另外,XSL也是。XSL本是也是XML格式。也能够获得10分。
其他的Template Script,如taglib,tapestry只能获得0分。
freemarker, velocity由于具有一定的动态解释的方便特性,可以获得2分。
至于在Java Code里面操作Template或者提供匹配数据的那些技术,由于Template中不存在Script Logic,能够获得5分。
大家可能不太注意这个特性。但是这个特性还是有一些意义的。其他的如ASP.net,还有动态语言,Ruby, Python, PHP, Perl等,都是Template Script和宿主语言一致。
这能够一定程度上降低学习成本。尤其是宿主语言比较适合作为Script的情况下。

(2)Template Purity 模板纯净度
这主要是指Template里面没有Script Logic代码污染。
这方面,所有的Scripted Template技术都只能获得0分。
XMLC能够获得10分,只利用HTML本身的Attribute,没有增加任何自定义DOM Attribute。
Wicket, DOMPlus能够获得9分,它们增加了一部分自定义DOM Attribute。
JDynamiTe, Fastm能够获得7分,它们采用了XML Comment作为自定义结构标签。
Rife也能够获得3 -- 7分,具体看它采用什么标签格式。
(3)Template Tidiness 模板整洁度
主要是指Template的格式是否整齐规范。Taglib, XSL无疑是胜利者,本身就是XML格式,通用的XML Parser就可以解析它们,比较容易在IDE Plugin中处理。
XMLC, Taglib, XSL能够获得10分。
Tapestry, Wicket, DOMPlus 也能够获得10分,同样是XML格式。
JDynamiTe, Fastm, Rife能够获得5分。
JSP, Velocity, Freemarker只能获得0分。
(4) Replacement Flexibility 替换灵活度
主要是指能否自由替换Template里面的任何一块文本。不用考虑DOM Node。
JSP, Freemarker, Velocity, Rife, JDynamicTe, Fastm无疑是胜利者,毫无限制,能够获得10分。
Taglib, XSL, Tapestry, Wicket, XMLC, DOMPlus都或多或少受到DOM Node的限制(解析的最小单位是XML Node),能够获得6分。
(5)WYIWYG 所见即所得
Template能够在Browser里面直接大致正确显示,设计人员友好。
XMLC, DOMPlus得分10。
Wicket得分9。
JDynamiTe, Fastm, (Rife根据情况) 得分8。
Tapestry得分7。HTML毕竟夹杂了Logic Tag。
JSP, Freemarker, Velocity, Taglib, XSL得分0。

Freemarker, Velocity属于按行解析,有可能采取如下手段,把语句包含在XML Comment里面,进行显示友好的处理。这种情况下得分5。
<!-- <br /> #if …. <br /> -->

由于Taglib的XML规范格式,使得某些IDE Plugin,DreamWeaver Plugin能够显示HTML Display Taglib。如果是对于此类Plugin来说,Taglib的所见即所得分数可以是0-- 5分。类似于Tapestry,仍然是Logic Tag影响了最终得分。
(6)Action Code Purity 用户代码纯净度
主要是指用户提供显示数据的后台Java代码的纯净度,是否免除了HTML,或者Template操作的污染。
Servlet的HTML污染现象就非常严重。代码里面夹杂了大量的HTML Text。分数自然是0。
JSP, Freemarker, Velocity都能够获得10分。用户后台代码十分纯净,不需要引入具体框架的代码。任何一份Action Code,完全不用知道自己使用的是什么Template,这三种Scripted Template都能够随意替换。能够获得10分。pojo
Taglib根据各种具体情况,能够最高获得8分。
Fastm, DOMPlus需要根据一定的约定,产生POJO数据。用户Action Code同样不需要引入具体的框架代码,产生的这些数据同样可以很容易地被其他Template,比如JSP, Freemarker, Velocity使用,能够某种程度上替换Template。能够获得6分。
Tapestry需要在每份用户Action Code里面引入Template框架的Package。只能获得4分。
Wicket不仅需要在每份用户Action Code里面引入框架的Package,还需要引入框架特殊的View Data Model数据类型,并且提供特殊类型的数据。只能获得2分。
XMLC, Rife, JDynamiTe不仅需要在每份用户Action Code里面引入框架的Package,而且需要大量的Template操作。只能获得0分。

(这项特性的比较,对于Tapestry,Wicket来说是不公平的。因为它们的框架就包括了Template本身。Action里面引入框架Package是很正常的。而且这些框架同样可以外接其余的Template,只是原来的编程模型,需要做一些更改。这里只是对于单项比较就事论事。)
(7) Infrastructure Code Purity 基架代码纯净度
这里是指框架的内部实现代码里面是否夹杂了HTML Text污染。这也意味着如果用户需要扩展页面UI组件,是否也需要在代码里面夹杂HTML Text。
HTML Taglib, Wicket, Tapestry的框架实现代码里面包含了很多HTML Text输出语句。用户需要自定义扩展页面UI组件,也需要在代码里面夹杂HTML Text。所以,得分只能是0。
JSP, Freemarker, Velocity, XMLC, XSL, Rife, JDynamiTe, Fastm, DOMPlus得分都是10。
(8)动态Include
即运行的时候,动态选择Include另外的Template文件。
JSP文件里面的 @ include 属于静态Copy And Paste技术。
Jsp:include命令是动态Include (经codeutil指正)
相当于
<!--br /> request.getRequestDispatcher(…).include(request, response); <br /> -->

Velocity, Freemarker的#Parse指令应该也是动态解释执行的。也可以算是动态Include。
至于XMLC, Rife, JDynamiTe这类技术能够随意操作Template Node,动态Include也是小菜一碟。
Fastm, DOMPLus同样提供了操作Template Node的能力,而且为了避免这类Template Manipulation代码污染,还提供了类似于XSL的Node Interceptor的机制实现动态Include。
XSL Apply Imports Call Template能够动态引入并使用其他的XSL。

所以,JSP, Freemarker, XMLC, Rife, JDynamiTe, Fastm, DOMPlus, XSL的动态Include方面的分数都是10。
其余的,Taglib, Wicket, Tapestry得分为0。
(9)Recursive Display of Tree Data树型数据的递归显示
递归显示一个任意深度的树型数据,这是一个动态Include基础上的更高级的需求。可以说,不支持动态Include,就不支持递归显示。
递归,XSL无疑是天生赢家。XSL的Pattern Match语法可以说就是为递归编写的。
其余的语法都是Imperative Programming。递归的前提是必须能够定义一个方法,自己直接或者转弯抹角的能够调用到自己。
对于JSP, Velocity, Freemarker这类没头没尾的Script来说,属于强人所难。
Tapestry, Taglib, Wicket比较牛,专门提供了Tree Model。
XMLC, Rife, JDynamiTe这些Template Manipulator高兴了,可以在Java代码里面任意根据数据任意操作Template Node。
Fastm, DOMPlus不仅可以在Java代码里面任意操作,而且提供了类似于XSL Pattern Match的Node Interceptor功能,不需要写Template Node操作代码,就可以实现递归。而且可以实现Data Iterator + Template Iterator的匹配序列。

递归方面,得分如下。
XSL, XMLC, Rife, JDynamiTe, Fastm, DOMPlus得分10。
Tapestry, Taglib, Wicket能够显示特定的Tree Model。得分4。
其余的,得分0。只能通过Java代码里面夹杂一堆的HTML Text,然后整体输出给Scripted Template来实现。
(10) Space Efficiency空间效率
基于Template Manipulation的技术都有空间效率问题。用户同时访问同一个Page的时候,内存中存在多个副本。XMLC的问题可能最重。因为XML DOM结构很重。
JDynamicTe, Rife直接在一个Template Node上操作,如果有多个用户同时访问同一个Page。那么同一份Template Node就会在内存中Duplicate多份。

空间效率方面得分情况
XMLC得分0。JDynamicTe, Rife得分3。如果静态文本节点作了优化,分数可能更高。
Taglib由于编译的结果非常臃肿,Tag之间的信息交流非常困难。分数为6。
DOMPlus一份DOM产生多份SAX Event,没有严重的多副本问题,但是DOM结构本身比较大,所以得分为6。
其余的技术,内存里的静态文本都只保存一份,都没有严重的空间效率问题,得分都是10。
(11) Mapping Explicitness 映射关系明显度
什么数据应该显示在什么位置,一目了然。这种特性。
JSP, Velocity, Freemarker直接在Template里面把数据取出来显示,一目了然,清清楚楚,得分都是10。
Wicket的强制View Model 类型这里帮了大忙,无时无刻不提醒用户Model 和 View (Template)之间的映射关系。得分8。
XMLC直接操作HTML Node By ID, or By Generated Method, 得分为7。
比起,JSP等来说,Taglib的映射关系就隔了一层。尤其是当Tag之间存在层次关系的时候,比如,Form Tag下面的Input Tag,Select Tag下面的Option Tag。Taglib的分数只有6。
XSL的XPath Pattern Match也是要稍微转个弯,类似于AOP Interceptor的思路。得分为5。
Tapestry的配置如此复杂,得分只有4。
Rife, JDynamicTe直接操作Template Node,而且是自定义层次的Template Node,用户编写Action Code的时候,必须随时查看Template里面的那些自定义标签之间的层次关系,并完全理解,了然于胸,才可能编写正确的代码。这方面的成本大大提高。分数只有3。
Fastm, DOMPlus的问题类似,也是自定义层次的Template Node,需要随时查看Template里面的那些自定义标签(或者DOM Attribute)之间的层次关系。分数只有3。
(12) Display Logic Reusability 显示逻辑重用度
嵌在Template里面的Server Side Script代码,不具有任何可重用性。除了整个Include,你无法在另外的地方调用Template里面的某一段代码。
JSP, Velocity, Freemarker, Logic Taglib, Tapestry Logic Tag,XSL的逻辑可重用度分数都是0。当页面设计人员更改了具体页面布局元素(HTML Tag)的时候,原来的Template里面的Script全部作废,需要重新填充到新的HTML里面。
Template Manipulation和Model Match技术的显示逻辑都存在后台的Java代码里面,自然是可以重用的。方法调用,类继承,包含,怎么都行。

Wicket的View Model都是绑定到具体的HTML UI Tag上,比如,List, Table等。当这些Tag变化较大的时候,原有的代码都需要改变。某些HTML Display Taglib也是如此。重用度分数为4。
当结构层次没有变化,只是具体的HTML Tag变化的时候,XMLC的原有DOM处理代码几乎不需要变动。在处理循环的时候,代码需要Create Specific HTML DOM Node,然后添加到某个DOM Node上面。而且代码可能大量使用自动产生的代码的方法。这影响了它的得分,分数为4。
当结构层次没有变化,只是具体的HTML布局元素发生了变化,那么,Rife, JDynamiTe,的代码都不需要变化。但是,它们的代码侵入性非常强,比XMLC还要强(如果XMLC采用标准的HTML DOM操作方法)。权衡考虑,Rife, JDynamiTe的重用度分数是5。
当结构层次没有变化,只是具体的HTML布局元素发生了变化,Fastm, DOMPlus的代码也不需要变化。而且,Fastm, DOMPlus没有代码侵入性,产生的Data Model就是POJO,可以用在JSP, Velocity, Freemarker,Taglib里面。所以,重用度分数为8。

Scripted Template
前面讲述了评估指标。下面分别各项技术进行单项说明。
(1) Scripted Template
HTML和Server Side Script混杂在一起的显示层技术。
包括JSP, Velocity, Freemarker, Taglib, Tapestry, XSL等。

Server Side的这些Scripted Template技术比较流行,耳闻能详。前面进行指标描述的时候,各种参数,也基本上涉及到了。就不具体展开进行单项的用法说明和特性分析。
JSP, Velocity, Freemarker的优势在于这些技术对用户后台Java代码侵入性非常低,这些Template都可以任意替换,而不影响用户后台Java代码。

下面讲述另外两类不是很常见的技术。
(2)Template Manipulation
Java代码直接操作Template(比如,HTML DOM)产生结果的显示层技术。
包括XMLC, JDynamiTe, Rife等。

(3) Model Match
Java代码负责提供符合显示层要求的Data Model,显示层框架本身把Data Model和Template进行匹配,产生结果。
包括Wicket, Fastm, DOMPlus, 等。

Template Manipulation

Java代码直接操作Template(比如,HTML DOM)产生结果的显示层技术。
包括XMLC, JDynamiTe, Rife等。
这类技术都具有良好的所见即所得特性。
(1)XMLC
http://xmlc.enhydra.org/
XMLC把一个HTML文件翻译成一个Java HTML DOM Class,
比如,


... ...
这些具有id的HTML元素,在Java HTML DOM Class都产生了对应的方法。
HTMLElement getElementPara1()
public void setTextPara1(String text)
HTMLTitleElement getElementTitle()
HTMLInputElement getElementNameInput();

比如, CLASS="class1 class2">
就产生了如下的Constant Fields.
public static final String NAME_myName;
public static final String CLASS_class1;
public static final String CLASS_class2;

具体操作代码如下,
HTMLObject htmlObj = new HelloHTML();
// Construct head
HTMLHeadingElement head = htmlObj.createElement("h1");
Text headText = htmlObj.createText("Hello World");
head.appendChild(htmlTest);

// Construct anchor
HTMLAnchorElement anchor = htmlObj.createElement("a");
anchor.setHref("Welcome.po");
Text anchorText = htmlObj.createText("Welcome Page");
anchor.appendChild(anchorText);

// Replace contents of id-labeled node.
Element replace = htmlObj.getElementReplaceme();
Element parent = replace.getParent();

// Start with the last new child so we can use insertBefore
parent.replaceChild(anchor, replace);
parent.insertBefore(head, anchor);

可以看到,用户的Action Code里面充满了HTML DOM Node的添加删除操作。而且里面使用的代码都不是标准的DOM操作方法,而是代码生成的方法。代码侵入性非常强,如果要换成别的Template,比如JSP, velocity所有的代码都要作废。
当然XMLC产生的是一个DOM,后面还是可以接续XSL的。

一般来说,XML DOM操作只能针对完整的Node。一般需要替换整个Attribute,整个Text。
对于, 另外有一个不常见的需求。动态替换Java Script代码的里面的某一部分。这时候,XMLC就完全无能为力了。或许也可以引入外来的Text Parser Engine,比如Velocity, Freemarker, Fastm, JDynamicTe等来做这件事情。http://jdynamite.sourceforge.net/doc/jdynamite.html

XMLC的主要问题还是空间效率问题。每次请求,用户需要产生一个Java DOM Class副本,进行操作。如果有多个用户访问同一个Page,那么就同时存在多个Java DOM Class副本。
当然里面的静态文本资源是共享的,我们看到上面的Java DOM Class里面,产生了很多String常数。
但是DOM Node结构本身的尺寸就比较大。即使采用了一些优化简化的DOM Parser,去除了用不到的结构,整个尺寸还是比较大。
(2) JDynamiTe

JDynamiTe是PHPLib Template的移植。采用XML Comment的方式标记动态结构块。
我们来看一个典型的两层循环的例子。

 

{VALUE_X} {VALUE_Y}

对应的代码是,
import cb.jdynamite.*;

dynamiTe=new JDynamiTe();
dynamiTe.setInput(application.getRealPath("cbtemplate/testTemplate.html"))
// Second table with nested Dynamic Element
for (int row = 0; row < 5; row++) {
// first group of columns
// 4) Use "setDynElemValue" to set or reset the value of a Dynamic Element
dynamiTe.setDynElemValue("colX", ""); // reset for each row
for (int col = 0; col < 3; col++) {
dynamiTe.setVariable("VALUE_X", "line_" + row + ",col_" + col);
dynamiTe.parseDynElem("colX"); // add a column
}
// second group of columns
dynamiTe.setDynElemValue("colY", ""); // reset for each row
for (int col = 3; col < 5; col++) {
dynamiTe.setVariable("VALUE_Y", "line_" + row + ",col(BIS)_" + col);
dynamiTe.parseDynElem("colY"); // add a column
}
dynamiTe.parseDynElem("myBigRow"); // add a row
}
// 5) Use "parse" to finaly get the value of your Dynamic Template Document
dynamiTe.parse();
out.println(dynamiTe.toString()); // send HTML page

我们看到,Template本身操作贯穿程序的始终。
setDynElemValue, setVariable, parseDynElem, parse都是template Class本身的方法,类似于XML DOM Node的添加删除修改。
我们看到这类DOM Manipulator的代码侵入性非常强,用了之后,如果要换别的Template,比如JSP, velocity,这段代码完全作废。
(3) Rife
http://rifers.org/
类似于JDynamiTe,Rife也采用自定义动态块标签。
下面是一个典型的例子。递归显示一个Data Tree。下面只是核心片断。如果对整个例子感兴趣,可以去Rife的网站查看Sample和Tutorial。
这是一段Tree Template。

${v level/}
${b level}

    ${v nodes/}

${/b}
${b node}
  • ${v title/}${v level/}
    ${/b}

     

    对应的Java代码操作Template Node,输出Data Tree。

    import com.uwyn.rife.engine.Element;
    import com.uwyn.rife.template.InternalValue;
    import com.uwyn.rife.template.Template;

    // obtain an instance of the template that will output the tree
    Template template = getHtmlTemplate("tutorial.recursion");

    // obtain a new internal value to construct a collection
    // of sibling child nodes in the local scope
    InternalValue nodes = template.createInternalValue();

    // set the child's title value
    template.setValue("title", encodeHtml(child.getTitle()));
    // and append it to the local internal value
    nodes.appendBlock("node");

    // set the level value which includes the sibling nodes in the
    // same level
    template.setBlock("level", "level");

    我们看到,template的操作代码贯穿整个程序的始终。getHtmlTemplate, createInternalValue, setValue, appendBlock, setBlock。非常类似于上面JDynamiTe的用法。
    JDynamiTe显示Data Tree的过程也是大致如此。XMLC也是如此。
    Rife同样具有JDynamiTe和XMLC的代码侵入性强的缺点。如果需要换别的Template技术,比如JSP, velocity,整个代码都要做废。

    Model Match
    Java代码负责提供符合显示层要求的Data Model,显示层框架本身把Data Model和Template进行匹配,产生结果。
    包括Wicket, Fastm, DOMPlus, 等。
    这类技术都具有良好的所见即所得特性。
    (1) Wicket
    http://wicket.sourceforge.net/
    Wicket类似于Tapstry,采用HTML自定义Attribute作为自定义标签。
    这段是Rife的一个典型的循环的例子。wicket:id一个标签,几乎可以满足任何需求。有兴趣的读者可以去Wicket网站查看完整的Sample。这里只有核心片断。毕竟,本文不是一部Wicket教程。




    Add your comment here:










    1/2/2004

    More comment text here.




     

    我们可以看到,Template非常干净。只有少数的自定义attribute, (and tag)。
    对应的Java代码如下。

    import wicket.markup.html.WebPage;
    import wicket.markup.html.basic.Label;
    import wicket.markup.html.basic.MultiLineLabel;
    import wicket.markup.html.form.Form;
    import wicket.markup.html.form.TextArea;
    import wicket.markup.html.list.ListItem;
    import wicket.markup.html.list.ListView;
    import wicket.model.PropertyModel;

    public final class GuestBook extends WebPage
    { /** Use a Vector, as it is synchronized. */
    private static final List commentList = new Vector();
    private final ListView commentListView;

    public GuestBook()
    {
    add(new CommentForm("commentForm"));
    add(commentListView = new ListView("comments", commentList)
    {
    public void populateItem(final ListItem listItem)
    {
    final Comment comment = (Comment)listItem.getModelObject();
    listItem.add(new Label("date", comment.date.toString()));
    listItem.add(new MultiLineLabel("text", comment.text));
    }
    });
    }
    }

    我们看到,Wicket的代码,相当干净利索,虽然写法上使用了匿名内部类。没有任何Template本身的操作。只是需要提供一个框架需要的View Model。ListView,MultiLineLabel,Label。
    Wicket的PropertyModel能够用来包装一个POJO。比如,一段HTML Template
    Stock of IBM: some value

    对应的Java代码是
    import wicket.model.PropertyModel;

    public PojoStockQuotePage()
    { StockQuote quote = new StockQuote("IBM");
    add(new Label("stockIBM", new PropertyModel(quote, "quote"));
    }

    我们看到,Wicket的代码结构非常像Swing。只需要对应HTML UI Tag提供一份View Model就可以。操作起来实在是方便。而且HTML Tag里面只需要添加 Wicket:id这样的自定义Attribute,就可以同时表达动态层次块和变量部分(其实Rife也是如此)。

    当需要换Template的时候,比如JSP, Velocity, Freemarker,Taglib等,Wicket提供的View Model还是可以使用的。
    Wicket的一个不足之处是,代码需要使用框架自定义的HTML View Model。这也可能是一个优点,能够帮助用户清楚地理解,代码和HTML Template之间的对应关系。

    从严格意义上来说,比起Taglib, Tapestry来说, 只有Wicket, Echo这样的框架才是真正意义上的组件框架。而且,Wicket相对于Echo的优势如此明显,这里就不多说了。不然就跑题了。总之,Wicket是一个非常值得关注的框架。
    (2) Fastm
    http://fastm.dev.java.net/servlets/ProjectDocumentList
    Fastm的思路相当于JDynamiTe, Wicket的思路组合。
    Fastm = JDynamiTe + Wicket
    Fastm采用自定义标签来标记动态Block,然后类似于JSTL, Velocity, Freemarker, Tapestry那样,接受一个POJO作为Model,并采用OGNL Style(同时也接受XPath Style)的方式对数据进行寻址。
    Fastm的公式很简单,Fastm Template + Model = Result。
    这个Model是POJO。可以是Java Bean, Map, DOM Node等任何Object。

    我们来看一段典型的Tree Data递归显示的例子。
    这段是HTML Template片断。

    class name:
    <!-- BEGIN DYNAMIC: @children -->


      <!-- BEGIN DYNAMIC: children -->

    • class name:
      <!-- BEGIN DYNAMIC: @children -->

        <!-- BEGIN DYNAMIC: children -->
        <!-- END DYNAMIC: children -->

      <!-- END DYNAMIC: @children -->

      <!-- END DYNAMIC: children -->

    <!-- END DYNAMIC: @children -->

     

    上面的@children需要特别说明一下,意思是检测当前Model是否具有children这个property,如果具有,那么向下展开,否则就跳过去。这样的话,如果没有children的话,多余的

      tag就不需要打印出来了。虽然空
        tag并不影响显示。

         

        对应的Java代码只需要提供一个POJO作为Tree Data。

        public Object makeModel(){
        Map a = new HashMap();
        a.put("name", "A");
        List aChildren = new ArrayList();
        a.put("children", aChildren);
        {
        Map a1 = new HashMap();
        a1.put("name", "A1");
        List a1Children = new ArrayList();
        a1.put("children", a1Children);
        {
        Map a11 = new HashMap();
        a11.put("name", "A1-1");
        a1Children.add(a11);

        Map a12 = new HashMap();
        a12.put("name", "A1-2");
        a1Children.add(a12);
        }
        aChildren.add(a1);
        }
        return a;
        }

        这段代码采用了Map作为Model, 也可以采用Java Bean, XML DOM Node等任何Object。所以,当然可以提供一个XML文件作为Model。

        看起来Fastm和JSP, Freemarker, Velocity,JSTL一样,对View Model没有什么特殊要求。POJO就可以。基本上就是如此。
        且慢,Fastm对Model还是有特殊要求的。类似于Wicket,Fastm也没有逻辑标签,Fastm也利用数据来表示条件、循环等逻辑分支。遇到Collection, Array等数据类型,就自动把动态块展开。如果不显示某一块,那么就提供一个空数据。
        这就是Fastm所需要的所有约定。看起来很简单,真正满足这个约定也不难。但是,某些特殊的情况下,为了满足这个约定,需要后台的用户代码做一些比JSP, Velocity, Freemarker要求的更多的Model组装工作。
        Fastm的另一个问题是,Model和View(Template)之间的映射关系不是很明了。虽然比JDynamiTe,Rife等容易明白多了,但是比Wicket还是差一些。因为Fastm没有自定义View Model类型,需要用户自己掌握Bean, Map层次和Template层次之间的正确对应。
        (3) DOMPlus
        http://fastm.dev.java.net/servlets/ProjectDocumentList
        DOMPlus是Fastm的思路在XML DOM领域的扩展。
        如果说,Fastm = JDynamiTe + Wicket;那么,DOMPlus = XMLC + Wicket
        DOMPlus是XMLC和Wicket思路的组合。
        如果说,Fastm的公式是,Fastm Template + Model = Result。
        那么,DOMPlus的公式是,DOM + Model = DOM or SAX
        这个Model是POJO。可以是Java Bean, Map, DOM Node等任何Object。
        一个很有趣的现象就是 DOM + DOM = DOM
        没错,就是如此。

        DOMPlus采用自定义DOM Attribute来标记动态Element, 动态Attribute, 动态Text。
        我们来看一个典型的Tree Data 递归显示的例子。
        对应的HTML DOM片断是。

         


      • class name:



         

        nodeTarget表示可能被重复多次的动态Element,attributesTarget表示需要替换的attribute。这里数据寻址方式采用的是XPath。@name表示DOM Node的name attribute。
        DOMPlus的自定义标签只有3个,nodeTarget, attributeTarget, textTarget。

        对应的XML Tree Data 是,

















        这两个DOM一匹配,就产生了结果XML,是一棵显示在HMTL List里面Tree。

        DOMPlus的Template更加干净,几乎接近于XMLC的Pure HTML DOM,等同于Wicket。
        而且DOMPlus并没有XMLC的空间问题。DOMPlus只保留一份DOM在内存中,每次请求来的时候,DOMPlus根据数据匹配产生SAX Event,直接写入Response。

        DOMPlus的匹配引擎很类似于XSL的功能,同样是用XML格式的模板文件处理XML数据。而且两者都同样是递归处理引擎。
        所不同的是DOMPlus Template能够在浏览器中正确显示,而且表达结构的自定义属性非常简单,只有3个(Fastm有2个)。

        DOMPlus的问题和Fastm一样,数据层次和模板层次之间的关系,一定要非常清楚,而不是像JSP, Velocity, Freemarker那样把数据抓过来就可以用。
        另外的问题就是,处理的最小单位是XML Node。XML Node里面的text的部分替换就无能为力了。比如 和XMLC的解决方法一样,可以引入外面的文本解析器。用来处理XML Node鞭长莫及的地方,比如,JavaScript代码的内部的动态替换部分。
        Regular Expression,Velocity, Freemarker, Fastm, JDydanamiTe,等任何能够脱离Web环境的通用文本解析工具都可以。JSP, Taglib, Tapestry, Wicket等无法脱离Web环境而存在,肯定不行。
        Login
        <!--nd-->

        ------
        注:
        Fastm和DOMPlus是我的作品,轻量的Template 匹配引擎。这两项技术本身只是单项的Template显示技术,不是一个完整的web整体解决方案。

        特性总表

        (1) Host Language Consistency宿主语言一致性
        (2)Template Purity 模板纯净度
        (3)Template Tidiness 模板整洁度
        (4) Replacement Flexibility 替换灵活度
        (5)WYIWYG 所见即所得
        (6)Action Code Purity 用户代码纯净度
        (7) Infrastructure Code Purity 基架代码纯净度
        (8)动态Include
        (9)Recursive Display of Tree Data树型数据的递归显示
        (10) Space Efficiency空间效率
        (11) Mapping Explicitness 映射关系明显度
        (12) Display Logic Reusability 显示逻辑重用度

        限于空间,下面的分数表采用索引数字来代表特性。横向是特性,纵向是技术。
        下面的表格中没有写Freemarker,只写了Velocity,这两项技术比较类似。各项参数也大致接近。当然,各自的Fans都能够看到很深很细的使用细节,宏定义之类的。

        指标索引 1 2 3 4 5 6 7 8 9 10 11 12
        Scripted Template
        Velocity 2 0 0 10 0-5 10 10 10 0 10 10 0
        JSP 10 0 0 10 0 10 10 10 0 10 10 0
        Taglib 0 0 10 6 0-5 2 - 8 0 0 4 6 6 0
        Tapestry 0 0 10 6 7 4 0 0 4 10 4 0
        XSL 10 0 10 6 0 10 10 10 10 10 5 0
        Template Manipulation
        XMLC 5 10 10 6 10 0 10 10 10 0 7 4
        JDynamiTe 5 8 5 10 8 0 10 10 10 3 3 5
        Rife 5 3-7 5 10 0-7 0 10 10 10 3 3 5
        Model Match
        Wicket 5 9 8 6 9 2 0 0 4 10 8 4
        Fastm 5 7 5 10 8 6 10 10 10 10 3 8
        DOMPlus 5 9 8 6 10 6 10 10 10 6 3 8

        下面我们大致看一下Browser Side(Ajax)的情况。

        Browser Side
        同Server Side的技术格局恰好相反, Browser Side的HTML DOM Manipulation技术、HTML View Model技术比较多,比较流行。各种JavaScript UI控件,DOM绑定控件,这方面的库很多,而且很酷。这里不再列举了。

        Browser Side的Scripted Template技术就比较少见了。我知道的大概有下面几个。

        TrimPath的JST
        http://www.trimpath.com/project/wiki/JavaScriptTemplates
        语法举例

        Helma
        http://dev.helma.org/Wiki/JavaScript+Template+Engine/
        语法举例
        <!--f (session.user != null)-->
        Hello <!--session.user.name-->
        <!--lse-->

        SWATO
        http://swik.net/SWATO/Swato+JavaScript+Template
        语法举例
        #for (i in products) {
        # var p=products[i];


    1/1/2004

    Comment text goes here.


  • $<!--pric--> <!--quantit-->: <!--aler-->
    评论 共 1 条 请登录后发表评论
    1 楼 leixiaodmm 2013-07-05 15:36
    看看我的基于WEB 的IDE已经做成了开源项目 有兴趣可以参与开发
    http://blog.csdn.net/ok_leixiao/article/details/9213347

    发表评论

    您还没有登录,请您登录后再发表评论

    文章信息

    Global site tag (gtag.js) - Google Analytics