velocity模板引擎帮助

Velocity用户手册是帮助页面设计者和内容提供者认识Velocity和其简单而功能强大的脚本语言――Velocity模板语言(VTL)。在手册上的许多例子,都是用Velocity插入动态的内容到网页上,但是所有的VLT例子都能应用到其他的页面和模板中。
感谢使用 Velocity!
Velocity是什么?
Velocity是一个基于java的模板引擎(template engine)。它允许任何人仅仅简单的使用模板语言(template language)来引用由java代码定义的对象。
当Velocity应用于web开发时,界面设计人员可以和java程序开发人员同步开发一个遵循MVC架构的web站点,也就是说,页面设计人员可以只关注页面的显示效果,而由java程序开发人员关注业务逻辑编码。Velocity将java代码从web页面中分离出来,这样为web站点的长期维护提供了便利,同时也为我们在JSP和PHP之外又提供了一种可选的方案。
Velocity的能力远不止web站点开发这个领域,例如,它可以从模板(template)产生SQL和PostScript、XML,它也可以被当作一个独立工具来产生源代码和报告,或者作为其他系统的集成组件使用。Velocity也可以为Turbine web开发架构提供模板服务(template service)。Velocity+Turbine提供一个模板服务的方式允许一个web应用以一个真正的MVC模型进行开发。

Velocity能为我们作什么?
Mud 商店例子
假设你是一家专门出售Mud的在线商店的页面设计人员,让我们暂且称它为“在线MUD商店”。你们的业务很旺,客户下了各种类型和数量的mud订单。他们都是通过输入用户名和密码后才登陆到你的网站,登陆后就允许他们查看订单并购买更多的mud。现在,一种非常流行的mud正在打折销售。另外有一些客户规律性的购买另外一种也在打折但是不是很流行的Bright Red Mud,由于购买的人并不多所以它被安置在页面的边缘。所有用户的信息都是被跟踪并存放于数据库中的,所以某天有一个问题可能会冒出来:为什么不使用velocity来使用户更好的浏览他们感兴趣的商品呢?
Velocity使得web页面的客户化工作非常容易。作为一个web site的设计人员,你希望每个用户登陆时都拥有自己的页面。
你会见了一些公司内的软件工程师,你发现他们每个人都同意客户应该拥有具有个性化的信息。那让我们把软件工程师应该作的事情发在一边,看一看你应该作些什么吧。
你可能在页面内嵌套如下的VTL声明:

Hello $customer.Name! #foreach( $mud in $mudsOnSpecial ) #if ( $customer.hasPurchased($mud) ) #end #end
$flogger.getPromo( $mud )
foreach 的详细用法不久就会进行深入描述。重要的是,这短小的脚本能在你的网站上出现。当一个对Bright Red Mud 很感兴趣的顾客登陆的时候,同时Bright Red Mud在热卖中,这时顾客就能显著地看到。假如一个玩Terracotta Mud很久的顾客登陆,Terracotta Mud 的售卖信息就会出现在前面中间。Velocity的适用性是很巨大的,限制的只是你的创造性。 VTL Reference 含有许多其他Velocity元素,这些元素能够共同帮助你,使你的网站更加好。当你越来越熟悉那些原理,你开始释放Velocity的能力。 Velocity模板语言(VTL):说明 VTL意味着提供最简单、最容易并且最整洁的方式合并页面动态内容。VTL使用references来在web site内嵌套动态内容,一个变量就是一种类型的reference。变量是某种类型的refreence,它可以指向java代码中的定义,或者从当前页面内定义的VTL statement得到值。下面是一个VTL statement的例子,它可以被嵌套到HTML代码中: #set( $a = "Velocity" ) 和所有的VTL statement一样,这个statement以#字符开始并且包含一个directive:set。当一个在线用户请求你的页面时,Velocity 模板引擎将查询整个页面以便发现所有#字符,然后确定哪些是VTL statement,哪些不需要VTL作任何事情。 #字符后紧跟一个directive:set时,这个set directive使用一个表达式(使用括号封闭)――一个方程式分配一个值给变量。变量被列在左边,而它的值被列在右边,最后他们之间使用=号分割。 在上面的例子中,变量是$a,而它的值是Velocity。和其他的references一样以$字符开始,而值总是以双引号封闭。Velocity中仅有String可以被赋值给变量。 使用$字符开始的references用于得到什么;使用#字符开始的directives用于作些什么。在上面的例子中,#set是分配一个值给变量。变量$a 在模板中输出 "Velocity"。

Hello Velocity World!
一旦某个变量被分配了一个值,那么你就可以在HTML文件的任何地方引用它。在下面的例子中,一个值被分配给$foo变量,并在其后被引用。

#set( $foo = "Velocity" ) Hello $foo World! 上面的实现结果是在页面上打印“Hello Velocity World!” 为了使包含VTL directives的statement更具有可读性,我们鼓励你在新行开始每个VTL statement,尽管你不是必须这么作。Set的用法将在后面详细描述。

注释
注释是那些描述文本不出现在模板引擎输出里面。注释一个主要用处是提醒自己和解释出现在VTL中的声明,或是其他用途。下面是一个在VLT中的注释例子。

This is a single line comment.

单行注释以##开始,结束在这行的结尾。如果你要写几行注释,这没有必要写几个单行注释。
多行注释,以#开始#结束,可以解决这个问题。
This is text that is outside the multi-line comment.
Online visitors can see it.

#*
Thus begins a multi-line comment. Online visitors won’t
see this text because the Velocity Templating Engine will
ignore it.
*#

Here is text outside the multi-line comment; it is visible.
这里有几个例子关于单行和多行注释如何工作。
This text is visible. ## This text is not.
This text is visible.
This text is visible. #* This text, as part of a multi-line comment,
is not visible. This text is not visible; it is also part of the
multi-line comment. This text still not visible. *# This text is outside
the comment, so it is visible.

This text is not visible.

这里有第三种类型的注释,VLT注释块,可能用于存放文档的作者名称和版本信息。
#**
This is a VTL comment block and
may be used to store such information
as the document author and versioning
information:
@author
@version 5
*#

References

在VTL中有三种类型的references:变量(variables)、属性(properties)、方法(methods)。作为一个使用VTL的页面设计者,你和你的工程师必须就references的名称达成共识,以便你可以在你的template中使用它们。
所有的 reference被作为一个String对象处理。如果有一个对象$foo是一个Integer对象,那么Velocity将调用它的toString()方法将这个对象转型为String类型。

变量
非正式变量是由“$”开头,接着是VTL标识符。VLT标识符必须以字母(a…z,A…Z)开头。剩下的部分限于以下几种:
 字母(a…z,A…Z)
 数字(0…9)
 连字符(“-”)
 下划线(“_”)
这里是几个在VTL中有效的变量reference。
$foo
$mudSlinger
$mud-slinger
$mud_slinger
m u d S l i n g e r 1 当 V L T 定 义 一 个 变 量 , 例 如 mudSlinger1 当VLT定义一个变量,例如 mudSlinger1VLTfoo,变量能或者通过模板中的set 方法,或者通过Java 代码获得值。
例如,Java 变量 $foo 的值是 bar ,在这个模板被请求时,在网页上 bar 会替代所有 $foo 。选择地,假如包括了下面的声明:
#set( $foo = “bar” )
按照这样的设置,输出就会跟之前的一样。

属性
第二种有趣的VTL reference就是属性,而且属性有一种与众不同的格式。非正式变量是由“$”开头,接着是VTL标识符,再接着就是字符(“.”)和其他的VLT标识符。这里是一些在VLT中有效属性的定义:
$customer.Address
p u r c h a s e . T o t a l 在 第 一 个 例 子 中 purchase.Total 在第一个例子中 purchase.Totalcustomer.Address有两种含义。它可以表示:查找hashtable对象customer中以Address为关键字的值;也可以表示调用customer对象的getAddress()方法。当你的页面被请求时,Velocity将确定以上两种方式选用那种,然后返回适当的值。

方法
一个方法就是被定义在java中的一段代码,并且它有完成某些有用工作的能力,例如一个执行计算和判断条件是否成立、满足等。方法是一个由$开始并跟随VTL标识符组成的References,一般还包括一个VTL方法体。一个VTL方法体包括一个VLT标识接着一个左括号(“(”),接着是参数列表,再接着是右括号(“)”)。这里是一些在VTL中有效的方法定义:
$customer.getAddress()
$purchase.getTotal()
$page.setTitle( “My Home Page” )
p e r s o n . s e t A t t r i b u t e s ( [ " S t r a n g e " , " W e i r d " , " E x c i t e d " ] ) 前 两 个 例 子 person.setAttributes( ["Strange", "Weird", "Excited"] ) 前两个例子 person.setAttributes(["Strange","Weird","Excited"])customer.getAddress()和 p u r c h a s e . g e t T o t a l ( ) 看 起 来 挺 想 上 面 的 属 性 purchase.getTotal()看起来挺想上面的属性 purchase.getTotal()customer.Address 和 p u r c h a s e . T o t a l 。 如 果 你 觉 得 他 们 之 间 有 某 种 联 系 的 话 , 那 你 是 正 确 的 。 V T L 属 性 可 以 作 为 V T L 方 法 的 缩 写 。 purchase.Total。如果你觉得他们之间有某种联系的话,那你是正确的。 VTL属性可以作为VTL方法的缩写。 purchase.TotalVTLVTLcustomer.Address属性和使用$customer.getAddress()方法具有相同的效果。如果可能的话使用属性的方式是比较合理的。属性和方法的不同点在于你能够给一个方法指定一个参数列表。
非正式定义能够用下面的方法:
$sun.getPlanets()
$annelid.getDirt()
$album.getPhoto()
我们期待那些方法返回属于太阳系的行星的名称,喂养我们的蚯蚓,或者从相册里面取出一张照片。只有长符号为下面的方法服务。
$sun.getPlanet( [“Earth”, “Mars”, “Neptune”] )

Can’t pass a parameter list with $sun.Planets

$sisyphus.pushRock()

Velocity assumes I mean $sisyphus.getRock()

$book.setTitle( “Homage to Catalonia” )

Can’t pass a parameter list

正式reference标记
非正式references用于上述的例子中。但是同样有正式的references,如下面所示:
${mudSlinger}
${customer.Address}
p u r c h a s e . g e t T o t a l ( ) 在 几 乎 所 有 场 合 你 都 可 以 使 用 非 正 式 r e f e r e n c e s , 但 是 在 某 些 场 合 , 只 能 使 用 正 式 r e f e r e n c e 才 能 正 确 处 理 。 设 想 你 创 建 一 个 句 子 : {purchase.getTotal()} 在几乎所有场合你都可以使用非正式references,但是在某些场合,只能使用正式reference 才能正确处理。 设想你创建一个句子: purchase.getTotal()使references使referencevice 作为句子的名词 。目标是为了使某些人选择不同的词,产生下面两种结果之一:“Jack is a pyromaniac.” 或者 “Jack is a kleptomaniac.”。使用非正式定义不太适合用于这种情况。看一下下面的例子:
Jack is a v i c e m a n i a c . 本 来 变 量 是 vicemaniac. 本来变量是 vicemaniac.vice现在却变成了$vicemaniac,这样Veloctiy就不知道您到底要什么了。所以,应该使用正是格式书写
Jack is a v i c e m a n i a c . 现 在 V e l o c i t y 就 知 道 r e f e r e n c e 是 {vice}maniac. 现在Velocity就知道reference 是 vicemaniac.Velocityreferencevice,而不是$vicemaniac。正式定义经常用于模板中refernces与文本连接在一起的情况。

Quiet reference notation
当Velocity遇到没有定义的reference,通常它会直接输出reference。例如:假如下面的reference出现在一个VTL模板中:

当 form 最初加载的时候,变量 e m a i l 没 有 值 , 但 你 想 出 现 一 个 空 白 的 文 本 框 设 定 值 为 “ email 没有值,但你想出现一个空白的文本框设定值为“ emailemail”。
使用quiet reference notation可以使Velocity正常显示,你需要用 ! e m a i l , 代 替 !email ,代替 !emailemail。所以上面的例子,会改成下面:

这样文本框的初始值就不会是email而是空值了。
正式和quiet格式的reference notation也可一同使用,像下面这样:

Getting literal
Velocity使用特殊字符KaTeX parse error: Expected 'EOF', got '#' at position 2: 和#̲来帮助它工作,所以如果要在te…字符。
货币字符
这是没有问题的:“I bought a 4 lb. sack of potatoes at the farmer’s market for only $2.50!”,VTL中使用$2.5这样的货币标识是没有问题得的,VTL不会将它错认为是一个reference,因为VTL中的reference总是以一个大写或者小写的字母开始。

Escaping valid VTL reference
某些情况使用Velocity可能会觉得很烦恼。逃避特殊符是处理出现在你的模板中VTL特殊符有效方法,就是使用反斜杠(“\”)。
#set( $email = “foo” )
$email
假如Velocity在你的模板中遇到 $email ,它会搜索上下文,得到相应的值。这里的输出是 foo ,因为 $email 被定义了。假如 $email 没有被定义,输出会是 $email 。
设想 $email 被定义了(例如,它的值是 foo ),而且你想输出 $email 。这里有几种方法能达到目的,但是最简单的是使用逃避符。

The following line defines $email in this template:

#set( $email = “foo” )
$email
$email
\$email
\$email
将显示为:
foo
$email
\foo
$email
注意到 “\” 屏蔽了左边的 “$”。屏蔽左边规则,使得 \$email 显示为 \$email 。那些例子与 $email没有定义相比较。
$email
$email
\$email
\$email
将显示为:
$email
$email
\$email
\$email
注意Velocity处理 定义了的references 与没有定义的不一样。这里 set $foo 的值为 gibbous。
#set( $foo = “gibbous” )
$moon = f o o 输 出 会 是 : foo 输出会是: foomoon = gibbous ,$moon 按照字面上输出因为它没有定义,gibbous 替代 $foo 输出。
避开VTL的 directives 还有其他方法,在 Directives 那章节会更详细描述。

Case substitution
现在你已经对reference比较熟悉了,你可以将他们高效的应用于你的template了。Velocity利用了很多java规范以方便了设计人员的使用。例如:
$foo

$foo.getBar()

is the same as

$foo.Bar

$data.getUser(“jon”)

is the same as

$data.User(“jon”)

$data.getRequest().getServerName()

is the same as

$data.Request.ServerName

is the same as

${data.Request.ServerName}
那些例子说明了同样的references 用法。Velocity 利用Java的 instrospection 和 bean features解决 reference 的名称对于对象和对象方法的问题。它可以出入你的模板中和求出 references 的值。
Velocity 是模仿Sun微系统中的Bean规范定义的,因而它是很灵活的。然而,它的开发者已经很努力地捕捉和纠正可能出现的错误。当方法 getFoo() 在模板中 被 $bar.foo调用时,Velocity首先尝试 $getfoo。如果失败,它会继续尝试 $getFoo。同样地,当模板查询 $bar.Foo,Velocity会先尝试 $getFoo(),然后再尝试 g e t f o o ( ) 。 但 是 , 注 意 V T L 中 不 会 将 r e f e r e n c e 解 释 为 对 象 的 实 例 变 量 。 例 如 : getfoo()。 但是,注意VTL中不会将reference解释为对象的实例变量。例如: getfoo()VTLreferencefoo.Name将被解释为Foo对象的getName()方法,而不是Foo对象的Name实例变量。

Directives
Reference允许设计者使用动态的内容,而directive使得你可以应用java代码来控制你的显示逻辑,从而达到你所期望的显示效果。
#set
#set标志是用于对一个reference赋值。值会赋给一个变量或者一个属性,而且赋值会在括号里出现:
#set( $primate = “monkey” )
#set( $customer.Behavior = $primate )
左边(LHS) 一定是一个变量或者一个属性。右边(RHS)可以是下面中的一个类型:
 变量
 字符串
 属性
 方法
 数字
 数组
这些例子显示上述的每一种类型:
#set( $monkey = $bill ) ## variable reference
#set( $monkey.Friend = “monica” ) ## string literal
#set( $monkey.Blame = $whitehouse.Leak ) ## property reference
#set( $monkey.Plan = s p i n d o c t o r . w e a v e ( spindoctor.weave( spindoctor.weave(web) ) ## method reference
#set( $monkey.Number = 123 ) ##number literal
#set( $monkey.Say = [“Not”, KaTeX parse error: Expected 'EOF', got '#' at position 16: my, "fault"] ) #̲# ArrayList 注意:…monkey.Say.get(0)。
RHS也可以是一个简单的算术表达式:
#set( $value = $foo + 1 )
#set( $value = $bar - 1 )
#set( $value = $foo * $bar )
#set( $value = $foo / $bar )
如果你的RHS是一个null,VTL的处理将比较特殊:它将指向一个已经存在的reference,这对初学者来讲可能是比较费解的。例如:
#set( $result = $query.criteria(“name”) )
The result of the first query is $result

#set( $result = $query.criteria(“address”) )
The result of the second query is r e s u l t 如 果 result 如果 resultquery.criteria(“name”)返回一个“bill”,而$query.criteria(“address”)返回的是null,则显示的结果如下:
The result of the first query is bill

The result of the second query is bill
这容易使新手糊涂:创建一个#foreach循环,企图想通过一个属性或者一个方法 #set一个reference,然后马上就用 #if 测试。例如:
#set( $criteria = [“name”, “address”] )

#foreach( $criterion in $criteria )

#set( $result = $query.criteria($criterion) )

#if( $result )
    Query was successful
#end

#end
在上面的例子中,程序将不能智能的根据 r e s u l t 的 值 决 定 查 询 是 否 成 功 。 在 result的值决定查询是否成功。在 resultresult被#set后(added to the context),它不能被设置回null(removed from the context)。打印的结果将显示两次查询结果都成功了,但是实际上有一个查询是失败的。
为了解决以上问题我们可以通过预先定义的方式:
#set( $criteria = [“name”, “address”] )

#foreach( $criterion in $criteria )

#set( $result = false )
#set( $result = $query.criteria($criterion) )

#if( $result )
    Query was successful
#end

#end
不像其他Velocity指示符号,#set 没有一个#end 结束。

String Literals
当你使用#set directive,String literal封闭在一对双引号内。象下面:
#set( $directoryRoot = “www” )
#set( $templateName = “index.vm” )
#set( t e m p l a t e = " template = " template="directoryRoot/$templateName" )
$template
上面这段代码的输出结果为:
www/index.vm
但是,当string literal被封装在单引号内时,它将不被解析:
#set( $foo = “bar” )
$foo
#set( b l a r g h = ′ blargh = ' blargh=foo’ )
$blargh
输出为:
bar $foo
上面这个特性可以通过修改velocity.properties文件的stringliterals.interpolate = false的值来改变上面的特性是否有效。

条件语句
If / ElseIf / Else
当一个web页面被生成时使用Velocity的#if directrive,如果条件成立的话可以在页面内嵌入文字。例如:
#if( KaTeX parse error: Expected 'EOF', got '#' at position 37: …city!</strong> #̲end 上例中的条件语句将在以…foo是一个boolean型的变量,且它的值为true;(ii)$foo变量的值不为null。这里需要注意一点:Velocity context仅仅能够包含对象,所以当我们说“boolean”时实际上代表的时一个Boolean对象。即便某个方法返回的是一个boolean值,Velocity也会利用内省机制将它转换为一个Boolean的相同值。
如果条件成立,那么#if和#end之间的内容将被显示。在这个例子中,如果 $foo的值为true,输出为“Velocity!”。相反地,如果 $foo 是一个 null值,或者是一个 false 值,表达式值为 false,没有输出。
#elseif和#else元素可以同#if一同使用。注意:Velocity 模板引擎遇到一个为true值的表达式就会停止。在下面的例子,假设 f o o = 15 , foo=15, foo=15,bar=6:
#if( $foo < 10 )
Go North
#elseif( $foo == 10 )
Go East
#elseif( KaTeX parse error: Expected 'EOF', got '#' at position 42: …South</strong> #̲else <stron…foo比10大,所以在开始的两个比较中都失败。接着 $bar跟6比较是真的所以输出为 GO South。
注意这里的Velocity的数字是作为Integer来比较的――其他类型的对象将使得条件为false,但是与java不同它使用“==”来比较两个值,而且velocity要求等号两边的值类型相同。

关系、逻辑运算符
Velocity中使用等号操作符判断两个变量的关系。这里有个简单例子关于等于号的使用:
#set (KaTeX parse error: Expected 'EOF', got '#' at position 32: …nucleic acid") #̲set (bar = “ribonucleic acid”)

#if ($foo == $bar)
In this case it’s clear they aren’t equivalent. So…
#else
They are not equivalent and this will be the output.
#end
Velocity有AND、OR和NOT逻辑运算符。想得到更多信息,请看VTL Reference Guide。下面的例子是说明AND、OR和NOT逻辑运算符的用法:

logical AND

#if( $foo && KaTeX parse error: Expected 'EOF', got '#' at position 42: … that</strong> #̲end 只有当foo 和 KaTeX parse error: Expected 'EOF', got '#' at position 12: bar 都为true,#̲if 才会得到true值。如果foo=false ,表达式的值为 false,$bar 就不会求值。如果 $foo的值为 true ,Velocity模板引擎会检查 b a r 的 值 , 如 果 bar的值,如果 barbar=true,整个表达式的值为true,输出为“This AND that”。如果$bar=false,整个表达式的值为false,没有输出。
逻辑OR 的工作方式一样,除了只要有一个值为true ,整个表达式的值就为true。考虑一下下面的例子。

logical OR

#if( $foo || KaTeX parse error: Expected 'EOF', got '#' at position 41: … That</strong> #̲end 如果foo=true,Velocity模板引擎就没有必要查找 $bar,无论 b a r 是 t r u e 还 是 f a l s e , 表 达 式 的 值 为 t r u e , 输 出 为 “ T h i s O R T h a t ” 。 如 果 bar 是true 还是 false ,表达式的值为 true ,输出为“This OR That”。如果 bartruefalsetrueThisORThatfoo=flase,$bar的值就一定要检查,在这个例子中,如果 b a r 同 样 是 f a l s e , 表 达 式 的 值 为 f a l s e , 没 有 输 出 。 从 另 外 一 个 角 度 看 , 如 果 bar 同样是false,表达式的值为 false ,没有输出。从另外一个角度看,如果 barfalsefalsebar 的值为true ,整个表达式的值为 true ,输出为 “This OR That”。
关于逻辑NOT ,只有一个疑问:
##logical NOT

#if( !$foo )
NOT that
#end
如果 f o o = t r u e , ! foo=true, ! foo=true,!foo 的值为 false,没有输出。如果 f o o = f a l s e , ! foo=false,! foo=false!foo的值为true,输出为“NOT that”。注意不要跟 quiet reference $!foo 混为一谈,那是完全不一样的。

循环
Foreach循环
#foreach 用于循环。例子:

  • #foreach( $product in $allProducts )
  • $product
  • #end
每次循环$allProducts中的一个值都会赋给$product变量。 $allProducts可以是一个Vector、Hashtable或者Array。分配给$product的值是一个java对象,并且可以通过变量被引用。例如:如果$product是一个java的Product类,并且这个产品的名字可以通过调用他的getName()方法得到。 现在我们假设$allProducts是一个Hashtable,如果你希望得到它的key应该像下面这样:
  • #foreach( $key in $allProducts.keySet() )
  • Key: $key -> Value: $allProducts.get($key)
  • #end
Velocity还特别提供了得到循环次数的方法,以便你可以像下面这样作: #foreach( $customer in $customerList ) #end
$velocityCount$customer.Name
$velocityCount变量的名字是Velocity默认的名字,你也可以通过修改velocity.properties文件来改变它。默认情况下,计数从“1”开始,但是你可以在velocity.properties设置它是从“1”还是从“0”开始。下面就是文件中的配置: # Default name of the loop counter # variable reference. directive.foreach.counter.name = velocityCount

Default starting value of the loop

counter variable reference.

directive.foreach.counter.initial.value = 1

include
#include script element允许模板设计者引入本地文件。被引入文件的内容将不会通过模板引擎被render。为了安全的原因,被引入的本地文件只能在TEMPLATE_ROOT目录下。
#include( “one.txt” )
#include 引用的文件用引号括起来。
如果您需要引入多个文件,可以用逗号分隔就行:
#include( “one.gif”,“two.txt”,“three.htm” )
在括号内可以是文件名,但是更多的时候是使用变量的。这用于根据页面提交的需求而输出。这里有一个例子同时有文件名和变量。
#include( “greetings.txt”, $seasonalstock )

parse
#parse script element允许模板设计者一个包含VTL的本地文件。Velocity将解析其中的VTL并render模板。
#parse( “me.vm” )
就像#include,#parse接受一个变量而不是一个模板。任何由#parse指向的模板都必须包含在TEMPLATE_ROOT目录下。与#include不同的是,#parse只能指定单个对象。
你可以通过修改velocity.properties文件的parse_direcive.maxdepth的值来控制一个template可以包含的最多#parse的个数――默认值是10。#parse是可以递归调用的,例如:如果dofoo.vm包含如下行:
Count down.
#set( $count = 8 )
#parse( “parsefoo.vm” )
All done with dofoo.vm!
那么在parsefoo.vm模板中,你可以包含如下VTL:
$count
#set( $count = $count - 1 )
#if( $count > 0 )
#parse( “parsefoo.vm” )
#else
All done with parsefoo.vm!
#end
在显示“Count down”后,Velocity通过parsefoo.vm,从8往下数。当计数到了0,它就会显示“All done with parsefoo.vm!”。在这时,Velocity 会返回到dofoo.vm ,输出信息:“All done with dofoo.vm!”。

停止
#stop script element允许模板设计者停止执行模板引擎并返回。把它应用于debug是很有帮助的。
#stop

Velocimacros
#macro script element允许模板设计者定义一段可重用的VTL template。Velocimacros广泛用于简单和复杂的行列。Velocimacros的出现是为了减少编码和极小化排版错误,对Velocimacros的概念提供一个介绍。
#macro( d )

#end 在上面的例子中Velocimacro被定义为d,然后你就可以在任何VTL directive中以如下方式调用它: #d() 当你的template被调用时,Velocity将用替换为#d()。 每个Velocimacro可以拥有任意数量的参数――甚至0个参数,虽然定义时可以随意设置参数数量,但是调用这个Velocimacro时必须指定正确的参数。下面是一个拥有两个参数的Velocimacro,一个参数是color另一个参数是array: #macro( tablerows $color $somelist ) #foreach( $something in $somelist ) $something #end #end Velocimacro在这个例子的定义,tablerows,有两个元素。第一个是替换 $color ,第二个是替换$somelist。 任何东西都可以通过Velocimacro加入到VTL模板中。tablerows Velocimacro 是一个foreach 标识。 这里有两个#end标识在#tablerows Velocimacro 定义里面。第一个是属于 #foreach,第二个是属于Velocimacro定义的。 #set( $greatlakes = ["Superior","Michigan","Huron","Erie","Ontario"] ) #set( $color = "blue" ) #tablerows( $color $greatlakes )
注意到$greatlakes 替代 $somelist。当#tablerows Velocimacro被调用时,就会产生下面的输出:
Superior
Michigan
Huron
Erie
Ontario
Velocimacros可以在Velocity模板内实现行内定义(inline),也就意味着同一个web site内的其他Velocity模板不可以获得Velocimacros的定义。定义一个可以被所有模板共享的Velocimacro显然是有很多好处的:它减少了在一大堆模板中重复定义的数量、节省了工作时间、减少了出错的几率、保证了单点修改。 上面定义的#tablerows( $color $list )Velocimacro被定义在一个Velocimacros模板库(在velocity.properties中定义)里,所以这个macro可以在任何规范的模板中被调用。它可以被多次应用并且可以应用于不同的目的。例如下面的调用: #set( $parts = ["volva","stipe","annulus","gills","pileus"] ) #set( $cellbgcol = "#CC00FF" ) #tablerows( $cellbgcol $parts )
当为mushroom.vm实现一个请求时,Velocity会在模板库中找到#tablerows Velocimacro(定义在velocity.properties文件),产生以下输出:
volva
stipe
annulus
gills
pileus

Velocimacro arguments
Velocimacro可以使用以下任何元素作为参数:
 Reference:任何以KaTeX parse error: Unexpected character: '' at position 14: 开头的reference ̲ String literal…foo….$bar]
 对象数组:[“a”,”b”,”c”]
 boolean值:true、false
当将一个reference作为参数传递给Velocimacro时,请注意reference作为参数时是以名字的形式传递的。这就意味着参数的值在每次Velocimacro内执行时才会被产生。这个特性使得你可以将一个方法调用作为参数传递给Velocimacro,而每次Velocimacro执行时都是通过这个方法调用产生不同的值来执行的。例如:
#macro( callme $a )
$a $a $a
#end
#callme( $foo.bar() )
执行的结果是:reference $foo的bar()方法被执行了三次。
在第一次扫描中,出现惊人的作用。但是当你考虑到Velocimacro的最原始动机:消除剪切、粘贴、复制,简单地使用VTL使它更灵活。它允许你对传递对象到Velocimacro,例如一个产生重复序列颜色,着色表格的行的对象。
如果你不需要这样的特性可以通过以下方法:
#set( $myval = $foo.bar() )
#callme( $myval )

