1. 取得语义Getting literal
VTL 特别的字符,比如$ 和 #, 来做这个工作,因此在模板中使用这些自负的时候必须格外小心。本节讲述$ 的转义。
1.1. 货币
我们写下句子 "I bought a 4 lb. sack of potatoes at the farmer's market for only $2.50!" ,这并没有什么问题。但如前所述,VTL标识符总是以大写或是小写字母开始,所以$2.50 在引用中将不能出错。
1.2. 转义有效的VTL 引用
问题将会出现,因为Velocity 将有一个潜在的冲突。转义特殊字符是处理VTL模板种特殊字符的最好的办法,者可以用一个反斜线来进行。
foo /foo |
如果 Velocity 在VTL模板中遇到一个$email引用,他将在上下文中查找相应的值。这里,输出将是foo,因为 $email 是定义了的。如果$email 未定义,输出将是$email 。
假设$email 是定义了的(比如,具有值foo),但是你想输出 $email。可以有几种方法来做这个事情,不是最简单的是使用转义符。
## The following line defines $email in this template: #set( $email = "foo" ) |
将输出是
foo /foo |
注意: / 绑定在$ 的左边。从做绑定原则使///$email 被解释为//$email。 和上面例子比较下面的例子,这里$email 未定义。
|
输出
|
注意,Velocity 处理定义和未定义的引用是不同的。下面一个set 指令将$foo 设为值gibbous.。
#set( $foo = "gibbous" ) $moon = $foo |
输出将是$moon = gibbous
-- 这里 $moon 作为字面输出,因为他并没有定义。而gibbous 将在$foo 的位置输出。
我们也可以转义VTL 指令,这将在指令一节祥述。
2. Case Substitution
现在你大致了解了引用,可以在模板中使用它们了。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} |
这个例子显示了引用的一些其他用法。Velocity 借鉴了Java的自省和组件bean特征,来解决引用名在上下文中作为对象和对象方法的问题。可以在你的模板的任何地方插入引用和求值。
Velocity, 建模在Sun Microsystems定义的BEAN规范之上,是大小写敏感的;开发者努力捕捉和纠正可能出现的用户错误。当方法getFoo() 在模板中通过$bar.foo引用时,Velocity 首先尝试$getfoo。如果失败,他会再尝试 $getFoo。类似地,当一个模板引用到 $bar.Foo, Velocity 将尝试 $getFoo() 先,然后尝试 getfoo()。
注意: 模板中引用示例变量的问题仍然没有解决。 只有引用等价于JavaBean的 getter/setter 方法解决了。(比如 $foo.Name 解决了到类 Foo的 getName() 示例方法的引用,但不能引用Foo的一个公共实例变量Name)。
3. 指令
因为指令(使用脚本来有效操控JAVA代码的输出)允许页面设计员真正专注于咱点的外观和内容设计,引用允许模板设计员为Web页面产生动态内容。
3.1. #set
#set 指令用来为引用设置相应的值。值可以被值派给变量引用或者是属性引用,而且赋值要在括号里括起来。
#set( $primate = "monkey" ) #set( $customer.Behavior = $primate ) |
赋值的左边必须是一个变量应用或者是属性引用。右边可以是下面的类型之一:
变量引用
字面字符串
属性引用
方法引用
字面数字
数组列表
这些例子演示了上述的每种类型:
#set( $monkey = $bill ) ## variable reference #set( $monkey.Friend = "monica" ) ## string literal #set( $monkey.Blame = $whitehouse.Leak ) ## property reference #set( $monkey.Plan = $spindoctor.weave($web) ) ## method reference #set( $monkey.Number = 123 ) ##number literal #set( $monkey.Say = ["Not", $my, "fault"] ) ## ArrayList |
注意:最后一个例子中,在方括号[..] 中定义的项目可以被ArrayList 类定义的方法访问。 比如,你可以使用$monkey.Say.get(0)访问上述的第一个元素。
右边也可以是一个简单的算术表达式:
#set( $value = $foo + 1 ) #set( $value = $bar - 1 ) #set( $value = $foo * $bar ) #set( $value = $foo / $bar ) |
如果右边是一个属性或方法引用,取值是NULL,他将不会赋值给左边。通过这种机制将一个存在的引用从上下文中删除是不可能的。这对Velocity的新手可能会混淆。例如:
#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,上述VTL 将解释为:
The result of the first query is bill
The result of the second query is bill |
这往往会给那些想构建#foreach循环来试图通过属性和方法引用来设置一个引用的新手带来困惑,下面马上通过#if指令测试一下。例如:
#set( $criteria = ["name", "address"] )
#foreach( $criterion in $criteria )
#set( $result = $query.criteria($criterion) )
#if( $result ) Query was successful #end
#end |
在上面的例子中,依靠$result 的去值来决定查询是否成功恐怕不是英明的做法。 当$result 被#set设置后(添加到上下文中),他就不能再被设值为null (从上下文中删除)。
我们对此的解决方法是预设$result 为 false。 然后如果 $query.criteria() 调用失败,你就可以检查之。
#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 语句。
3.2. 字面字符串
当使用#set 指令时,括在双引号中的字面字符串将解析和重新解释,如下所示:
#set( $directoryRoot = "www" ) #set( $templateName = "index.vm" ) #set( $template = "$directoryRoot/$templateName" ) $template |
输出将会是:
www/index.vm |
然而,当字面字符串括在单引号中时,他将不被解析:
#set( $foo = "bar" ) $foo #set( $blargh = '$foo' ) $blargh |
输出是:
Bar $foo |
默认情况下,使用单引号来渲染未解析文本在Velocity是有效的。这种特征可以通过编辑velocity.properties 中的 stringliterals.interpolate=false来改变。
3.3. 条件
3.4. If / ElseIf / Else
Velocity中的#if 指令允许在页面生成时,在IF条件为真的情况下包含文本。例如:
#if( $foo ) <strong>Velocity!</strong> #end |
变量 $foo 先求值,以决定是否为真。在这两种情况下为真: (i) $foo 是一个逻辑变量并具有真的值,或者 (ii) 值非空。要记住Velocity 上下文仅包括对象,所以当我们说“布尔”'boolean'时,他会被表示为“布尔类”(Boolean class)。 这对即使是返回布尔类型的方法也是真的—自省架构将返回一个具有相同逻辑值的布尔类。
如果求值为真时, #if 和 #end 语句之间的内容将输出。在这种情况下,如果 $foo 为真,输出将是"Velocity!"。相反,如果 $foo 具有一个null 值,或者逻辑假,语句求值为假,则没有输出。
一个 #elseif 或者 #else 项可以用在#if 语句中。请注意, Velocity 模板引擎将在第一个为真的表达式时停止。下面的例子中,假设$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,结果为真,所以输出为Go South。
请注意在现在, Velocity的数值比较约束为整型—其他类型都将求值为false。 仅有一个例外是等于'==',这时Velocity 要求等号两边的对象具有相同的类型。
3.5. 关系和逻辑操作符
Velocity 使用等式操作符来决定两个变量间的关系。这里是一个简单的例子演示如何使用等式操作符:
#set ($foo = "deoxyribonucleic 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参考手册VTL Reference Guide 。下面是一些演示如何使用逻辑操作符的例子:
## logical AND
#if( $foo && $bar ) <strong> This AND that</strong> #end
|
例子中#if() 指令仅在$foo 和$bar 斗为真的时候才为真。如果$foo 为假,则表达式也为假;并且 $bar 将不被求值。如果 $foo 为真,Velocity 模板引擎将继续检查$bar;的值,如果 $bar 为真,则整个表达式为真。并且输出This AND that 。如果 $bar 为假,将没有输出因为整个表达式为假。
逻辑OR 的工作方式相同,唯一的例外是其中一个表达式要被求值,以便决定整个表达式是否为真。请看下面的例子:
## logical OR
#if( $foo || $bar ) <strong>This OR That</strong> #end |
如果 $foo 为真,Velocity 模板引擎就不需要去察看$bar 的值,不管 $bar 是否为真,真个表达式都为真,因此输出This OR That 。如果 $foo 为假,$bar 就必须检查其值了。在这种情况下,如果$bar 也是为假,表达式将为假,没有任何输出。当然,如果$bar 为真,则真个表达式为真,输出This OR That。
对于逻辑NOT 操作符,只有一个操作数:
##logical NOT
#if( !$foo ) <strong>NOT that</strong> #end
|
这里,如果$foo 为真,!$foo 求值为假,没有输出。如果$foo 为假,!$foo 求值为真,输出NOT that 。请当心,不要和安静引用quiet reference $!foo 混淆它们是完全不同的。