Reference允许设计者使用动态的内容,而directive使得你可以应用java代码来控制你的显示逻辑,从而达到你所期望的显示效果。
#set标志是用于对一个reference赋值,值会赋给一个变量或者一个属性,而且赋值会在括号里出现:
#set($primate="monkey") #set($customer.Behavior=$primate)
左边(LHS) 一定是一个变量或者一个属性,右边(RHS)可以是下面中的一个类型:
◇ 变量
◇ 字符串
◇ 属性
◇ 方法
◇ 数字
◇ 数组
这些例子显示上述的每一种类型:
## variable reference #set($monkey=$bill) ## string literal #set($monkey.Friend="monica") ## property reference #set($monkey.Blame=$whitehouse.Leak) ## method reference #set($monkey.Plan=$spindoctor.weave($web)) ##number literal #set($monkey.Number=123) ## ArrayList #set($monkey.Say=["Not",$my,"fault"])
注意:最后一个例子的取值方法为:$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$result
如果$query.criteria(“name”)返回一个“bill”,而$query.criteria(“address”)返回的是null,则显示的结果如下:
The result of the first query is bill The result of the second query isbill
这容易使新手糊涂:创建一个#foreach循环,企图想通过一个属性或者一个方法 #set一个reference,然后马上就用#if测试。例如:
#set( $criteria = ["name","address"] ) #foreach( $criterion in $criteria ) #set( $result = $query.criteria($criterion)) #if( $result ) Query was successful #end #end
在上面的例子中,程序将不能智能的根据$result的值决定查询是否成功。在$result被#set后(added tothe context),它不能被设置回null(removedfrom 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结束。
当你使用#setdirective,Stringliteral封闭在一对双引号内。象下面:
#set( $directoryRoot = "www" ) #set( $templateName = "index.vm") #set( $template ="$directoryRoot/$templateName" ) $template
上面这段代码的输出结果为:
www/index.vm
但是,当stringliteral被封装在单引号内时,它将不被解析:
#set( $foo = "bar" ) $foo #set( $blargh = '$foo' ) $blargh
输出为:
bar $foo
上面这个特性可以通过修改velocity.properties文件的stringliterals.interpolate = false的值来改变上面的特性是否有效。
当一个web页面被生成时使用Velocity的#if directrive,如果条件成立的话可以在页面内嵌入文字。例如:
#if( $foo ) <strong>Velocity!</strong> #end
上例中的条件语句将在以下两种条件下成立:
(a) $foo是一个boolean型的变量,且它的值为true
(b) $foo变量的值是不为null的string或者不为空的collection。
(c) $foo变量的值是不为null的对象(除了string和collection)
这里需要注意一点:Velocity context仅仅能够包含对象,所以当我们说“boolean”时实际上代表的时一个Boolean对象。即便某个方法返回的是一个boolean值,Velocity也会利用内省机制将它转换为一个Boolean的相同值。如果条件成立,那么#if和#end之间的内容将被显示。在这个例子中,如果$foo的值为true,输出为“Velocity!”。相反地,如果$foo是一个null值,或者是一个false值,表达式值为false,没有输出。
#elseif和#else元素可以同#if一同使用。注意:Velocity模板引擎遇到一个为 true 值的表达式就会停止。在下面的例子,假设$foo=15,$bar=6:
#if( $foo < 10 ) <strong>Go North</strong> #elseif( $foo == 10 ) <strong>Go East</strong> #elseif( $bar == 6 ) <strong>Go South</strong> #else <strong>Go West</strong> #end
在这个例子中,$foo比10大,所以在开始的两个比较中都失败。接着$bar跟6比较为true的所以输出为GO South。
注意这里的Velocity的数字是作为Integer来比较的――其他类型的对象将使得条件为false,但是与java不同它使用“==”来比较两个值,而且velocity要求等号两边的值类型相同。
Velocity中使用等号操作符判断两个变量的关系。这里有个简单例子关于等于号的使用:
#set ($foo = "deoxyribonucleicacid") #set ($bar = "ribonucleic acid") #if ($foo == $bar) In this case it's clear they aren'tequivalent. So... #else They are not equivalent and this will bethe output. #end
Velocity有AND、OR和NOT逻辑运算符。
## logical AND #if( $foo && $bar ) <strong> This AND that</strong> #end
只有当$foo和$bar都为true,#if才会得到true值。如果$foo=false,表达式的值为false,$bar就不会求值。如果$foo的值为true,Velocity模板引擎会检查$bar的值,如果$bar=true,整个表达式的值为true,输出为“This AND that”。如果$bar=false,整个表达式的值为false,没有输出。
逻辑OR的工作方式一样,除了只要有一个值为true,整个表达式的值就为true。考虑一下下面的例子:
## logical OR #if( $foo || $bar ) <strong>This OR That</strong> #end
如果$foo=true,Velocity模板引擎就没有必要查找$bar,无论$bar是true还是false,表达式的值为true,输出为“This OR That”。如果$foo=flase,$bar的值就一定要检查,在这个例子中,如果$bar同样是false,表达式的值为false,没有输出。从另外一个角度看,如果$bar的值为true,整个表达式的值为true,输出为 “This OR That”。
关于逻辑 NOT,只有一个疑问:
##logical NOT #if( !$foo ) <strong>NOT that</strong> #end
如果$foo=true,!$foo的值为false,没有输出。如果$foo=false,!$foo的值为true,输出为“NOT that”。注意不要跟quiet reference $!foo混为一谈,那是完全不一样的。
#foreach用于循环,例子:
<ul> #foreach( $product in $allProducts ) <li>$product</li> #end </ul>
每次循环$allProducts中的一个值都会赋给$product变量。$allProducts可以是一个Vector、Hashtable或者Array。分配给$product的值是一个java对象,并且可以通过变量被引用。例如:如果$product是一个java的Product类,并且这个产品的名字可以通过调用他的getName()方法得到。
现在我们假设$allProducts是一个Hashtable,如果你希望得到它的key应该像下面这样:
<ul> #foreach( $key in $allProducts.keySet() ) <li>Key: $key ­> Value: $allProducts.get($key)</li> #end </ul>
Velocity还特别提供了得到循环次数的方法,以便你可以像下面这样作:
<table> #foreach( $customer in $customerList) <tr><td>$velocityCount</td><td>$customer.Name</td></tr> #end </table>
$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 script element允许模板设计者引入本地文件,被引入文件的内容将不会通过模板引擎被render。为了安全的原因,被引入的本地文件只能在TEMPLATE_ROOT目录下。
#include( "one.txt" )
#include引用的文件用引号括起来,如果您需要引入多个文件,可以用逗号分隔就行:
#include( "one.gif","two.txt","three.htm")
在括号内可以是文件名,但是更多的时候是使用变量的,这用于根据页面提交的需求而输出,这里有一个例子同时有文件名和变量:
#include( "greetings.txt",$seasonalstock )
#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
在显示“Countdown”后,Velocity通过parsefoo.vm,从8往下数。当计数到了0,它就会显示“All done with parsefoo.vm!”。在这时,Velocity会返回到dofoo.vm,输出信息:“Alldone with dofoo.vm!”。
#break跳出循环,循环以外代码继续执行。
#stop直接终止输出,循环以外代码终止执行,页面所有均不进行渲染。
#foreach($i in [1..10]) #if($i==1) #break ##stop #end $i #end 1
(a) 注释掉break和stop时,输出:123456789101
(b) 仅有break命令时,输出:1
(c) 仅有stop命令时,输出为空,stop后面页面所有内容均不进行渲染
停止执行模板引擎并返回,把它应用于debug是很有帮助的。
动态执行一串字符串的值:
#evaluate('string with VTL #if(true)will bedisplayed#end')
渲染结果:string with VTL willbe displayed
#set($source1 = "abc") #set($select = "1") #set($dynamicsource = "$source$select") ## $dynamicsource is now the string '$source1' #evaluate($dynamicsource)
渲染结果:abc
类似于C语言的#define命令。
#define($hello) Hello ${who}! #end #set($who = "World") $hello
渲染结果:Hello World!