Velocimacro properties
Velocity.properties文件中的某几行能够使Velocimacros的实现更加灵活。注意更多的内容可以看Developer Guide。
Velocity.properties文件中的velocimacro.libraary:一个以逗号分隔的模板库列表。默认情况下,velocity查找唯一的一个库:VM_global_library.vm。你可以通过配置这个属性来指定自己的模板库。
Velocity.properties文件中的velocimacro.permissions.allow.inline属性:有两个可选的值true或者false,通过它可以确定Velocimacros是否可以被定义在regular template内。默认值是ture――允许设计者在他们自己的模板中定义Velocimacros。
Velocity.properties文件中的velocimacro.permissions.allow.inline.replace.global属性有两个可选值true和false,这个属性允许使用者确定inline的Velocimacro定义是否可以替代全局Velocimacro定义(比如在velocimacro.library属性中指定的文件内定义的Velocimacro)。默认情况下,此值为false。这样就阻止本地Velocimacro定义覆盖全局定义。
Velocity.properties文件中的velocimacro.permissions.allow.inline.local.scale属性也是有true和false两个可选值,默认是false。它的作用是用于确定你inline定义的Velocimacros是否仅仅在被定义的template内可见。换句话说,如果这个属性设置为true,一个inline定义的Velocimacros只能在定义它的template内使用。你可以使用此设置实现一个奇妙的VM窍门:a template can define a private implementation of the second VM that will be called by the first VM when invoked by that template. All other templates are unaffected。
Velocity.properties文件中的velocimacro.context.localscope属性有true和false两个可选值,默认值为false。当设置为true时,任何在Velocimacro内通过#set()对context的修改被认为是针对此velocimacro的本地设置,而不会永久的影响内容。
Velocity.properties文件中的velocimacro.library.autoreload属性控制Velocimacro库的自动加载。默认是false。当设置为ture时,对于一个Velocimacro的调用将自动检查原始库是否发生了变化,如果变化将重新加载它。这个属性使得你可以不用重新启动servlet容器而达到重新加载的效果,就像你使用regular模板一样。这个属性可以使用的前提就是resource loader缓存是off状态(file.resource.loader.cache = false)。注意这个属性实际上是针对开发而非产品的。

Velocimacro Trivia
Velocimacro必须被定义在他们被使用之前。也就是说,你的#macro()声明应该出现在使用Velocimacros之前。
特别要注意的是,如果你试图#parse()一个包含#macro()的模板。因为#parse()发生在运行期,但是解析器在parsetiem决定一个看似VM元素的元素是否是一个VM元素,这样#parse()-ing一组VM声明将不按照预期的样子工作。为了得到预期的结果,只需要你简单的使用velocimacro.library使得Velocity在启动时加载你的VMs。

Escaping VTL directives
VTL directives can be escaped with “\”号,使用方式跟VTL的reference使用逃逸符的格式差不多。

#include( “a.txt” ) renders as

#include( “a.txt” )

#include( “a.txt” ) renders as #include( “a.txt” )

#include( “a.txt” )

\#include ( “a.txt” ) renders as <contents of a.txt>

\#include ( “a.txt” )
在对在一个directive内包含多个script元素的VTL directives使用逃逸符时要特别小心(比如在一个if-else-end statement内)。下面是VTL的if-statement的典型应用:
#if( KaTeX parse error: Expected 'EOF', got '#' at position 31: …heslav Ganelin #̲end 如果jazz是ture,输出将是:
Vyacheslav Ganelin
如果$jazz是false,将没有输出。使用逃逸符将改变输出。考虑一下下面的情况:
#if( j a z z ) V y a c h e s l a v G a n e l i n # e n d 现 在 无 论 jazz ) Vyacheslav Ganelin \#end 现在无论 jazz)VyacheslavGanelin#endjazz是true还是false,输出结果都是:
#if($ jazz )
Vyacheslav Ganelin
#end
事实上,由于你使用了逃逸符,$jazz根本就没有被解析为boolean型值。在逃逸符前使用逃逸符是合法的,例如:
\#if( KaTeX parse error: Expected 'EOF', got '#' at position 32: …slav Ganelin \\#̲end 以上程序的显示结果为:…jazz为false,那么将没有输出。注意:事情也有例外,如果script elements 没有完全的逃避。
\#if( $jazz )
Vyacheslave Ganelin
\#end
在这里#if 已经逃避了,但是#end没有,有太多的#end 的产生解析错误。
VTL:Formatting issues
尽管在此用户手册中VTL通常都开始一个新行,如下所示:
#set( $imperial = [“Munetaka”,“Koreyasu”,“Hisakira”,“Morikune”] )
#foreach( $shogun in $imperial )
KaTeX parse error: Expected 'EOF', got '#' at position 8: shogun #̲end 但是像下面这种写法…foo = [“KaTeX parse error: Expected 'EOF', got '#' at position 20: …nd ","a cake"])#̲foreach(a in f o o ) foo) foo)a #end please.
上面的代码可以被改写为:
Send me
#set( $foo = [”$10 and ",“a cake”] )
#foreach( $a in $foo )
KaTeX parse error: Expected 'EOF', got '#' at position 3: a #̲end please. 或者 …foo = ["KaTeX parse error: Expected 'EOF', got '#' at position 38: … #̲foreach …a in f o o ) foo ) foo)a
#end please.
每一种的输出结果将一样。

其他特性和杂项
math
在模板中可以使用Velocity内建的算术函数,如:加、减、乘、除。下面的等式分别是:加、减、乘、除:
#set( $foo = $bar + 3 )
#set( $foo = $bar - 4 )
#set( $foo = $bar * 6 )
#set( $foo = $bar / 2 )
当执行除法时将返回一个Integer类型的结果。而余数你可以使用%来得到:
#set( $foo = $bar % 5 )
在Velocity内使用数学计算公式时,只能使用像-n,-2,-1,0,1,2,n这样的整数,而不能使用其它类型数据。当一个非整型的对象被使用时它将被logged并且将以null作为输出结果。

