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
的
<foreach> <if><if-not>
<let><set>
等逻辑标签。尤其是这个
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
。
<!--
#if ….
-->
由于
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 相当于
<%
request.getRequestDispatcher(…).include(request, response);
%>
这才是动态
Include
技术。
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
。