java 显示层,Web显示层技术评估

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

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

属性。

简单的寻址,

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

由于

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

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

XMLC

把一个

HTML

文件翻译成一个

Java

HTML DOM Class

比如,

Hello,

World

... ...

这些具有

id

HTML

元素,在

Java HTML DOM Class

都产生了对应的方法。

HTMLElement getElementPara1()

public void setTextPara1(String text)

HTMLTitleElement getElementTitle()

HTMLInputElement getElementNameInput();

比如,

NAME="myName"> 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

对于,

这类只需要替换某一部分的

Attribute

来说,处理起来就有点大而无当。这时候,

XMLC

引入了外部的

Regular Expression Matcher

等工具来处理这种情况。

另外有一个不常见的需求。动态替换

Java Script

代码的里面的某一部分。这时候,

XMLC

就完全无能为力了。或许也可以引入外来的

Text Parser Engine

,比如

Velocity, Freemarker, Fastm, JDynamicTe

等来做这件事情。

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

类似于

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

InternalValuenodes = 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

Wicket

类似于

Tapstry

,采用

HTML

自定义

Attribute

作为自定义标签。

这段是

Rife

的一个典型的循环的例子。

wicket:id

一个标签,几乎可以满足任何需求。有兴趣的读者可以去

Wicket

网站查看完整的

Sample

。这里只有核心片断。毕竟,本文不是一部

Wicket

教程。

Add your comment here:

This is a

comment

1/1/2004

"text">Comment text goes 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:

wicket:id="stockIBM">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

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:

value="{name}">

class name:

上面的

@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

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

的部分替换就无能为力了。比如

#}

以数据为中心的

Ajax

应用中(把数据取过来,而不是取一段

HTML

,或者一段

Script

),当页面布局结构比较复杂的情况下,也可以选择

Browser Side XSL

一个有趣的联想是

DOMPlus

的思路。

DOMPlus

不仅支持

DOM + DOM = SAX

,而且支持

DOM + DOM = DOM

这个特性特别适合于

Browser

Side

。假设存在

DOMPlus

Javascript

版本。

Javascript

Server Side

拿来

XML Data

,和

Browser

里面的一段

HTML

进行一下

Match

,显示就搞定了。不需要写任何代码。

Unobtrusive

Brower Side

方面,

Scripted Template

技术并不流行。

这个事实说明了,

Browser

Side

的显示技术更加归于常态,显示模型更加自然。

JavaScript

编程有个流行的概念,叫做

Unobtrusive

,就是我们常说的无侵入性。

JavaScript, HTML, CSS

清晰有效的分开。

行为的归行为,内容的归内容,风格的归风格。

凯撒的归凯撒,上帝的归上帝,人民的归人民。

各自照看好自己的领域,而不侵入他人的领域。

无侵入,

POJO

等概念,在

Server Side

方面(比如

Java

),也是甚嚣尘上,炒作的不亦乐乎。

但是在

Web

显示技术的方面,

Unobtrusive

无侵入特性,不能不说,

Browser Side

由于先天的

JavaScript

操作

DOM

的优势,已经走在了前面。

虽然

JavaScript

作为一门动态语言,开发效率自然超过强类型编译语言,但是代码维护、

IDE

提示、辅助重构方面的成本也不可低估。

所以,

Server Side

的显示技术,仍然是不可缺少的。在

Server Side

同样应用

Unobtrusive

原则,也仍然具有重要的意义。

前面提到的两个指标,

Template

Purity

模板纯净度

, Action

Code Purity

用户代码纯净度。

就属于

Unobtrusive

指标。

显示技术里面,代码逻辑表示动态部分,复杂部分;

Template

表达静态部分,简单部分。

所以,人们更加关注代码逻辑的容易管理的程度。

由于代码逻辑在

IDE

里面相对容易管理。人们更能够容忍

Java

或者

Java Script

代码里面出现具体的

Template Node

,而觉得

Template

里面的

Script

比较难以管理。

Scripted Template

基本上是

Obtrusive

的,对

Template

的侵入性最强。虽然

Template

操作没有侵入到

Java

或者

JavaScript

代码。

这叫做

1 -- Way

Obtrusive

Template Manipulation

大致能够做到对

Template

Unobtrusive

非侵入,虽然他们的

Template Node

操作侵入了

Java

或者

Java Script

代码。

这叫做

1-Way

Unobtrusive

Model Match

技术具有最好的

Unobtrusive

非侵入特性。

Java

或者

JavaScript

代码不侵入

Template

到里面,具体的

Template Node

操作也不侵入到

Java

或者

JavaScript

代码里面。

这叫做

2-Way

Unobtrusive

Fastm, DOMPlus

是天生的

Model Match,

具有

2-Way Unobtrusive

特性。

Wicket

也是天生的

Model Match

,大致能够做到

1.5 -Way Unobtrusive

如果严格限制不采用

Logic

Taglib, Tapstry Logic Tag

,那么

Taglib

Tapestry

也能够做到

1.5 – Way Unobtrusive.

显示逻辑

AOP

这个需求主要包括页面数据类型的统一格式化。

比如,所有类型为

Date

,名字以

Time

结尾的数据(

startTime, endTime

等),都显示到秒钟;

Day

结尾的时间字段

(registerDay, birthDay

)

,都显示到天。

Period, Quarter, Year

结尾的字段也都有不同的显示需求。

能够支持自定义显示逻辑

AOP

Interceptor

的技术并不是很多。

XSL

语法天生就是

AOP

