`
jetway
  • 浏览: 471924 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

使用 Velocity 实现客户端和服务器端模板

阅读更多

Velocity 是一种通用的、开放源代码的模板解决方案,可以在报告生成/数据转换应用程序中独立使用,也可以在 MVC 模型框架中作为视图组件。本文中,Sing Li 介绍了 Velocity,并说明如何将其模板处理功能集成到客户端独立应用程序、服务器端 Web 应用程序或者 Web 服务中。

HTML 或者 XML 这样的标准表示或交换格式中,文本性数据的操作和转换是一种频繁而且通常非常单调的活动,每个开发人员都会遇到。模板引擎可以改善这个过程,它在模板中保留输出中的静态部分,而动态生成和安排变化的部分。Velocity 是一种高度实用的、开放源代码的模板引擎,可以方便地集成到其他客户端或服务器端应用程序中。

对于服务器端应用程序,如果与兼容 Servlet 2.3+ Web 层容器集成,Velocity JSP 技术提供了一种可行的替代方案,可以强制实施表示逻辑与应用程序业务逻辑的清晰划分。事实上,Velocity 支持的模板语言非常简单,形成的模板也十分清晰,Web 站点设计人员和样式开发人员可以学习和维护这些模板。

本文中将考察 Velocity 的简单模板语言、创建一些模板并将其用于独立的客户应用程序。然后我们将把这个模板引擎集成到 Struts MVC 框架中作为视图组件。

基本模板引擎操作

基本模板引擎操作非常简单。首先看一看清单 1 中的模板:


清单 1. 基本的 Velocity 模板

<html>

<head>

<title>A Template Based Page</title>

</head>

<body>

<p>This is a page generated by $generatedBy.</p>

<p>The customer's name is $customerName.</p>

</body>

</html>

 

这个模板是一个完整的 HTML 文件。您可以使用文本编辑器或者喜欢的图形化可视网页编辑器创建该文件。创建的简易性是基于模板的系统的主要好处和要求。

当模板引擎运行时,清单 1 中彩色显示的部分将被实际的数据替换。获取数据并与模板结合的过程称为 合并。看一看清单 2 中的脚本所表示的数据:


清单 2. 为模板合并设置数据值

#set ($generatedBy = "Velocity")

#set ($customerName = "John Doe")

 

现在,如果清单 1 中的模板与清单 2 中的数据合并,将得到清单 3 所示的结果:


清单 3. 合并到模板中的数据

<html>

<head>

<title>A Template Based Page</title>

</head>

<body>

<p>This is a page generated by Velocity.</p>

<p>The customer's name is John Doe.</p>

</body>

</html>

 

您可能发现,这种特性和字处理程序中的邮件合并功能类似。在字处理程序中,信函结构与来自邮件列表的名称和地址合并。和邮件合并一样,这种应用程序最适用于要合并的数据源非常大而且有变化的情况。

从这个单纯的意义上讲,Velocity 是一个模板引擎。Velocity 的输出格式仅受文本模板中所能放置的内容的限制。包括现在最流行的格式(HTMLXMLSQL,等等)。

使用 Velocity 模板语言创建模板

Velocity 模板是文本文件(HTMLXML 等等),其中包括:

  • 照原样合并的静态部分
  • 将被要合并的数据替代的占位符
  • 脚本语言中的指示符和指令

Velocity 模板使用的脚本语言称为 Velocity 模板语言(VTL)。和其他脚本语言相比,VTL 语法相对而言不是很丰富。任何具有编程背景的人都可以非常快地学会 VTL

占位符与引用

VTL 中的引用是一个命名元素,如 $customerName 。引用可以在 Velocity 模板中作为占位符。在模板合并过程中,这些占位符将被替换成相应的文本值,从而形成最终的输出。比如,在 清单 1 中,我们可以看到使用了两个 VTL 引用( $generatedBy $customerName )已生成最终输出结果。

变量在 VTL 中是一种引用类型。您可以使用 #set() 指示符为变量赋值。清单 4 给出了一些例子:


清单 4. 变量类型的 VTL 引用

#set( $this = "Velocity")

#set( $numericBase = 999 )

#set( $booleanCondition = true )

This page is generated using $this.

There are ($numericBase + 1) pages in total.

 

变量名必须从一个字母开始,因此 Velocity 很容易把变量名与模板中的货币符号分开(比如, $100 不可能是一个变量名)。合并操作中所有的变量都被转化成字符串,可能造成一些有趣的现象。看一看清单 4 中用红色显示的文本。合并后的输出如清单 5 所示:


清单 5. 合并后的模板中带有数字值的变量

This page is generated using Velocity.

There are (999 + 1) pages in total.

 

因为 $numericBase 在合并操作中被转化成了字符串,因此不会执行算术操作。因为 VTL 专门用于模板操作而非通用的计算语言,所以只需要支持整数算术运算(尽管可以使用插件工具进行扩展)。下面的脚本说明了如何利用这种数学运算能力:

#set( $newSum = $numericBase + 1)

There are $newSum pages in total.

 

该模板合并后相应的输出为:

There are 1000 pages in total.

 

到目前我们处理的还只有标量。要创建包含多个元素的 ArrayList 变量,可以使用如下的语法:

#set( $treeList = ["pine", "oak", "maple", "redwood"])

 

您可以使用 $treeList.get(1) 列表中的第二个元素。

赋值以后, $treeList 就是一个基于 ArrayList 的变量(就像是标准 JDK 集合类中那样)。您可以直接使用符号 $treeList.get(n) 访问它的每个元素,其中的 n 是以 0 为基的 ArrayList 索引。比如,像 清单 6 种红色显示的一行所表明的那样, $treeList.get(1) 用于选择 ArrayList 中第二项,即 oak。这种调用 ArrayList 类方法的语法也可用于调用其他变量对象的方法(更多信息请参阅侧栏中的 属性和方法参考)。

 

关于占位符替换的一点说明:Velocity 把任何不能识别的引用作为普通文本打印

,如清单 6 中下面突出显示的两行(蓝色和红色)所示:


清单 6. 占位符置换

The second item in the list is $treeList.get(1).

$notDeclared is an undeclared variable.

But $!notDeclared is invisible when not declared.

 

VTL 支持一种静态引用符号,以避免呈现不存在的或者 空的 引用。如果使用安静引用符号,比如 $!notDeclared ,那么 Velocity 将什么也不输出,而不是输出完整的引用名。注意变量名前面的“!”表示这是静态引用符号。当合并清单 6 中的模板时,两个引用都没有分配任何值,但是蓝色显示的引用将原样显示,而绿色的一个则看不到:

The second item in the list is oak.

$notDeclared is an undeclared variable.

But is invisible when not declared.

 

选择性呈现和循环

可以使用指示符 #if... #then... #else.... 有条件地呈现模板中特定的部分。清单 7 给出了一个例子:


清单 7. 使用 #if#then #else 有选择地呈现

#if $customer.GoldMember

 Thank you Mr. $customer.LastName, for flying with us.

 Your loyal patronage is greatly appreciated. 

 This flight earns you an additional 5000 miles.

#else

 Thank you for flying with us.

 Please consider joining our frequent flyer program.

#endif

 

在清单 7 的模板中,使用 $customer 对象的 boolean 属性 GoldMember 确定在最终输出中出现哪些信息。对于金牌顾客,最终输出中将呈现蓝色显示的消息;对于其他顾客,则在最终输出中呈现绿色显示的消息。

模板中经常要使用循环格式化表格或者列表形式的信息。显示的数据通常保存在一个 ArrayList 引用中。在 Velocity 中唯一用于处理重复循环的指示符是 #foreach 指示符。清单 8 中的模板通过 $treeList ArrayList 变量演示了 #foreach 指示符的用法。当然,也可以使用任何其他可用的集合类型的对象引用,或者返回一个集合的对象属性/方法引用。


清单 8. 使用 #foreach 循环

<table>

<tr><td>Tree Name</td></tr>

#foreach $name in $treeList

<tr><td>

     $name is a big tree!

</td></tr>

#end

</table>

 

$treeList 中包含树名的列表,清单 8 中的模板合并后的输出如清单 9 所示:


清单 9. #foreach 循环中合并后的输出

<table>

<tr><td>Tree Name</td></tr>

<tr><td>

     pine is a big tree!

</td></tr>

<tr><td>

     oak is a big tree!

</td></tr>

<tr><td>

     maple is a big tree!

</td></tr>

<tr><td>

     redwood is a big tree!

</td></tr>

</table>

 

如果从 HTML 浏览器中查看,清单 9 当然就是一个包含树名的表。

注意在 #foreach 循环体内有一个内置的计数器,可以在 #foreach 指示符循环体内通过 $velocityCounter 引用访问它。默认情况下,这个计数器从 1 开始,每执行一次循环递增一次。

Velocity 中的宏

Velocity 的一个主要特性是能够很容易地定义宏,称为 Velocimacros。宏使您能够很容易地封装和重用模板脚本。默认情况下,宏保存在 VM_global_library.vm 文件中。比如,考虑清单 10 中名为 #showTree() Velocimacro


清单 10. 定义 Velocimacro

#macro (showTree)

    #if ($treeList )

        #foreach ($e in $treeList )

            $e

        #end

    #end

#end

 

您可以调用 #showTree() Velocimacro 并使用它打印 $treeList ArrayList ―― 如果这个列表已经定义的话。调用的语法很简单,即 #showTree()

参数化宏也是可能的。比如,我们可以修改 #showTree() 宏使其用于任何列表,如清单 11 所示:


清单 11. 带参数的 Velocimacro

#macro (showList $val)

    #if ($val )

        #foreach ($e in $val )

            $e

        #end

    #end

#end

 

要使用清单 11 中的宏调用 $treeList ,我们可以使用 #showList($treeList) 。这两种情况的输出都一样,如清单 12 所示:


清单 12. Velocimacro 的合并输出

     pine

     oak

     maple

     redwood

 

其他有趣的 VTL 细节

单行注释或者行尾注释从 ## 开始,多行注释则放在 #* font-size: 7pt; colo

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics