velocity 获取list对象_Velocity语法教程

1.简介

Velocity是一款基于Java的模板引擎。它允许Web页面设计者引用Java代码中定义的方法。Web设计者能与根据Model-View-Controller (MVC)模型开发Web网站的Java程序员合作,意味着Web页面设计者能将注意力放在创建设计精良的网站,而程序员能将注意力放在编写代码上。Velocity从Web页面中分离Java代码,使Web网站在长时间运行时更可维护性和提供Java Server Pages(JSP)或PHP的替代方案。

Velocity能用于从模板产生Web页面、SQL、PostScript和其它输出。它能用于作为单独的工具类生成源码和报表,或作为其它系统的一个整合组件。Velocity将为Turbine Web应用程序框架提供模板服务。Velocity+Turbine将提供模板服务允许Web应用程序根据真实MVC模型开发。

2.安装

  • JDK(必须)

  • Jakarta Commons Collections(必须)

  • Jakarta Commons Lang(必须)

  • Excalibur(ex-Avalon)Logkit(可选,如果使用默认的基于文件的日志时需要)

  • Jakarta ORO(可选,当使用org.apache.velocity.convert.WebMacro模板转换工具或org.apache.velocity.app.event.implement.Escape Reference ReferenceInsertionEventHandler时使用)

3.实践

3.1 基本步骤

  • 初始化Velocity

  • 创建Context对象

  • 添加数据对象到Context

  • 选择模板

  • “合并”模板和数据产生输出

3.2 单例

模板:

bfab997c5308a9c5c85e6c6327a532c6.png

代码:

Velocity.init();VelocityContext context = new VelocityContext();context.put( "word", "Hello Velocity!");// 模板路径默认是当前项目的根目录Template template = Velocity.getTemplate("src/main/java/com/study/velocity/HelloWord.vm");StringWriter sw = new StringWriter();template.merge(context, sw);System.out.println(sw);

3.3 多例

与单例不同,多例可以在用一个JVM或Web应用程序中维护多组配置。

VelocityEngine ve = new VelocityEngine();ve.init();Template t = ve.getTemplate("src/main/java/com/study/velocity/HelloWord.vm");StringWriter sw = new StringWriter();VelocityContext context = new VelocityContext();context.put( "word", "Hello Velocity!");t.merge(context, sw);System.out.println(sw);

4.注释

注释一向是一门编程语言的必须成员,没有注释的代码不能称之为好代码。注释允许放

置描述文本在模板引擎中。注释通常用于提示自己和解释别人VTL(VelocityTemplate Language)语句在做什么。

Velocity包含三种注释:

  • 单行注释

  • 多行注释

  • 文档注释

4.1 单行注释

单行注释以 ## 开始,从被注释的位置开始到行结尾的所有字符将不被模板引擎解析。

## 这是单行注释

4.2 多行注释

以 #* 开始,*#结尾,中间的内容不被模板引擎解析。

#* 这是多行注释*#

4.3 文档注释

类似于JavaDoc注释,用于存储各种额外信息。

#**这是文档注释@author  赵凡@version  1.0*#

5.引用

在VTL中,有三种类型的引用:变量、属性和方法。

5.1 变量

变量的速记符号由前导“$”字符后随VTL标识符组成。VTL标识符必须以字母开头,合法字符包含:

  • 字母

  • 数值

  • 连字符

  • 下划线

下面是VTL中有效的变量引用:

$foo$mudSlinger$mud-slinger$mud_slinger$mudSlinger1

当VTL引用一个变量时,例如$foo,变量能从模板中的set指令或Java代码中的Context获取值。

#set( $word = "Hello Velocity!" )${word}
5.2 属性

代码:

Velocity.init();VelocityContext context = new VelocityContext();User user = new User();user.setUsername("xxxx");context.put( "user", user);Template template = Velocity.getTemplate("src/main/java/com/study/velocity/Properties.vm");StringWriter sw = new StringWriter();template.merge(context, sw);System.out.println(sw);public class User {    private String username;    public String getUsername() {        System.out.println("do get");        return username;    }    public void setUsername(String username) {        this.username = username;    }}
模板:
$user.username
输出结果:
do getxxxx
由上面的结果表明,$user.username调用的就是user的getUsername方法。

5.3 方法

方法引用由前导“$”字符后随VTL标识符和VTL方法体。VTL方法体由VTL标识符后随左圆括号、可选参数列表、右圆括号。下面是有效的VTL:

$sun.getPlanets()$annelid.getDirt()$album.getPhoto()$sun.getPlanet( ["Earth", "Mars", "Neptune"] )$sisyphus.pushRock()$book.setTitle( "Homage to Catalonia" )
5.4 属性查找规则

就像前面所说的,属性通常引用父对象的方法。Velocity很聪明,计算请求属性的方法。它基于命名规则查找方法。期望的查找序列依赖于是否属性名开始与大写字母。对于小写字母,例如$customer.address的顺序是:

getaddress()getAddress()get("address")isAddress()
对于大写字母稍有不同:
getAddress()getaddress()get("Address")isAddress()
5.5 渲染

每个引用(无论变量、属性或方法)最后产生的值转换为字符串对象。如果一个对象是Integer,那么Velocity将调用它的.toString()方法解析对象为字符串。

5.6 下标表示法

使用下标形式$foo[0]能用于访问指定索引的对象。这种形式的同义词在指定对象上调用get(Object)方法上一致,例如$foo.get(0)

$foo[0]       ## $foo takes in an Integer look up$foo[$i]      ## Using another reference as the index$foo["bar"]   ## Passing a string where $foo may be a Map

括号语法也适用于Java数组,因为Velocity包装数组在访问对象中,提供get(Integer)

方法返回指定元素。

括号语法在任何适用.get的地方都是有效的,例如:

$foo.bar[1].junk$foo.callMethod()[1]$foo["apple"][4]
引用也可以使用索引设置,例如:
#set($foo[0] = 1)#set($foo.bar[1] = 3)#set($map["apple"] = "orange")
5.7 正规引用符号

上面的引用符号都是缩写,正式的引用符号如下所示:

${mudSlinger}${customer.Address}${purchase.getTotal()}
大多数情况下,可以使用缩写,但是在一种情况下,必须使用正式写法。
Jack is a $vicemaniac.

上面的例子中,变量是vicemaniac,但是我们实际想要的是vice,此时,我们可以在变

量前后加上中括号来表示这个变量。

Jack is a ${vice}maniac.
5.8 处理未定义引用

当Velocity遇到了未定义的引用时,默认会原样输出引用。可以使用以下方式使其输出

空串。

$!email$!{email}

Velocity 1.6引入严格引用模式的概率,通过设置Velocity配置属性

"runtime.references.strict”为true激活。在未定义或歧义的情况下,Velocity将抛出异常。使用该设置引用必须明确放置在context中或使用#set指令定义或抛异常。

引用在context中有一个null值将不会产生一个异常。此外,如果试图调用不存在的方

法或属性将抛出异常。如果试图调用的对象是null抛出异常。

在下面的例子中,$bar已定义,$foo未定义,所有这些语句将抛出异常:

$foo                         ## Exception#set($bar = $foo)            ## Exception#if($foo == $bar)#end        ## Exception#foreach($item in $foo)#end  ## Exception

当试图调用的方法或属性不存在时Velocity抛出异常。在这种情况下,$bar包含一个对

象定义一个属性"foo"返回一个字符串,而retnull防御null。

$bar.bogus          ## $bar没有bogus属性,Exception$bar.foo.bogus      ## $bar.foo没有bogus属性,Exception$bar.retnull.bogus  ## 不能在null上调用属性,Exception
#if和#elseif指令中的引用比较特殊:
#if ($foo)#end                  ## False#if ( ! $foo)#end               ## True#if ($foo && $foo.bar)#end      ## False并且$foo.bar将不会计算#if ($foo && $foo == "bar")#end ## False并且$foo == "bar"将不会计算#if ($foo1 || $foo2)#end        ## False $foo1并且$foo2将不会计算

严格模式必须在#if指令中包含>、=或<=。同时,参数#foreach必须迭代(该行

为能修改属性 directive.foreach.skip.invalid)。最后,在严格模式下,未定义宏引用

也将抛出异常。

this is $foo    ## 抛出异常,因为$foo是nullthis is $!foo   ## 渲染为"this is "没有异常this is $!bogus ## bogus不在context中,因此抛出异常

6.指令

指令允许模板设计者生成Web网站的动态内容,而指令——易于使用脚本元素能用于创建操作Java代码输出——允许Web设计者真正负责Web网站的外观和内容。

指令总是以#开始。如同引用,指令的名字可以通过{和}符号括起来。通常文本紧随其后。例如以下产生错误:

#if($a==1)true enough#elseno way!#end
在这种情况下,使用花括号分隔#else。
#if($a==1)true enough#{else}no way!#end
6.1 #set

#set指令用于设置引用的值。值能复制给变量引用或属性引用,这发生在括号中:

#set( $primate = "monkey" )#set( $customer.Behavior = $primate )
等于号左边必须是一个变量引用或属性引用。右边可以是以下类型:
  • 变量引用

  • 字符串字面值

  • 属性引用

  • 方法引用

  • 数值字面值

  • 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($w#set( $monkey = $bill ) ## variable reference#set( $eb) ) ## 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例子中的元素使用[...]定义操作符,定义在ArrayList类中的方法都可以

访问。因此,例如,你可以使用$monkey.Say.get(0)访问第一个元素。类似,Map的例子,元素定义在{}操作符中,可以使用定义在Map类中的方法访问。因此,例如,你可以使用$monkey.Map.get("banana")访问第一个元素返回一个字符串"good",或$monkey.Map.banana返回相同值。等号右边也可以是简单的算术表达式:

#set( $value = $foo + 1 )#set( $value = $bar - 1 )#set( $value = $foo * $bar )#set( $value = $foo / $bar )

如果右边是计算为null的属性或方法引用,它将不赋值给左边。依赖于Velocity的配置,通常这种机制不能够删除已存在的引用。

#set( $result = $query.criteria("name") )第一个查询的结果是$result#set( $result = $query.criteria("address") )第二个查询的结果是$result

如果$query.criteria("name")返回字符串“bill”,而$query.criteria("address")返回null,上面VTL将渲染为:

第一个查询的结果是bill第二个查询的结果是bill
6.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。#[[不解析我!]]#语法允许模板设计者易于在VTL代码中使用大块的不解释和不解析内容。

#[[#foreach ($woogie in $boogie)  nothing will happen to $woogie#end]]#
渲染为:
#foreach ($woogie in $boogie)  nothing will happen to $woogie#end

7.条件指令

7.1 if/elseif/else

在Velocity中,#if指令允许在if语句条件为true时包括文本。例如:

#if( $foo )   Velocity!#end
变量$foo计算决定是否为true,这三种情况下将发生什么:
  • $foo是boolean(true/false),为true

  • $foo是字符串或集合,不为null和不为空

  • $foo是一个不为null的对象(除了字符串或集合)

记住,Velocity context只包含Object,因此,当我们说"boolean",它将表示为Boolean(类)。

如果条件为true,#if和#end语句之间的内容变成输出。在这种情况下,如果$foo是true,输出将是:“Velocity!”。相反的,如果$foo有一个null值,或者有一个boolean false,条件为false,那么没有输出。

#elseif或#else语句能与#if语句连用。注意,Velocity模板引擎将在第一个条件表达式为true的语句终止。在以下例子中,假设$foo为15,$bar为6.

#if( $foo < 10 )    Go North#elseif( $foo == 10 )    Go East#elseif( $bar == 6 )    Go South#else    Go West#end

在该例子中,$foo大于10,因此前面两个比较失败。接下来$bar与6比较为true,因此输出时Go South。

7.2 关系和逻辑运算符

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中,

等价运算符能直接用于比较数值、字符串或对象。当对象是不同的类时,通过调用每

个对象的toString()获取字符串表现形式然后比较。

Velocity也有逻辑AND、OR和NOT运算符。下面例子演示,使用逻辑AND、OR和NOT运算符。

## 逻辑AND#if( $foo && $bar )    This AND that#end## 逻辑OR#if( $foo || $bar )    This OR That#end##逻辑NOT#if( !$foo )  NOT that#end

这些逻辑运算符与Java中的逻辑运算符一致,此处不再累述。需要注意的是$!foo不会

应为foo为null而报错。逻辑运算符也有自己的文本形式的版本:eq、ne、and、or、

not、gt、ge、lt和le。

8.循环指令

Velocity模板支持各种集合类型的迭代。

  • Object[] Velocity包装数据对象到迭代对象中,可以将其当做固定长度的List,可调用size()、isEmpty()和get(int)。

  • java.util.Collection Velocity将使用iterator()方法获取一个Iterator用于循环,因此,如果你实现了Collection接口,请确保iterator()返回一个Iterator。

  • java.util.Map Velocity依赖接口的values()方法获取一个Collection接口,调用iterator()方法检索Iterator用于循环。

  • java.util.Iterator、java.util.Enumeration 只是暂时支持。

  • 任意不返回null的public Iterator iterator()方法。

8.1 Map

迭代Map中的Key,通过Key获取Map中的元素,来带到迭代的功能。

#foreach( $key in $allProducts.keySet() )    Key: $key -> Value: $allProducts.get($key)#end

8.2 集合

Velocity可以通过简单的方式获取循环中的计数器。

<table>#foreach( $customer in $customerList )    <tr><td>$foreach.counttd><td>$customer.Nametd>tr>#endtable>

Velocity也可以通过简单的方式告诉你,是否是最后一次循环。

#foreach( $customer in $customerList )    $customer.Name#if( $foreach.hasNext ),#end#end

如果你想要#foreach循环一个基于0的索引,你能使用$foreach.index替$foreach.count。同样,提供$foreach.first和$foreach.last。如果你想要访问外部循环的#foreach循环的属性,你能直接通过$foreach.parent或$foreach.topmost属性引用它们(例如,$foreach.parent.index或$foreach.topmost.hasNext)。可以设置循环允许执行的最大次数。默认没有最大值(表示为0或更小),但这能在velocity.properties文件中设置为任意数值。

directive.foreach.maxloops = -1

如果你想要终止foreach,你现在能使用#break指令终止循环。

## list first 5 customers only#foreach( $customer in $customerList )    #if( $foreach.count > 5 )        #break    #end    $customer.Name#end
9 导入外部文 件 Velocity有两种方式从外部引入文件: 包括和解析。

9.1 包括

#include脚本元素允许模板设计者导入本地文件,然后插入到#include指令定义的位置。文件的内容通过模板引擎渲染。由于安全原因,文件只能包含在TEMPLATE_ROOT。

#include("one.txt")

#include指令引用的文件被封闭在双引号中。如果多个文件被include,应该通过逗号分隔。

#include("one.gif","two.txt","three.htm")
可以使用变量替换文件名作为参数。
#include("greetings.txt", $seasonalstock)
9.2 解析

#parse脚本元素允许模板设计者导入包含VTL的本地文件。Velocity将解析VTL并渲染

模板。

#parse("me.vm")

像#include指令一样,#parse可以传入一个变量而不是模板。任意引用的模板必须在TEMPLATE_ROOT中。和#include指令不同,#parse只需要一个参数。VTL模板可以在模板中递归使用#parse引用。velocity.properties中的directive.parse.max.depth属性允许用户自定义最大递归数,默认设置为10。

(如果velocity.properties文件中没有出现directive.parse.max.depth,Velocity将默认设置为10)。

Count down.#set( $count = 8 )#parse( "parsefoo.vm" )All done with dofoo.vm!
引用的模板:
$count#set( $count = $count - 1 )#if( $count > 0 )    #parse( "parsefoo.vm" )#else    All done with parsefoo.vm!#end

10.宏调用

#macro脚本元素允许模板设计者定义重复的VTL模板片段。宏调用在简单和复杂的场

景中非常广泛。

定义宏:

#macro( d )#end
调用宏:
#d()
定义有体的宏,$!bodyContent为宏体:
#macro( d )<tr><td>$!bodyContenttd>tr>#end
调用有体的宏:
#@d()Hello!#end
定义带参数的宏:
#macro( tablerows $color $somelist )#foreach( $something in $somelist )    $something#end#end
调用带参数的宏:
#set( $greatlakes = ["Superior","Michigan","Huron","Erie","Ontario"] )#set( $color = "blue" )
#tablerows( $color $greatlakes )
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值