您的位置:首页 > 其它

Velocity语法强化5之指令符号

2013-07-26 13:18 351 查看
模板设计者使用“引用“生成动态内容, 指令(directives) – 简单的说就是设计者在模板中操作java对象—让视图设计者全面控制输出内容的格式.

指令总是以 #开头后面紧跟具体的指令符. 就像引用一样(指令的一种),可以将指令理解为”表示这里是一个什么东东).如下例生成一个出错提示:

#if($a==1)true enough#elseno way!#end

这个例子中应使用括号将else分开.

#if($a==1)true enough#{else}no way!#end

1.#set指令

#set 用来给一个引用赋值.值可以被赋给变量引用或属性引用, 但要将它们放入括号中,如下示:

#set( $primate = "monkey" )

#set( $customer.Behavior = $primate )

“左操作数被赋值“是引用操作的一个规则.=号右侧可能是以下类型之一:

· Variable reference变量引用

· String literal字符串

· Property reference 属性引用

· Method reference 命令引用

· Number literal 数字

· ArrayList 数组

· Map 映射

下面是对上述类型设置的示例:

#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

#set( $monkey.Map = {"banana" : "good", "roast beef" : "bad"}) ## Map

注意: 在ArrayList类型引用的例子中,其原素定义在数组 [..]中, 因此,你可以使表 $monkey.Say.get(0)访问第一个元素.

类似的,引用Map 的例子中, 原素定义在 { } 中,其键和值间以:隔成一对,使用 $monkey.Map.get("bannana") 在上例中将返回 'good', ( $monkey.Map.banana也会有同样效果).

下面是一般的计算表达式:

#set( $value = $foo + 1 )

#set( $value = $bar - 1 )

#set( $value = $foo * $bar )

#set( $value = $foo / $bar )

但注意:如果右边的操作数是一个属性或命令的引用而返回null,那么赋值将不会成功,且在随后的VTL中也不能再取出使用. 如下例:

#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, 上面的TVL输出结果将是:

The result of the first query is bill

The result of the second query is bill

这对与初学者的理解有些麻烦,比如在 #foreach loops中, 你使用 #set 给一个属性或命令赋值时,如下例示:

#set( $criteria = ["name", "address"] )

#foreach( $criterion in $criteria )

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

#if( $result )

Query was successful

#end

#end

☆☆:在上例中,就不能依赖if( $result )来决定查询是否成功. $result 一但被 #set 为null (context会同样), 它将不能被赋 其它值 (不能从 context中取出).

一个解决办法是,每次都将$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

注意: #set 不需要使用 #end 来声明结尾.

2.Literals (语义解析)

使用#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 such that stringliterals.interpolate=false.

另外, 指令 #literal 元素可以用来输出字面意思,如下示.

#literal()

#foreach ($woogie in $boogie)

nothing will happen to $woogie

#end

#end

会输出::

#foreach ($woogie in $boogie)

nothing will happen to $woogie

#end

3.Conditionals(条件判断)

1.If / ElseIf / Else

#if 指令用来根据条件在页面中输出内容, 如下简单的例子:

#if( $foo )

<strong>Velocity!</strong>

#end

根据变量 $foo计算后是否为true决定输出, 这会有两种情况: (i) $foo 的是值是一个boolean (true/false)型并有一个true value, 或 (ii) 它是一个非null值. 要记者,Velocity context 中只能包含Objects, 因此当我们讲 'boolean'时, 它就是一个Boolean (the class).

在 #if 和 #end 的内容是否会输出,由$foo是否为true决定. 这里,如果 $foo is true, 输出将是: "Velocity!". 如果$foo 为null或false,将不会有任何输出.

#elseif 或 #else 可以和#if组合使用. 如果第一个表达式为true,将会不计算以后的流程,如下例假设t $foo 是15 and $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

输出将会是

Go South.

2.Relational and Logical Operators(关系和逻辑运算)

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

注意:== 计算与java中的 == 计算有些不同:不能用来测试对象是否相等(指向同一块内存). Velocity中是否相等仅直接的用来比较numbers, strings的值, or objects的toString()结果是否相等. 如果是不同的对象,会调用它们的toString()命令结果来比较.

Velocity也使用AND, OR and NOT 执行逻辑运算.详细说明请参看《VTL参考中文版》,如下是一些简单示例:

## logical AND

#if( $foo && $bar )

<strong> This AND that</strong>

#end

仅当 $foo $bar 和都为true时,#if()才会输出中间内容.

OR 运算例子

## logical OR

#if( $foo || $bar )

<strong>This OR That</strong>

#end

$foo或$bar只要有一个为true就可以输出。

NOT运算则只有一个操作参数或表达式 :

##logical NOT

#if( !$foo )

<strong>NOT that</strong>

#end

考虑下,下面的例子有几种输出结果?.

#if( $foo == $bar)it's true!#{else}it's not!#end</li>

4.Loops(循环)

Foreach Loop

#foreach 用来创建循环. For example:

<ul>

#foreach( $product in $allProducts )

<li>$product</li>

#end

</ul>

#foreach 会生成包含$products中对象的一个列表. 每一次循环都会将列表中的一个对象赋与变量$product .

$allProducts 或以是一个Vector, a Hashtable or an Array类型的容器. 指定给变量 $product 是一个引用到其中一个java对象的引用. For example, if $product 确实是一个java代码中的Product class i,它可以这样的方法访问$product.Name method (ie: $Product.getName()).

我们假设 $allProducts 是一个Hashtable.看看取出其中的东东多么简单:

<ul>

#foreach( $key in $allProducts.keySet() )

<li>Key: $key -> Value: $allProducts.get($key)</li>

#end

</ul>

通过引用变量$velocityCount可以访问到Velocity提供的计数器:

<table>

#foreach( $customer in $customerList )

<tr><td>$velocityCount</td><td>$customer.Name</td></tr>

#end

</table>

$velocityCount默认的计数器引用,你可以在配置 velocity.properties中改成你喜欢的:

# 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

当然,你还可以设置其它参数,具体见《Velocity Java开发指南中文版》中讲解.

# The maximum allowed number of loops.

directive.foreach.maxloops = -1

5.Include(引入)

#include 脚本元素让模板设计者可以在模板中引入一个本地文件, 这个被引入的文件将不会经过Velocity的解析. 安全起见,可以引入的文件只是配置参数TEMPLATE_ROOT所定义目录下的,默认为当前目录下.

#include( "one.txt" )

如果需要引入多个文件,可以像下面这样.

#include( "one.gif","two.txt","three.htm" )

当然,还可用一个变量名来代替文件名引入.

#include( "greetings.txt", $seasonalstock )

6.Parse(解析模板)

#parse 元素指示可以引入一个包含TVL的本地文件,这个文件将被Veloict engine解析输出。.

#parse( "me.vm" )

与 #include 指令不同, #parse 可以从引入的模板中得到变量引用.但#parse指令只能接受一个参数.

VTL templates 被#parse 的模板中还可以再包含#parse声明,默认的深度为10,这是由配置参数directive.parse.max.depth在文件velocity.properties中决定的,你可以修改它以适合项目要求

7.Stop

#stop 指令用来指示在模板的某处,engine停止解析,这一般用来调用。用法很简单.

#stop

8.Velocimacros(宏调用)
这个宏很强大!!

#macro 指令让模板设计者可以将些重复、相关的的脚本判断定义为一个功能块.无论在什么情况下. 出于单一意图设计的 Velocimacro都会最大程序的减少模板编写中可以的出错,还是看个例子来理解一下Velocimacros的概念.

#macro( d )

<tr><td></td></tr>

#end

这样就定义了一个名为d的宏,它可以在其它的模板中像下面那样直接引用:

#d()

Velocimacro可以接收0到任意多的传入参数.如上个例是0个参数,但当它被调用时,也必须传入同样多的参数. 这里定义了一个有两个参数的宏.

#macro( tablerows $color $somelist )

#foreach( $something in $somelist )

<tr><td bgcolor=$color>$something</td></tr>

#end

#end

然后,我们在页面中来使用:

#set( $greatlakes = ["Superior","Michigan","Huron","Erie","Ontario"] )

#set( $color = "blue" )

<table>

#tablerows( $color $greatlakes )

</table>

注意变量 $greatlakes 取代了宏中变量 $somelist的输出,最终的输出如下:

<table>

<tr><td bgcolor="blue">Superior</td></tr>

<tr><td bgcolor="blue">Michigan</td></tr>

<tr><td bgcolor="blue">Huron</td></tr>

<tr><td bgcolor="blue">Erie</td></tr>

<tr><td bgcolor="blue">Ontario</td></tr>

</table>

宏一般被定义在模板中,那么站点上的其它模板中又如何调用呢?如能定义一个可以更大范围内共想的宏就太好了

如果将宏#tablerows($color $list) 定义到一个模板库中(Velocimacros template library), 其它模板就都可以访问它了.

Velocimacro Arguments(宏的参数)

Velocimacros可以从TVL中接受以下参数 :

· 引用类型 : 所有以'$'开头的

· String literal : something like "$foo" or 'hello'

· Number literal : 1, 2 etc

· IntegerRange : [ 1..2] or [$foo .. $bar]

· ObjectArray : [ "a", "b", "c"]

· boolean value true

· boolean value false

当传一个引用参数给宏时, 引用是通过名字传入的('pass by name').

#macro( callme $a )

$a $a $a

#end

#callme( $foo.bar() )

上例中命令 bar() 被调用了3 times.

最后要说的是,这个特性有些难以学习,但当你精心组织规划你的宏库时, 消除在VTL中重复功能的脚本时 –你可以像使用一个对象或组件一样使用宏, 比如一个宏对象生成多个表格的重复色彩.

如果你想利用这个特性,你只需要像下面那样简单的编码传一个值给它来调用 :

#set( $myval = $foo.bar() )

#callme( $myval )

Velocimacro Properties(宏的属性)

配置文件 velocity.properties 中有多行相关配置,具体请见《Velocity Java开发指南中文版》.

velocimacro.library –用来指定全局的宏库,多个可以,号分开.

velocimacro.permissions.allow.inline – 默认为true,可以让宏定义在一个正规的模板文件中.

velocimacro.permissions.allow.inline.to.replace.global – 用来指定模板内定义的宏的功能是否要以替换全局库,默认为false.

velocimacro.permissions.allow.inline.local.scope –模板中定义的宏的使用范围是否只是本模板可用.

velocimacro.context.localscope –如果为true,宏通过#set赋值时.宏中将保持一个,且不会由于context中的数据被修改而变化,同样,宏中的修改也不会改变context中的。

velocimacro.library.autoreload – 是否自动重新载入,用于调试环境,默认false,如为true,需要取掉chcheing:. file.resource.loader.cache = false ).

一些细节:

宏必须在模板中使用#macro()指令前定义.

尽量不要直接在模板中使用#parse() 包含 #macro() 指令.因为 #parse() 动作在运行执行,时会有一个在VM中查找元素的过程.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: