前言
在参考官方的翻译文档时, 很多语句的翻译的还有点生硬, 而且我在学的过程中有些地方读起来很吃力, 我相信也会有跟我一样的朋友, 所以写此文, 希望把表达的不清楚的地方能稍微的解释的变清楚一些, 同时加上一些自己对该语法的理解和看法, 当然, 不一定准确, 仅代表个人观点.
#set( $a = "Velocity" )
这个VTL 语句, 像所有的VTL语句一样,通过 # 字符开始并包含一个指令: set. 当一个用户访问你的页面时,Velocity模板 将在你的Web页面中搜索所有的#字符, 然后认为它是VTL语句的开始,但是#字符并没有实际意义。
## 单行注释
vtl中引用分为三种, 变量, 属性, 及方法
当VTL应用一个变量时, 例如$foo,这个变量可以获取一个值从模板的 set指令中, 或者从Java代码中。例如,假如在Java中定义了一个变量foo, java中定义的值就是Web页面中所有的 $foo引用. 或者, 我在页面中定义下面语句 #set( $foo = "bar" ),$foo输出的结果将和你定义的是一样的。
VTL中第二个特点鲜明的引用是属性引用, 属性有一个与众不同的格式. 它的标识符前面需要添加一个$变量标识符, 紧跟着后面一个点(“.”) . 下面是一个在VTL中属性引用的实例: $customer.Address 在vtl中, 我的理解, 它即可以是customer的属性Address, 也可以是customer.getAddress()方法… 比el表达式更强大, 你可以根据需求来返回你需要的值.
方法跟java是一样的, 也是可以传参, 做很多事情
$customer.getAddress() $purchase.getTotal() $page.setTitle( "My Home Page" ) $person.setAttributes( ["Strange", "Weird", "Excited"] )下面的方法可以被属性引用简写
$sun.getPlanets() $annelid.getDirt() $album.getPhoto()但是下面的方法,就不可以简写
## 根据以下数组中参数获取 $sun.getPlanet( ["Earth", "Mars", "Neptune"] ) ## 添加一个fans $user.addFans() ## 设定title $book.setTitle( "Homage to Catalonia" )假如你有一个引用在一个集合上 , 你就可以用集合对象的方法, 比如size,get(index),isEmpty等方法
$myarray.isEmpty() $myarray.size() $myarray.get(2) $myarray.set(1, 'test')后台对象中有一个setPhones(String… phones)的方法, vtl可以这样用 $user.setPhones('13812345678', '15812345670', '18812345671') $user.setPhones() 将会赋一个空数组
正如前面提到的, 属性经常涉及到父类方法的引用. Velocity是十分擅长解决方法对应的属性获取,它可以根据几种不同的命名约定进行选择,准确的查找规则依赖是否属性的名字以大写开始。对于小写名字,例如 $customer.address, 调用的顺序是
getaddress() getAddress() get(“address”) isAddress() 对于大写的属性名字像 $customer.Address, 它稍微不同: getAddress() getaddress() get(“Address”) isAddress()每一个引用的值(变量,属性,或者方法)都被转换为一个字符串并作为最终的输出。假如这里有一个对象表示为$foo (例如一个整数对象), 当Velocity调用它时,Velocity会调用它的.toString() 方法转化为字符串.
$userList[2].name等同于 $userList.get(2).name 一看就明白 $userMap["name"] 等同于userMap.get("name") 跟java代码都是一样的,非常方便
这相同的语法也能够使用在Java数组上因为由于Velocity封装了数组在访问对象上提供了一个get(Integer)方法,它能返回一个特殊的元素。
$foo.bar[1].junk $foo.callMethod()[1] $foo["apple"][4]一个引用也能够通过索引来进行赋值, 例如:
#set($foo[0] = 1) #set($foo.bar[1] = 3) #set($map["apple"] = "orange")在大部分情况下你能够使用标识符引用,但是有些情况下要求正确的符号被要求正确的处理。我认为, 应该尽量用${}来写会比较好 一个简单的例子: Jack is a $vicemaniac. Jack is a ${vice}maniac. 以上两者的变量的引用是不一样的, 这你就应该看懂了, 为什么用正式引用标识符比较好的原因.
当Velocity遇到一个没有定义的引用时,正常的是按照原文输出的. 例如, 假如下面的引用是VTL模板的一部分. <input type="text" name="email" value="${email}"/> 按照道理, 当email没有值时, 我们希望的是value=”“, 但实际上vlt会在无值时输出”$email”…. 这就很尴尬了…相比el表达式就没有这个问题对吧. <input type="text" name="email" value="$!{email}"/> 这么写, 就可以解决这个问题, 在$后加上!就好了..
Velocity引用利用了一些Java的设计原则进行设计,很容易使用。 例如:
$foo.getBar() ## 等价于 $foo.Bar $data.setUser("jon") ## 等价于 #set( $data.User = "jon" ) $data.getRequest().getServerName() ## 等价于 $data.Request.ServerName ## 等价于 ${data.Request.ServerName}指令一直以 #开始.
#if ($userList.size() > 3) 用户多于3人的情况 #else 用户未达标 #end 模板会根据userList的长度, 输出以上两句话中的一句.像引用一样,指令的名字可能是相等的通过{ 和 } 符号. 这是好的方式
#{if} ($userList.size() > 3) 用户多于3人的情况 #{else} 用户未达标 #{end}#set 指令被用来设定一个引用的值. 这个值能够被分配一个变量引用或者属性引用,这种情况发生在括号中, 如下实例:
#set( $primate = "monkey" ) #set( $customer.Behavior = $primate )左边的(LHS)必须分配一个变量引用或者属性引用. 右边的(RHS)可以是以下类型:
Variable reference String literal Property reference Method reference Number literal ArrayList Map其实就跟java一样, 就是赋值左边要写属性, 右边赋值可以是以上几种类型, 下面是关于几种类型赋值的写法, 用时参考就好了:
#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同时右边的值也能使用简单的算术表达式, 这个跟el表达式也是一样的道理:
#set( $value = $foo + 1 ) #set( $value = $bar - 1 ) #set( $value = $foo * $bar ) #set( $value = $foo / $bar )另外 RHS如果是null值 则不会分配个LHS
#set( $result = $query.criteria("name") ) 第一次输出result 的值: $result #set( $result = $query.criteria("address") ) 第二次输出result 的值: $result 如果$query.criteria("name") 的值是张三, 而$query.criteria("address")的值是null的话, 则输出结果是: 第一次输出result 的值: 张三 第二次输出result 的值: 张三 也就是说, 第二次#set指令并没有改变result的值.再看下面的例子, 意图应该:
#set( $monkey = {}) ## 初始化monkey #set( $monkey.name = "猴子" ) ##下面准备遍历这个$monkey的key #set ( $conditionKey = ["name", "food"]) #foreach ($key in $conditionKey) #set ($result = $monkey[$key]) #if ($result) 输出:该key有值 #end #end 输出结果应该是: 该key有值 该key有值 这个结果显然不正确的, 因为$monkey.food 是没有值的 如果要解决这个问题, 那么就需要给$result提前赋值一个false #foreach ($key in $conditionKey) #set ($result = false) #set ($result = $monkey[$key]) #if ($result) 输出:该key有值 #end #end 这样的话, 利用#set指令的特性, 不会赋null值, 则在key == food时, $result的结果依然是false#set指令的时候, 在双引号里面的字符串将被解析, 如下所示: #set( $directoryRoot = "www" ) #set( $templateName = "index.vm" ) #set( $template = "$directoryRoot/$templateName" ) $template 输出结果: www/index.vm 然而, 当字符串处在单引号中, 它将不被解析: #set( $foo = "bar" ) $foo #set( $blargh = '$foo' ) 输出结果: bar $foo
默认情况, 这种特征使用单引号不解析Velocity中的可用变量. 你也可以通过改变velocity.properties 中的stringliterals.interpolate=false配置来改变这种默认设置. 或者, #[[不要解析此段代码]]# 语法准许模板设计者很容易的使用大量的语句块,而这些语句块中的变量不会被解析.
#[[ #foreach ($woogie in $boogie) nothing will happen to $woogie #end ]]# 所以, 以上这段代码就会在页面输出不管从语法, 还是逻辑运算符, 用法同java, 没什么可说的
#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 这就是一组if else基本的写法Velocity 使用等号决定两个变量之间的关系. 下面简单实例展示了等会的怎么使用.
#set ($foo = "deoxyribonucleic acid") #set ($bar = "ribonucleic acid") #if ($foo == $bar) 如果两者相等输出此处 #else 否则输出此处 #endvtl的逻辑操作符同java一样, 并且也有短路的特性, 不懂的补习一下java的基础知识
#if( $foo && $bar ) <strong> This AND that</strong> #end and逻辑操作符, 如果 $foo为false,表达式的结果为 false; $bar将不会计算. 这就是and短路特性 or逻辑操作符, 如果 $foo为true,表达式的结果为 true; $bar将不会计算. 这就是or短路特性上面这是List或者数组的写法, 下面是map的写法
<ul> #foreach( $key in $allProducts.keySet() ) <li>键: $key -> 值: $allProducts.get($key)</li> #end </ul>Velocity提供了一种简单的循环计数以至于你能够做一些事情,如下所示:
<table> #foreach( $customer in $customerList ) <tr><td>$foreach.count</td><td>$customer.Name</td></tr> #end </table>Velocity也提供了一种简单的方式来判断是否是最后一次迭代
#foreach( $user in $userList ) $user.name #if( !$foreach.hasNext ) 我是最后一个了 #end #end如果你想从零开始的#foreach循环, 你可以使用 $foreach.index 代替$foreach.count. 同样的, $foreach.first 和 $foreach.last 也提供了$foreach.hasNext方式.如果你想访问 #foreach外面的这些属性, 你能够引用它们通过 $foreach.parent或 $foreach.topmost 属性 (e.g. $foreach.parent.index 或者 $foreach.topmost.hasNext). 你也可以设置最大的循环执行次数. 默认情况下没有设置 (可以指定一个值 0 或者更小的), 可以设置一个数字在velocity.properties 的配置文件里面. directive.foreach.maxloops = -1
你想停止一个foreach 循环在你的模板中, 你可以使用 #break指令在任何时候停止循环:
#foreach( $customer in $customerList ) #if( $foreach.count > 5 ) #break #end $customer.Name #end#include脚本元素准许设计者引入一个本地文件, 然后插入到你#include 指令所在的地方。文件的内容不经过模板引擎处理. 由于安全的原因,这个文件仅仅能够放在 TEMPLATE_ROOT下面. 引用多个文件: #include( "one.gif","two.txt","three.htm" )
变量也可以作为文件名 #include( "greetings.txt", $seasonalstock )
#parse脚本元素准许模板设计者引用一个包含VTL的本地文件。Velocity将解析其中的VTL并输出里面的元素。 #parse( "me.vm" ) 注意:任何被 #parse 指令引用的模板必须放在TEMPLATE_ROOT下面.