Velocity Template Language(VTL):AN introduction
VTL意味着提供最单、最Ҏq且最整洁的方式合q面动态内宏V?br />
VTL
使用references来在web
site内嵌套动态内容,一个变量就是一U类型的reference。变量是某种cd的refreenceQ它可以指向java代码中的定义Q或者从当前
面内定义的VTL statement得到倹{下面是一个VTL statement的例子,它可以被嵌套到HTML代码中:
#set ( $a = “Velocity” )
?
所有的VTL
statement一Pq个statement以#字符开始ƈ且包含一个directiveQset。当一个在U用戯求你的页面时QVelocity
Templating Engine查询整个页面以便发现所有#字符Q然后确定哪些是VTL statementQ哪些不需要VTL作Q何事情?br />
Q字W后紧跟一个directiveQsetӞq个set directive使用一个表辑ּQ用括号封闭)――一个方E式分配一个值给变量。变量被列在左边Q而它的D列在双Q最后他们之间用=号分剌Ӏ?br />
在上面的例子中,变量?aQ而它的值是Velocity。和其他的references一样以$字符开始,而值L以双引号闭。Velocity中仅有String可以被赋值给变量?br />
C以下的规则:
使用$字符开始的references用于得到什么;使用#字符开始的directives用于作些什么?br />
Hello Velocity World!
一旦某个变量被分配了一个|那么你就可以在HTML文g的Q何地方引用它。在下面的例子中Q一个D分配l?foo变量Qƈ在其后被引用?br />
<html>
<body>
#set ( $foo = “Velocity” )
Hello $foo World!
</body>
</html>
上面的实现结果是在页面上打印“Hello Velocity WorldQ?#8221;
Z使包含VTL directives的statement更具有可L,我们鼓励你在新行开始每个VTL statementQ尽你不是必须q么作。Set directive在后面详细描述?br />
注释
单行注释Q?br />
## This is a single line comment.
多行注释Q?br />
#*
Thus begins a multi-line comment. Online visitors won’t
see this text because the Velocity Templating Engine will
ignore it.
*#
文档格式Q?br />
#**
This is a VTL comment block and
may be used to store such information
as the document author and versioning
information:
@version 5
@author
*#
References
?
VTL中有三种cd的referencesQ变?variables)、属?properties)、方?methods)。作Z个用VTL?
面设计者,你和你的工程师必dreferences的名U达成共识,以便你可以在你的template中用它们?br />
Everything coming to and from a reference被作Z个String对象处理。如果有一个对?foo是一个Integer对象Q那么Velocity调用它的toString()Ҏ这个对象{型ؓStringcd?br />
变量
格式要求同java?br />
属?
例子Q?br />
$customer.Address
$purchase.Total
$customer.Address
有两U含义。它可以表示Q查找hashtable对象customer中以Address为关键字的|也可以表C用customer对象?
getAddress()Ҏ。当你的面被请求时QVelocity确定以上两U方式选用那种Q然后返回适当的倹{?br />
Ҏ
一个方法就是被定义在java中的一D代码,q且它有完成某些有用工作的能力,例如一个执行计和判断条g是否成立、满等。方法是一个由$开始ƈ跟随VTL标识W组成的ReferencesQ一般还包括一个VTLҎ体。例如:
$customer.getAddress()
$purchase.getTotal()
$page.setTitle( “My Home Page” )
$person.setAttributes( [“Strange”, “Weird”, “Excited”] )
前两个例?customer.getAddress()?purchase.getTotal()看v来挺想上面的属?customer.Address ?$purchase.Total。如果你觉得他们之间有某U联pȝ话,那你是正的?br />
VTL属性可以作为VTLҎ的羃写?customer.Address属性和使用$customer.getAddress()Ҏh相同的效果。如果可能的话用属性的方式是比较合理的。属性和Ҏ的不同点在于你能够给一个方法指定一个参数列表?br />
正式reference标记
reference的正是格式如下:
${mudSlinger} 变量
${customer.Address} 属?br />
${purchase.getTotal()} Ҏ
非正是格式更见常用,但是有时q是使用正是格式比较适合。例如:你希望通过一个变?vice来动态的l织一个字W串?br />
Jack is a $vicemaniac.
本来变量?vice现在却变成了$vicemaniacQ这样Veloctiy׃知道您到底要什么了。所以,应该使用正是格式书写
Jack is a ${vice}maniac
现在Velocity知道变量?vice而不?vicemaniac?br />
Quiet reference notation
例如Q?br />
<input type=”text” name=”email” value=”$email” />
当页面的form被初始加载时Q变?emailq没有|q时你肯定是希望它能够显CZ个blank text来代替输?#8221;$email”q样的字Dc那么用quiet reference notation比较合适?br />
<input type=”text” name=”email” value=”$!email”/>
q样文本框的初始值就不会是email而是Ig?br />
正式和quiet格式的reference notation也可一同用,像下面这P
<input type=”text” name=”email” value=”$!{email}”/>
Getting literal
Velocity使用Ҏ字符$?来帮助它工作Q所以如果要在template里用这些特D字W要格外心。本节将讨论$字符?br />
货币字符
在VTL中?2.5q样的货币标识是没有问题得的QVTL不会它错认为是一个referenceQ因为VTL中的referenceL以一个大写或者小写的字母开始?br />
Escaping valid VTL reference
VTL中?#8220;"”作ؓ逃逸符?br />
例如Q?br />
#set( $email = “foo” )
$email
"$email
""$email
"""$email
render为:
foo
$email
"foo
""$email
如果email变量没有被定义则
$email
"$email
""$email
"""$email
被render为:
$email
"$email
""$email
"""$email
注意QVTL中未被定义的变量被认ؓ是一个字W串Q所以以下例子:
#set( $foo = “gibbous” )
$moon = $foo
的输出结果是Q?br />
$moon = gibbous
Case substitution
现在你已l对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}
但是Q注意VTL中不会将reference解释为对象的实例变量。例如:$foo.Name被解释为Foo对象的getNameQ)ҎQ而不是Foo对象的Name实例变量?br />
Directives
Reference允许设计者用动态的内容Q而directive使得你可以应用java代码来控制你的显C逻辑Q从而达C所期望的显C效果?br />
#set
#set directive被用于设|一个reference的倹{例如:
#set ( $primate = “monkey” )
#set ( $customer.Behavior = $primate )
赋值左侧的QLHSQ必L一个变量或者属性reference。右侧(RHSQ可以是以下cd中一U:
l 变量reference
l String literal
l 属性reference
l Ҏreference
l number literal
l ArrayList
下面是应用各U类型的RHS的例子:
Qset ( $monkey = $bill ) ##变量reference
Qset ( $monkey.Friend = “monica” ) ##String literal
Qset ( $monkey.Blame = $whitehouse.Leak )##属性reference
Qset ( $monkey.Plan = $spindoctor.weave($web) )##Ҏreference
Qset ( $monkey.Number = 123 )##Number literal
Qset ( $monkey.Say = [“Not”, $my, “fault”] )##ArrayList
注意Q最后一个例子的取值方法ؓQ?monkey.Say.get(0)
RHS也可以是一个简单的术表达式:
#set ( $value = $foo + 1 )
#set ( $value = $bar -1 )
#set ( $value = $foo * $bar )
#set ( $value = $foo / $bar )
如果你的RHS是一个nullQVTL的处理将比较ҎQ它指向一个已l存在的referenceQ这对初学者来讲可能是比较费解的。例如:
#set ( $resut = $query.criteria(“name”) )
The result of the first query is $result
#set ( $resut = $query.criteria(“address”) )
The result of the second query is $result
如果$query.criteria(“name”)q回一?#8220;bill”Q?query.criteria(“address”)q回的是nullQ则昄的结果如下:
The result of the first query is bill
The result of the first query is bill
看看下面的例子:
#set( $criteria = ["name", "address"] )
#foreach( $criterion in $criteria )
#set( $result = $query.criteria($criterion) )
#if( $result )
Query was successful
#end
#end
?
上面的例子中Q程序将不能的根?result的值决定查询是否成功。在$result?set后(added to the
contextQ,它不能被讄回nullQremoved from the
contextQ。打印的l果显CZơ查询结果都成功了,但是实际上有一个查询是p|的?br />
Z解决以上问题我们可以通过预先定义的方式:
#set( $criteria = [“name”, “address”] )
#foreach( $criterion in $criteria )
#set( $result = false )
#set( $result = $query.criteria( $criterion ) )
#if( $result )
Query was successful
#end
#end
String Literals
当你使用#set directiveQString literal闭在一对双引号内?br />
#set ( $directoryRoot = “www” )
#set ( $templateName = “index.vm” )
#set ( $template = “$directoryRoot/$tempateName” )
$template
上面q段代码的输出结果ؓQwww/index.vm
但是Q当string literal被封装在单引号内Ӟ它将不被解析Q?br />
#set ( $foo = “bar” )
$foo
#set ( $blargh = ‘$foo’ )
l果Q?br />
bar
$foo
上面q个Ҏ可以通过修改velocity.properties文g的stringliterals.interpolate = false的值来改变上面的特性是否有效?br />
条g语句
if/elseif/else
当一个web面被生成时使用Velocity?if directriveQ如果条件成立的话可以在面内嵌入文字。例如:
#if ( $foo )
<strong>Velocity!</strong>
#end
上例中的条g语句在以下两种条g下成立:
l $foo是一个boolean型的变量Q且它的gؓtrue
l $foo变量的g为null
q里需要注意一点:Velocity context仅仅能够包含对象Q所以当我们?#8220;boolean”时实际上代表的时一个Boolean对象。即便某个方法返回的是一个boolean|Velocity也会利用内省机制它转换Z个Boolean的相同倹{?br />
如果条g成立Q那?if?end之间的内容将被显C?br />
#elseif?else元素可以?if一同用。例如:
#if( $foo < 10 )
<strong> Go North </strong>
#elseif( $foo == 10 )
<strong> Go East </strong>
#elseif( $foo == 6 )
<strong> Go South </strong>
#else
<strong> Go West </strong>
#end
注意q里的Velocity的数字是作ؓInteger来比较的――其他类型的对象得条件ؓfalseQ但是与java不同它?#8220;Q=”来比较两个|而且velocity要求{号两边的值类型相同?br />
关系、逻辑q算W?
Velocity中用等h作符判断两个变量的关pR例如:
#set ( $foo = “deoxyribonucleic acid” )
#set ( $bar = “ribonucleic acid” )
#if ( $foo == $foo )
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逻辑q算W。下面是一些例子:
## logical AND
#if( $foo && $bar )
<strong> This AND that </strong>
#end
## logical OR
#if ( $foo || $bar )
<strong>This OR That </strong>
#end
##logical NOT
#if ( !$foo )
<strong> NOT that </strong>
#end
循环
Foreach循环
例子Q?br />
<ul>
#foreach ( $product in $allProducts )
<li> $product </li>
#end
</ul>
每次循环$allProducts中的一个值都会赋l?product变量?br />
$allProducts
可以是一个Vector、Hashtable或者Array。分配给$product的值是一个java对象Qƈ且可以通过变量被引用。例如:?
?product是一个java的Productc,q且q个产品的名字可以通过调用他的getNameQ)Ҏ得到?br />
现在我们假设$allProducts是一个HashtableQ如果你希望得到它的key应该像下面这P
<ul>
#foreach ( $key in $allProducts.keySet() )
<li>Key: $key -> Value: $allProducts.get($key) </li>
#end
</ul>
Velocityq特别提供了得到循环ơ数的方法,以便你可以像下面q样作:
<table>
#foreach ( $customer in $customerList )
<tr><td>$velocityCount</td><td>$customer.Name</td></tr>
#end
</table>
$velocityCount
变量的名字是Velocity默认的名字,你也可以通过修改velocity.properties文g来改变它。默认情况下Q计C“1”开始,但是?
可以在velocity.properties讄它是?#8220;1”q是?#8220;0”开始。下面就是文件中的配|:
# Default name of loop counter
# variable reference
directive.foreach.counter.name = velocityCount
# Default starting value of the loop
# counter variable reference
directive.foreach.counter.initial.value = 1
Velocimacro properties
Velocity.properties文g中的某几行能够Velocimacros的实现更加灵zR注意更多的内容可以看Developer Guide?br />
Velocity.properties文g中的velocimacro.libraaryQ一个以逗号分隔的模板库列表。默认情况下Qvelocity查找唯一的一个库QVM_global_library.vm。你可以通过配置q个属性来指定自己的模板库?br />
Velocity.properties
文g中的velocimacro.permissions.allow.inline属性:有两个可选的值true或者falseQ通过它可以确?
Velocimacros是否可以被定义在regular
template内。默认值是ture――允许设计者在他们自己的模板中定义Velocimacros?br />
Velocity.properties文g中的
velocimacro.permissions.allow.inline.replace.global
属性有两个可选值true和falseQ这个属性允怋用者确定inline的Velocimacro定义是否可以替代全局Velocimacro定义
Q比如在velocimacro.library属性中指定的文件内定义的VelocimacroQ。默认情况下Q此gؓfalse。这样就L本地
Velocimacro定义覆盖全局定义?br />
Velocity.properties文g中的
velocimacro.permissions.allow.inline.local.scale
属性也是有true和false两个可选|默认是false。它的作用是用于定你inline定义的Velocimacros是否仅仅在被定义?
template内可见。换句话_如果q个属性设|ؓtrueQ一个inline定义的Velocimacros只能在定义它的template内
用。你可以使用此设|实C个奇妙的VM敲门Qa 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?br />
Velocity.properties文g中的
velocimacro.context.localscope属性有true和false两个可选|默认gؓfalse。当讄为trueӞM?
Velocimacro内通过#set()对context的修改被认ؓ是针Ҏvelocimacro的本地设|,而不会永久的影响内容?br />
Velocity.properties
文g中的velocimacro.library.autoreload属性控制Velocimacro库的自动加蝲。默认是false。当讄?
tureӞ对于一个Velocimacro的调用将自动查原始库是否发生了变化,如果变化重新加载它。这个属性得你可以不用重新启动
servlet容器而达到重新加载的效果Q就像你使用regular模板一栗这个属性可以用的前提是resource
loader~存是off状态(file.resource.loader.cache = falseQ。注意这个属性实际上是针对开发而非产品的?br />
Velocimacro Trivia
Velocimacro必须被定义在他们被用之前。也是_你的#macro()声明应该出现在用Velocimacros之前?br />
?
别要注意的是Q如果你试图#parse()一个包?macro()的模ѝ因?parse()发生在运行期Q但是解析器在parsetiem军_一?
看似VM元素的元素是否是一个VM元素Q这?parse()-ing一lVM声明不按照预期的样子工作。ؓ了得到预期的l果Q只需要你单的使用
velocimacro.library使得Velocity在启动时加蝲你的VMs?br />
Escaping VTL directives
VTL directives can be escaped with “"”P使用方式跟VTL的reference使用逃逸符的格式差不多?br />
## #include( “a.txt” ) renders as <ontents of a.txt>(注释?
#include( “a.txt” )