导航菜单
首页 >  模板语法  > velocity(vm)模板引擎学习语法

velocity(vm)模板引擎学习语法

Velocity是一个基于Java的模板引擎(template engine)。它允许任何人仅仅简单的使用模板语言(template language)来引用由java代码定义的对象。velocity与freemaker,jstl并称为 java web 开发三大标签技术。

定义变量#set($app='123')#set($val='456')#set($total=$val+'-'+$app)$val-$app $total

velocity的语法符号大概分二类,一类用#开头,代表控制符号,#set表示定义变量,另一类用$开头,通常用于显示变量,上面的示例定义了三个变量:app值为'123',val值为'456',total值为 '456- 123',第4,5二行输出内容。当VTL应用一个变量时,例如$foo,这个变量可以获取一个值从模板的 set指令中,或者从Java代码中。例如:假如在Java中定义了一个变量foo, java中定义的值就是Web页面中所有的$foo引用。或者,我在页面中定义下面语句#set( $foo = "bar" ),$foo输出的结果将和你定义的是一样的。

遍历数组#set($list = ['CTU','SHA','LAX'])#foreach($item in $list)$velocityCount . $item #end

定义了一个数组,然后遍历输出,其中velocityCount为索引变量

VTL语法详解

#set( $a = "Velocity" )上面的VTL语句,通过#字符开始并包含一个指令:set。当一个用户访问你的页面时,Velocity 模板将在你的web页面中搜索所有的#字符,然后认为它是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('123', '456', '789') $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")正式引用标识符 很重要

在大部分情况下你能够使用标识符引用,但是有些情况下要求正确的符号被要求正确的处理。我认为,应该尽量用${}来写会比较好一个简单的例子:Java is a $vicemaniac.Jack is a ${vice}maniac.以上两者变量的引用是不一样的,通过上述例子可以看出为什么用正式标识符比较好的原因。

静态引用标识符

当 Velocity 遇到一个没有定义的引用时,正常的是按照原文输出的。例如:假如下面的引用是 VTL 模板的一部分。按照道理,当 email 没有值时,我们希望的是 value="",但实际上 vlt 会在无值时输出$email...这就很尴尬了,相比el表达式就没有这个问题。这么写,就可以解决这个问题,在 $后加上!就好了

模式替换或者说多种写法

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 referenceString literalProperty referenceMethod referenceNumber literalArrayListMap

其实就跟 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' )$blargh输出结果:bar$foo

默认情况,这种特征使用单引号不解析 Velocity 中的可用变量。你也可以通过改变 velocity.properties 中的stringliterals.interpolate=false 配置来改变这种默认设置。或者,#[[不要解析此段代码]]#语法准许模板设计者很容易的使用大量的语句块,而这些语句块中的变量不会被解析。

#[[#foreach ($woogie in $boogie) nothing will happen to $woogie#end]]#所以, 以上这段代码就会在页面输出条件语句

If / Elself / Else不管从语法,还是逻辑运算符,用法同 Java,没什么可说的

#if ( $foo < 10 )Go North#else if( $foo == 10 )Go East#else if( $bar == 6 )Go South#elseGo West#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 ) This AND that #endand逻辑操作符,如果 $foo为false,表达式的结果为false; $bar将不会计算。这就是and 短路特性or 逻辑操作符,如果 $foo为true,表达式的结果为 true;$bar 将不会计算。这就是or短路特性。循环#foreach 元素用来循环操作#foreach( $product in $allProducts )$product#end#foreach循环 $allProducts列表。每次遍历,$allProducts 里面的单个值将被赋值给$product。

上面这是List 或者数组的写法,下面是 map 的写法

#foreach( $key in $allProducts.keySet() )键:$key -> 值:$allProducts.get($key)#end

Velocity 提供了一种简单的循环计数以至于你能够做一些事情,如下所示:

#foreach( $customer in $customerList )$foreach.count$customer.Name#end

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下面.

相关推荐: