您的位置:首页 > Web前端 > HTML

【笔记】Velocity 语法笔记

2017-08-06 23:24 513 查看
set

注释
单行注释

多行注释

多行文档注释

引用
变量

属性

方法
VTL方法和属性的区别

支持可变参数

属性调用规则

渲染

索引标识符

正式引用标识符 很重要

静态引用标识符

模式替换或者说多种写法

指令
set指令

字面量 字符串的操作

条件语句
If ElseIf Else

关系和逻辑操作符

逻辑操作符 AND OR 和NOT 操作符

循环
foreach元素用来循环操作

引入

解析

前言

在参考官方的翻译文档时, 很多语句的翻译的还有点生硬, 而且我在学的过程中有些地方读起来很吃力, 我相信也会有跟我一样的朋友, 所以写此文, 希望把表达的不清楚的地方能稍微的解释的变清楚一些, 同时加上一些自己对该语法的理解和看法, 当然, 不一定准确, 仅代表个人观点.

set

#set( $a = "Velocity" )


这个VTL 语句, 像所有的VTL语句一样,通过 # 字符开始并包含一个指令: set. 当一个用户访问你的页面时,Velocity模板 将在你的Web页面中搜索所有的#字符, 然后认为它是VTL语句的开始,但是#字符并没有实际意义。

注释

单行注释

## 单行注释


多行注释

#*
多行注释, Velocity会忽略此段
*#


多行文档注释

#**
这种注释类似于javadoc
@author  somebody
@version 1.7
*#


引用

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"] )


VTL方法和属性的区别

VTL 属性引用能够被当着方法引用的简写. 属性 $customer.Address 引用和 $customer.getAddress()方法的引用效果是一样的. 一般情况下如果可以,我们通过简写的方式来引用方法.属性和方法主要不同是方法能够引用参数 .


下面的方法可以被属性引用简写

$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()


渲染

每一个引用的值(变量,属性,或者方
4000
法)都被转换为一个字符串并作为最终的输出。假如这里有一个对象表示为$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
指令被用来设定一个引用的值. 这个值能够被分配一个变量引用或者属性引用,这种情况发生在括号中, 如下实例:

#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
]]#
所以, 以上这段代码就会在页面输出


条件语句

If / ElseIf / Else

不管从语法, 还是逻辑运算符, 用法同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
否则输出此处
#end


逻辑操作符 AND, OR 和NOT 操作符.

vtl的逻辑操作符同java一样, 并且也有短路的特性, 不懂的补习一下java的基础知识

#if( $foo && $bar )
<strong> This AND that</strong>
#end
and逻辑操作符, 如果 $foo为false,表达式的结果为 false; $bar将不会计算. 这就是and短路特性
or逻辑操作符, 如果 $foo为true,表达式的结果为 true; $bar将不会计算. 这就是or短路特性


循环

#foreach元素用来循环操作

<ul>
#foreach( $product in $allProducts )
<li>$product</li>
#end
#foreach循环 $allProducts列表 . 每次遍历, $allProducts 里面的单个值将被赋值给$product.
</ul>


上面这是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下面.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息