语法,

Declaring

Pattern Match

,用法就是要求程序员编写

Interceptor

Fastm, DOMPlus

对这方面也支持的很好。同样是采用自定义

Interceptor

W3

DOM Level 2

规范定义了

DOM Traversal

DocumentTraversal, TreeWalker, NodeIterator,

NodeFilter

使用

Pull

模型(

SAX

Push

模型)处理

XML

的程序员,可以使用

NodeFilter

来过滤掉不需要显示的节点。

NodeFilter

毕竟只是一个

Filter

,只能对

Node

内容进行简单的开关选项处理,

YES, or No

,显示或者不显示。只是作为

DocumentTraversal

whatToShow

参数的一个补充。

AOP

能力很有限。

多语言支持的终极解决方案

多语言支持,也叫做国际化,本地化。

一般采用字典文件的做法。比如,

dict.en, dict.cn, dict.fr, dict.de, dict.jp

等。

在这类做法里面,

Template

里面通常都只有

Message Key

< message key=”name” />

有些更好的做法是这样,提供缺省文本信息。

用户名称

这样能够保持页面的一目了然。

除了字典文件的做法之外,另一种做法是直接把文字资源,存放到

Template

里面。

然后分多个目录。

En,

cn, fr, de, jp

等目录,下面全都是对应的

Template

文件。

这种方案叫做语言目录方案。

这种方案的缺点很明显,一个文件的改动,要扩散到所有的对应文件中。

这种方案的优点也很明显,文件内容一目了然,尤其是支持所见即所得的模板。另一个优点就是运行效率。字典文件方案运行的时候,需要进行大量的查字典,动态替换文本工作。而语言目录方案的模板里面大部分都是静态文本。

有没有一个两全其美的方案?答案是,有。

首先,我们采用自己的母语(比如,中文)作为主模板文件,都放在

cn

目录下。

然后,其中需要多语言的文本信息,都采用下面这种方式包装起来。

用户名称

long text about system help

这时候,

Template

仍然保持了所见即所得的特性。然后,我们根据这些

Key

,做其他语言的字典文件。

Dict.en, dict.jp,

dict.fr, etc.

然后我们用一个文本处理引擎,替换掉这些多语言信息。为每一种语言产生一个目录,下面都是对应的语言的

Template

文件。比如,

en, jp, fr,

Template

文件目录,里面都是对应的填充了内容的模板。打开一看,一目了然。

当然,这个处理过程中,并没有影响那些动态数据部分,而只是替换了静态文本部分。

每次只需要更改主要语言目录的文件,然后用引擎处理,变化自动分布到其他语言目录。

这种技术的关键在于,

Template

本身是否可再生资源?能否被多次处理?能否被统一处理?

有几种技术是具有这种可能性的。

Taglib

理论上可以被当作

XML

文件处理,具有理论上的可行性。

Fastm, DOMPlus

具有现实可操作性。

Fastm, DOMPlus

都可以自定义标签,处理动态部分的同时,也能够忽略其他动态部分。

总结与展望

本文分析了

Web

层显示技术的各类指标和特性。

本文的讨论目前还只是局限于一般的

B/S

结构。

Web Service, SOA

代表了

Web

未来发展的趋向。数据整合,流程整合,各类资源整合。

界面

UI

也不会限于

HTML

一种,

XUL, XAML, SVG, RSS

等也有各自的应用。

我们都知道

Web

中有一种“盗链”的现象。

一个网站,不是通过

Copy

,而是直接通过

Link

引入了其他网站的资源,比如

CSS

,图片资源等。这样可以节省自己的

Server

资源。

有些技术更狠,能够抓取别人的页面内容,剪贴拼凑之后显示在自己的网页上。

这种情况实际上是一种偷偷摸摸的不被允许的资源共享实践。

Web Service

把这种实践发展成了一种商业模式,资源共享模式。不仅可以共享数据和资源,而且可以共享内容和服务(比如

Portlet

)。

比如,

Web Service

Remote Portal

,就是一种内容提供模式、服务提供模式。网站流量不再依靠用户点击率来计算,而是依靠

Web Service

调用率。

我们来看看,能够共享的资源有哪些。

CSS,

图片,

JavaScript

等可以直接

Link

过来;数据、内容可以抓取过来。

其中以

CSS

的共享最为流行。

CSS +

图片

+

某些文字替换,组成了一个

Theme

(显示主体),或者

Skin

(表观)。很多人津津乐道,并孜孜不倦地谈论、应用、提供各种

Themes,

Skins

但是还有一个重要的资源共享没有得到充分的发展。就是

Template Layout

的共享。

目前,

Web Server

Template

资源,一般都存放在自己的文件系统中。

假设这样一种方式。

一个

Web Server

运行的时候,通过

Web Service

获取数据,通过

Link

引用

CSS

JS

,图片等,通过

XLink +

XPointer + XPath

获取一份

XML Node

or Fragment or Text

,作为

Template Layout

,自己的服务器上只需要一份

Display Logic

把这些东西组装起来,就可以把页面发布出来。甚至

Display Logic

也可以从

Web Service

获取(

Script

等,当然这里面涉及到安全问题),自己只负责统筹管理安排调用。

这种模型对于

Web

Service Client

来说,也是适用的。

这种模型的关键就在于,

Unobtrusive

。所有领域都是清楚地分开,

Domain Specific

,决不侵入到其他领域,也不允许其他领域的侵入。

以上是我对

Web

显示技术的总结和展望。

本文到这里结束。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值