Range Operator
Range operator可以被用于与#set和#foreach statement联合使用。对于处理一个整型数组它是很有用的,Range operator具有以下构造形式:
[n…m]
m和n都必须是整型,而m是否大于n则无关紧要。例子:
First example:
#foreach( $foo in [1…5] )
$foo
#end

Second example:
#foreach( $bar in [2…-2] )
$bar
#end

Third example:
#set( $arr = [0…1] )
#foreach( $i in $arr )
$i
#end

Fourth example:
[1…3]
产生以下输出:
First example:
1 2 3 4 5

Second example:
2 1 0 -1 -2

Third example:
0 1

Fourth example:
[1…3]
注意:range operator只在#set和#foreach中有效。
网页设计者使用标准尺寸制作表格,但是某时候会没有足够的数据填入表格,就会发现 range 非常有用。

Advanced Issue:Escaping and!
当一个reference被“!”分隔时,并且在它之前有逃逸符时,reference将以特殊的方式处理。注意这种方式与标准的逃逸方式时不同的。对照如下:
#set( $foo = “bar” )
$!foo
$!{foo}
$\!foo
$\!foo
这将显示为:
$!foo
$!{foo}
$!foo
$\!foo
\ 在 $ 前面跟逃避规则相比较;
$foo
$!foo
$!{foo}
\$!{foo}
这将显示为:
$foo
$!foo
$!{foo}
\bar

Velocimacro杂记
这章节是一个小型涉及Velocimacros的常见问题解答。这章节会随时间的变化而变化,所以它的作用有时是检验新的信息。
注意:在这章节’Velocimacro’简称为‘VM’。

  1. 我能用一个标识或者另外的VM 作为一个VM的参数吗?
    例如:#center ( #bold( “hello” ) )

答:不可以。一个directive的参数使用另外一个directive是不合法的。
但是,还是有些事情你可以作的。最简单的方式就是使用双引号,所以你可以这样做:
#set($stuff = “#bold(‘hello’)” )
#center( $stuff )
上面的格式也可以缩写为一行:
#center( “#bold( ‘hello’ )” )
请注意在下面的例子中参数被evaluated在Velocimacro内部,而不是在calling level。例子:

#macro( inner $foo )
inner : $foo
#end

#macro( outer KaTeX parse error: Expected 'EOF', got '#' at position 10: foo ) #̲set(bar = “outerlala”)
outer : $foo
#end

#set(KaTeX parse error: Expected 'EOF', got '#' at position 23: …calltimelala') #̲outer( "#inner(bar)" )

输出结果为:
Outer : inner : outerlala
因为#inner(KaTeX parse error: Expected 'EOF', got '#' at position 11: bar)的赋值发生在#̲outer(),所以bar的值在#outer()赋给的。
记住Veloctiy的特性:参数的传递是By Name的。例如:
#macro( foo $color )

Hi There #end

#foo( KaTeX parse error: Expected 'EOF', got '#' at position 76: …我们可以按照下面的方式执行: #̲set(color = $bar.rowColor())
#foo( $color )

2.我能通过#parse()登记velocimacros吗?

答:目前,Velocimacros必须在第一次被模板调用前被定义。这就意味着你的#macro()声明应该出现在使用Velocimacros之前。
如果你试图#parse()一个包含#macro() directive的模板,这一点是需要牢记的。因为#parse()发生在运行期,但是解析器在parsetiem决定一个看似VM元素的元素是否是一个VM元素,这样#parse()-ing一组VM声明将不按照预期的样子工作。为了得到预期的结果,只需要你简单的使用velocimacro.library使得Velocity在启动时加载你的VMs。

3.什么是velocimacro自动加载?

答:velocimacro.library.autoreload是专门为开发而非产品使用的一个属性。此属性的默认值是false。
当.resource.loader.cache = false 连同一起设为true ()(是你用的资源器,例如‘file’),当你编译它们的时候Velocity引擎会自动重载那些在你的velocimacro库文件中的修改,所以你不用servlet引擎(或者应用程序)或者其他窍门来使你的velocimacros重载。
这里有一个简单的属性配置。
file.resource.loader.path = templates
file.resource.loader.cache = false
velocimacro.library.autoreload = true
不要在你的作品中出现上述的配置

字符串串联
开发人员最常问的问题是我如何作字符拼接?在java中是使用“+”号来完成的。
在VTL里要想实现同样的功能你只需要将需要联合的reference放到一起就行了。例如:
#set( $size = “Big” )
#set( $name = “Ben” )

  The clock is $size$name.

输出结果将是:The clock is BigBen.。更有趣的情况是:
#set( $size = “Big” )
#set( $name = “Ben” )

  #set($clock = "$size$name" )

  The clock is $clock.

上例也会得到同样的结果。最后一个例子,当你希望混合固定字段到你的reference时,你需要使用标准格式:
#set( $size = “Big” )
#set( $name = “Ben” )

  #set($clock = "${size}Tall$name" )

  The clock is $clock.

输出结果是:The clock is BigTallBen.。使用这种格式主要是为了使得 s i z e 不 被 解 释 为 size不被解释为 sizesizeTall。

反馈
如果你在手册中遇到任何错误或者有其他关于Velocity用户手册的反馈,请email到 Velocity user list。谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值