英文來源: http://jakarta.apache.org/velocity/docs/user-guide.htmlhtml
關於這個用戶手冊java
Velocity用戶手冊是幫助頁面設計者和內容提供者認識Velocity和其簡單而功能強大的腳本語言――Velocity模板語言(VTL)。在手冊上的許多例子,都是用Velocity插入動態的內容到網頁上,可是全部的VLT例子都能應用到其餘的頁面和模板中。web
感謝使用 Velocity!數據庫
Velocity是什麼?apache
Velocity是一個基於java的模板引擎(template engine)。它容許任何人僅僅簡單的使用模板語言(template language)來引用由java代碼定義的對象。api
當Velocity應用於web開發時,界面設計人員能夠和java程序開發人員同步開發一個遵循MVC架構的web站點,也就是說,頁面設計人員能夠只關注頁面的顯示效果,而由java程序開發人員關注業務邏輯編碼。Velocity將java代碼從web頁面中分離出來,這樣爲web站點的長期維護提供了便利,同時也爲咱們在JSP和PHP以外又提供了一種可選的方案。數組
Velocity的能力遠不止web站點開發這個領域,例如,它能夠從模板(template)產生SQL和PostScript、XML,它也能夠被看成一個獨立工具來產生源代碼和報告,或者做爲其餘系統的集成組件使用。Velocity也能夠爲Turbine web開發架構提供模板服務(template service)。Velocity+Turbine提供一個模板服務的方式容許一個web應用以一個真正的MVC模型進行開發。緩存
Velocity能爲咱們做什麼?安全
Mud 商店例子架構
假設你是一家專門出售Mud的在線商店的頁面設計人員,讓咱們暫且稱它爲「在線MUD商店」。大家的業務很旺,客戶下了各類類型和數量的mud訂單。他們都是經過輸入用戶名和密碼後才登錄到你的網站,登錄後就容許他們查看訂單併購買更多的mud。如今,一種很是流行的mud正在打折銷售。另外有一些客戶規律性的購買另一種也在打折可是不是很流行的Bright Red Mud,因爲購買的人並很少因此它被安置在頁面的邊緣。全部用戶的信息都是被跟蹤並存放於數據庫中的,因此某天有一個問題可能會冒出來:爲何不使用velocity來使用戶更好的瀏覽他們感興趣的商品呢?
Velocity使得web頁面的客戶化工做很是容易。做爲一個web site的設計人員,你但願每一個用戶登錄時都擁有本身的頁面。
你會見了一些公司內的軟件工程師,你發現他們每一個人都贊成客戶應該擁有具備個性化的信息。那讓咱們把軟件工程師應該做的事情發在一邊,看一看你應該做些什麼吧。
你可能在頁面內嵌套以下的VTL聲明:
<HTML>
<BODY>
Hello $customer.Name!
<table>
#foreach( $mud in $mudsOnSpecial )
#if ( $customer.hasPurchased($mud) )
<tr>
<td>
$flogger.getPromo( $mud )
</td>
</tr>
#end
#end
</table>
foreach 的詳細用法不久就會進行深刻描述。重要的是,這短小的腳本能在你的網站上出現。當一個對Bright Red Mud 很感興趣的顧客登錄的時候,同時Bright Red Mud在熱賣中,這時顧客就能顯著地看到。假如一個玩Terracotta Mud好久的顧客登錄,Terracotta Mud 的售賣信息就會出如今前面中間。Velocity的適用性是很巨大的,限制的只是你的創造性。
VTL Reference 含有許多其餘Velocity元素,這些元素可以共同幫助你,使你的網站更加好。當你愈來愈熟悉那些原理,你開始釋放Velocity的能力。
Velocity模板語言(VTL):說明
VTL意味着提供最簡單、最容易而且最整潔的方式合併頁面動態內容。VTL使用references來在web site內嵌套動態內容,一個變量就是一種類型的reference。變量是某種類型的refreence,它能夠指向java代碼中的定義,或者從當前頁面內定義的VTL statement獲得值。下面是一個VTL statement的例子,它能夠被嵌套到HTML代碼中:
#set( $a = "Velocity" )
和全部的VTL statement同樣,這個statement以#字符開始而且包含一個directive:set。當一個在線用戶請求你的頁面時,Velocity 模板引擎將查詢整個頁面以便發現全部#字符,而後肯定哪些是VTL statement,哪些不須要VTL做任何事情。
#字符後緊跟一個directive:set時,這個set directive使用一個表達式(使用括號封閉)――一個方程式分配一個值給變量。變量被列在左邊,而它的值被列在右邊,最後他們之間使用=號分割。
在上面的例子中,變量是$a,而它的值是Velocity。和其餘的references同樣以$字符開始,而值老是以雙引號封閉。Velocity中僅有String能夠被賦值給變量。
使用$字符開始的references用於獲得什麼;使用#字符開始的directives用於做些什麼。在上面的例子中,#set是分配一個值給變量。變量$a 在模板中輸出 "Velocity"。
Hello Velocity World!
一旦某個變量被分配了一個值,那麼你就能夠在HTML文件的任何地方引用它。在下面的例子中,一個值被分配給$foo變量,並在其後被引用。
<html>
<body>
#set( $foo = "Velocity" )
Hello $foo World!
</body>
<html>
上面的實現結果是在頁面上打印「Hello Velocity World!」
爲了使包含VTL directives的statement更具備可讀性,咱們鼓勵你在新行開始每一個VTL statement,儘管你不是必須這麼做。Set的用法將在後面詳細描述。
註釋
註釋是那些描述文本不出如今模板引擎輸出裏面。註釋一個主要用處是提醒本身和解釋出如今VTL中的聲明,或是其餘用途。下面是一個在VLT中的註釋例子。
## This is a single line comment.
單行註釋以##開始,結束在這行的結尾。若是你要寫幾行註釋,這沒有必要寫幾個單行註釋。
多行註釋,以#*開始*#結束,能夠解決這個問題。
This is text that is outside the multi-line comment.
Online visitors can see it.
#*
Thus begins a multi-line comment. Online visitors won't
see this text because the Velocity Templating Engine will
ignore it.
*#
Here is text outside the multi-line comment; it is visible.
這裏有幾個例子關於單行和多行註釋如何工做。
This text is visible. ## This text is not.
This text is visible.
This text is visible. #* This text, as part of a multi-line comment,
is not visible. This text is not visible; it is also part of the
multi-line comment. This text still not visible. *# This text is outside
the comment, so it is visible.
## This text is not visible.
這裏有第三種類型的註釋,VLT註釋塊,可能用於存放文檔的做者名稱和版本信息。
#**
This is a VTL comment block and
may be used to store such information
as the document author and versioning
information:
@author
@version 5
*#
References
在VTL中有三種類型的references:變量(variables)、屬性(properties)、方法(methods)。做爲一個使用VTL的頁面設計者,你和你的工程師必須就references的名稱達成共識,以便你能夠在你的template中使用它們。
全部的 reference被做爲一個String對象處理。若是有一個對象$foo是一個Integer對象,那麼Velocity將調用它的toString()方法將這個對象轉型爲String類型。
變量
非正式變量是由「$」開頭,接着是VTL標識符。VLT標識符必須以字母(a..z,A..Z)開頭。剩下的部分限於如下幾種:
l 字母(a..z,A..Z)
l 數字(0..9)
l 連字符(「-」)
l 下劃線(「_」)
這裏是幾個在VTL中有效的變量reference。
$foo
$mudSlinger
$mud-slinger
$mud_slinger
$mudSlinger1
當VLT定義一個變量,例如$foo,變量能或者經過模板中的set 方法,或者經過Java 代碼得到值。
例如,Java 變量 $foo 的值是 bar ,在這個模板被請求時,在網頁上 bar 會替代全部 $foo 。選擇地,假如包括了下面的聲明:
#set( $foo = "bar" )
按照這樣的設置,輸出就會跟以前的同樣。
屬性
第二種有趣的VTL reference就是屬性,並且屬性有一種不同凡響的格式。非正式變量是由「$」開頭,接着是VTL標識符,再接着就是字符(「.」)和其餘的VLT標識符。這裏是一些在VLT中有效屬性的定義:
$customer.Address
$purchase.Total
在第一個例子中$customer.Address有兩種含義。它能夠表示:查找hashtable對象customer中以Address爲關鍵字的值;也能夠表示調用customer對象的getAddress()方法。當你的頁面被請求時,Velocity將肯定以上兩種方式選用那種,而後返回適當的值。
方法
一個方法就是被定義在java中的一段代碼,而且它有完成某些有用工做的能力,例如一個執行計算和判斷條件是否成立、知足等。方法是一個由$開始並跟隨VTL標識符組成的References,通常還包括一個VTL方法體。一個VTL方法體包括一個VLT標識接着一個左括號(「(」),接着是參數列表,再接着是右括號(「)」)。這裏是一些在VTL中有效的方法定義:
$customer.getAddress()
$purchase.getTotal()
$page.setTitle( "My Home Page" )
$person.setAttributes( ["Strange", "Weird", "Excited"] )
前兩個例子$customer.getAddress()和$purchase.getTotal()看起來挺想上面的屬性$customer.Address 和 $purchase.Total。若是你以爲他們之間有某種聯繫的話,那你是正確的。
VTL屬性能夠做爲VTL方法的縮寫。$customer.Address屬性和使用$customer.getAddress()方法具備相同的效果。若是可能的話使用屬性的方式是比較合理的。屬性和方法的不一樣點在於你可以給一個方法指定一個參數列表。
非正式定義可以用下面的方法:
$sun.getPlanets()
$annelid.getDirt()
$album.getPhoto()
咱們期待那些方法返回屬於太陽系的行星的名稱,餵養咱們的蚯蚓,或者從相冊裏面取出一張照片。只有長符號爲下面的方法服務。
$sun.getPlanet( ["Earth", "Mars", "Neptune"] )
## Can't pass a parameter list with $sun.Planets
$sisyphus.pushRock()
## Velocity assumes I mean $sisyphus.getRock()
$book.setTitle( "Homage to Catalonia" )
## Can't pass a parameter list
正式reference標記
非正式references用於上述的例子中。可是一樣有正式的references,以下面所示:
${mudSlinger}
${customer.Address}
${purchase.getTotal()}
在幾乎全部場合你均可以使用非正式references,可是在某些場合,只能使用正式reference 才能正確處理。
設想你建立一個句子:$vice 做爲句子的名詞 。目標是爲了使某些人選擇不一樣的詞,產生下面兩種結果之一:"Jack is a pyromaniac." 或者 "Jack is a kleptomaniac."。使用非正式定義不太適合用於這種狀況。看一下下面的例子:
Jack is a $vicemaniac.
原本變量是$vice如今卻變成了$vicemaniac,這樣Veloctiy就不知道您到底要什麼了。因此,應該使用正是格式書寫
Jack is a ${vice}maniac.
如今Velocity就知道reference 是$vice,而不是$vicemaniac。正式定義常常用於模板中refernces與文本鏈接在一塊兒的狀況。
Quiet reference notation
當Velocity遇到沒有定義的reference,一般它會直接輸出reference。例如:假以下面的reference出如今一個VTL模板中:
<input type="text" name="email" value="$email"/>
當 form 最初加載的時候,變量$email 沒有值,但你想出現一個空白的文本框設定值爲「$email」。
使用quiet reference notation可使Velocity正常顯示,你須要用$!email ,代替$email。因此上面的例子,會改爲下面:
<input type="text" name="email" value="$!email"/>
這樣文本框的初始值就不會是email而是空值了。
正式和quiet格式的reference notation也可一同使用,像下面這樣:
<input type="text" name="email" value="$!{email}"/>
Getting literal
Velocity使用特殊字符$和#來幫助它工做,因此若是要在template裏使用這些特殊字符要格外當心。本節將討論$字符。
貨幣字符
這是沒有問題的:"I bought a 4 lb. sack of potatoes at the farmer's market for only $2.50!",VTL中使用$2.5這樣的貨幣標識是沒有問題得的,VTL不會將它錯認爲是一個reference,由於VTL中的reference老是以一個大寫或者小寫的字母開始。
Escaping valid VTL reference
某些狀況使用Velocity可能會以爲很煩惱。逃避特殊符是處理出如今你的模板中VTL特殊符有效方法,就是使用反斜槓(「\」)。
#set( $email = "foo" )
假如Velocity在你的模板中遇到 $email ,它會搜索上下文,獲得相應的值。這裏的輸出是 foo ,由於 $email 被定義了。假如 $email 沒有被定義,輸出會是 $email 。
設想 $email 被定義了(例如,它的值是 foo ),並且你想輸出 $email 。這裏有幾種方法能達到目的,可是最簡單的是使用逃避符。
## The following line defines $email in this template:
#set( $email = "foo" )
將顯示爲:
foo
\foo
注意到 「\」 屏蔽了左邊的 「$」。屏蔽左邊規則,使得 \\\$email 顯示爲 \\$email 。那些例子與 $email沒有定義相比較。
將顯示爲:
注意Velocity處理 定義了的references 與沒有定義的不同。這裏 set $foo 的值爲 gibbous。
#set( $foo = "gibbous" )
$moon = $foo
輸出會是:$moon = gibbous ,$moon 按照字面上輸出由於它沒有定義,gibbous 替代 $foo 輸出。
避開VTL的 directives 還有其餘方法,在 Directives 那章節會更詳細描述。
Case substitution
如今你已經對reference比較熟悉了,你能夠將他們高效的應用於你的template了。Velocity利用了不少java規範以方便了設計人員的使用。例如:
$foo
$foo.getBar()
## is the same as
$foo.Bar
$data.getUser("jon")
## is the same as
$data.User("jon")
$data.getRequest().getServerName()
## is the same as
$data.Request.ServerName
## is the same as
${data.Request.ServerName}
那些例子說明了一樣的references 用法。Velocity 利用Java的 instrospection 和 bean features解決 reference 的名稱對於對象和對象方法的問題。它能夠出入你的模板中和求出 references 的值。
Velocity 是模仿Sun微系統中的Bean規範定義的,於是它是很靈活的。然而,它的開發者已經很努力地捕捉和糾正可能出現的錯誤。當方法 getFoo() 在模板中 被 $bar.foo調用時,Velocity首先嚐試 $getfoo。若是失敗,它會繼續嘗試 $getFoo。一樣地,當模板查詢 $bar.Foo,Velocity會先嚐試 $getFoo(),而後再嘗試 $getfoo()。
可是,注意VTL中不會將reference解釋爲對象的實例變量。例如:$foo.Name將被解釋爲Foo對象的getName()方法,而不是Foo對象的Name實例變量。
Directives
Reference容許設計者使用動態的內容,而directive使得你能夠應用java代碼來控制你的顯示邏輯,從而達到你所指望的顯示效果。
#set
#set標誌是用於對一個reference賦值。值會賦給一個變量或者一個屬性,並且賦值會在括號裏出現:
#set( $primate = "monkey" )
#set( $customer.Behavior = $primate )
左邊(LHS) 必定是一個變量或者一個屬性。右邊(RHS)能夠是下面中的一個類型:
l 變量
l 字符串
l 屬性
l 方法
l 數字
l 數組
這些例子顯示上述的每一種類型:
#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
注意:最後一個例子的取值方法爲:$monkey.Say.get(0)。
RHS也能夠是一個簡單的算術表達式:
#set( $value = $foo + 1 )
#set( $value = $bar - 1 )
#set( $value = $foo * $bar )
#set( $value = $foo / $bar )
若是你的RHS是一個null,VTL的處理將比較特殊:它將指向一個已經存在的reference,這對初學者來說多是比較費解的。例如:
#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,則顯示的結果以下:
The result of the first query is bill
The result of the second query is bill
這容易使新手糊塗:建立一個#foreach循環,企圖想經過一個屬性或者一個方法 #set一個reference,而後立刻就用 #if 測試。例如:
#set( $criteria = ["name", "address"] )
#foreach( $criterion in $criteria )
#set( $result = $query.criteria($criterion) )
#if( $result )
Query was successful
#end
#end
在上面的例子中,程序將不能智能的根據$result的值決定查詢是否成功。在$result被#set後(added to the context),它不能被設置回null(removed from the context)。打印的結果將顯示兩次查詢結果都成功了,可是實際上有一個查詢是失敗的。
爲了解決以上問題咱們能夠經過預先定義的方式:
#set( $criteria = ["name", "address"] )
#foreach( $criterion in $criteria )
#set( $result = false )
#set( $result = $query.criteria($criterion) )
#if( $result )
Query was successful
#end
#end
不像其餘Velocity指示符號,#set 沒有一個#end 結束。
String Literals
當你使用#set directive,String literal封閉在一對雙引號內。象下面:
#set( $directoryRoot = "www" )
#set( $templateName = "index.vm" )
#set( $template = "$directoryRoot/$templateName" )
$template
上面這段代碼的輸出結果爲:
www/index.vm
可是,當string literal被封裝在單引號內時,它將不被解析:
#set( $foo = "bar" )
$foo
#set( $blargh = '$foo' )
$blargh
輸出爲:
bar $foo
上面這個特性能夠經過修改velocity.properties文件的stringliterals.interpolate = false的值來改變上面的特性是否有效。
條件語句
If / ElseIf / Else
當一個web頁面被生成時使用Velocity的#if directrive,若是條件成立的話能夠在頁面內嵌入文字。例如:
#if( $foo )
<strong>Velocity!</strong>
#end
上例中的條件語句將在如下兩種條件下成立:(i)$foo是一個boolean型的變量,且它的值爲true;(ii)$foo變量的值不爲null。這裏須要注意一點:Velocity context僅僅可以包含對象,因此當咱們說「boolean」時實際上表明的時一個Boolean對象。即使某個方法返回的是一個boolean值,Velocity也會利用內省機制將它轉換爲一個Boolean的相同值。
若是條件成立,那麼#if和#end之間的內容將被顯示。在這個例子中,若是 $foo的值爲true,輸出爲「Velocity!」。相反地,若是 $foo 是一個 null值,或者是一個 false 值,表達式值爲 false,沒有輸出。
#elseif和#else元素能夠同#if一同使用。注意:Velocity 模板引擎遇到一個爲true值的表達式就會中止。在下面的例子,假設 $foo=15,$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
在這個例子中,$foo比10大,因此在開始的兩個比較中都失敗。接着 $bar跟6比較是真的因此輸出爲 GO South。
注意這裏的Velocity的數字是做爲Integer來比較的――其餘類型的對象將使得條件爲false,可是與java不一樣它使用「==」來比較兩個值,並且velocity要求等號兩邊的值類型相同。
關係、邏輯運算符
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
Velocity有AND、OR和NOT邏輯運算符。想獲得更多信息,請看VTL Reference Guide。下面的例子是說明AND、OR和NOT邏輯運算符的用法:
## logical AND
#if( $foo && $bar )
<strong> This AND that</strong>
#end
只有當$foo 和 $bar 都爲true,#if 纔會獲得true值。若是$foo=false ,表達式的值爲 false,$bar 就不會求值。若是 $foo的值爲 true ,Velocity模板引擎會檢查 $bar的值,若是$bar=true,整個表達式的值爲true,輸出爲「This AND that」。若是$bar=false,整個表達式的值爲false,沒有輸出。
邏輯OR 的工做方式同樣,除了只要有一個值爲true ,整個表達式的值就爲true。考慮一下下面的例子。
## logical OR
#if( $foo || $bar )
<strong>This OR That</strong>
#end
若是$foo=true,Velocity模板引擎就沒有必要查找 $bar,不管 $bar 是true 仍是 false ,表達式的值爲 true ,輸出爲「This OR That」。若是$foo=flase,$bar的值就必定要檢查,在這個例子中,若是 $bar 一樣是false,表達式的值爲 false ,沒有輸出。從另一個角度看,若是$bar 的值爲true ,整個表達式的值爲 true ,輸出爲 「This OR That」。
關於邏輯NOT ,只有一個疑問:
##logical NOT
#if( !$foo )
<strong>NOT that</strong>
#end
若是 $foo=true, !$foo 的值爲 false,沒有輸出。若是$foo=false,!$foo的值爲true,輸出爲「NOT that」。注意不要跟 quiet reference $!foo 混爲一談,那是徹底不同的。
循環
Foreach循環
#foreach 用於循環。例子:
<ul>
#foreach( $product in $allProducts )
<li>$product</li>
#end
</ul>
每次循環$allProducts中的一個值都會賦給$product變量。
$allProducts能夠是一個Vector、Hashtable或者Array。分配給$product的值是一個java對象,而且能夠經過變量被引用。例如:若是$product是一個java的Product類,而且這個產品的名字能夠經過調用他的getName()方法獲得。
如今咱們假設$allProducts是一個Hashtable,若是你但願獲得它的key應該像下面這樣:
<ul>
#foreach( $key in $allProducts.keySet() )
<li>Key: $key -> Value: $allProducts.get($key)</li>
#end
</ul>
Velocity還特別提供了獲得循環次數的方法,以便你能夠像下面這樣做:
<table>
#foreach( $customer in $customerList )
<tr><td>$velocityCount</td><td>$customer.Name</td></tr>
#end
</table>
$velocityCount變量的名字是Velocity默認的名字,你也能夠經過修改velocity.properties文件來改變它。默認狀況下,計數從「1」開始,可是你能夠在velocity.properties設置它是從「1」仍是從「0」開始。下面就是文件中的配置:
# 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
include
#include script element容許模板設計者引入本地文件。被引入文件的內容將不會經過模板引擎被render。爲了安全的緣由,被引入的本地文件只能在TEMPLATE_ROOT目錄下。
#include( "one.txt" )
#include 引用的文件用引號括起來。
若是您須要引入多個文件,能夠用逗號分隔就行:
#include( "one.gif","two.txt","three.htm" )
在括號內能夠是文件名,可是更多的時候是使用變量的。這用於根據頁面提交的需求而輸出。這裏有一個例子同時有文件名和變量。
#include( "greetings.txt", $seasonalstock )
parse
#parse script element容許模板設計者一個包含VTL的本地文件。Velocity將解析其中的VTL並render模板。
#parse( "me.vm" )
就像#include,#parse接受一個變量而不是一個模板。任何由#parse指向的模板都必須包含在TEMPLATE_ROOT目錄下。與#include不一樣的是,#parse只能指定單個對象。
你能夠經過修改velocity.properties文件的parse_direcive.maxdepth的值來控制一個template能夠包含的最多#parse的個數――默認值是10。#parse是能夠遞歸調用的,例如:若是dofoo.vm包含以下行:
Count down.
#set( $count = 8 )
#parse( "parsefoo.vm" )
All done with dofoo.vm!
那麼在parsefoo.vm模板中,你能夠包含以下VTL:
$count
#set( $count = $count - 1 )
#if( $count > 0 )
#parse( "parsefoo.vm" )
#else
All done with parsefoo.vm!
#end
在顯示「Count down」後,Velocity經過parsefoo.vm,從8往下數。當計數到了0,它就會顯示「All done with parsefoo.vm!」。在這時,Velocity 會返回到dofoo.vm ,輸出信息:「All done with dofoo.vm!」。
中止
#stop script element容許模板設計者中止執行模板引擎並返回。把它應用於debug是頗有幫助的。
#stop
Velocimacros
#macro script element容許模板設計者定義一段可重用的VTL template。Velocimacros普遍用於簡單和複雜的行列。Velocimacros的出現是爲了減小編碼和極小化排版錯誤,對Velocimacros的概念提供一個介紹。
#macro( d )
<tr><td></td></tr>
#end
在上面的例子中Velocimacro被定義爲d,而後你就能夠在任何VTL directive中以以下方式調用它:
#d()
當你的template被調用時,Velocity將用<tr><td></td></tr>替換爲#d()。
每一個Velocimacro能夠擁有任意數量的參數――甚至0個參數,雖然定義時能夠隨意設置參數數量,可是調用這個Velocimacro時必須指定正確的參數。下面是一個擁有兩個參數的Velocimacro,一個參數是color另外一個參數是array:
#macro( tablerows $color $somelist )
#foreach( $something in $somelist )
<tr><td bgcolor=$color>$something</td></tr>
#end
#end
Velocimacro在這個例子的定義,tablerows,有兩個元素。第一個是替換 $color ,第二個是替換$somelist。
任何東西均可以經過Velocimacro加入到VTL模板中。tablerows Velocimacro 是一個foreach 標識。 這裏有兩個#end標識在#tablerows Velocimacro 定義裏面。第一個是屬於 #foreach,第二個是屬於Velocimacro定義的。
#set( $greatlakes = ["Superior","Michigan","Huron","Erie","Ontario"] )
#set( $color = "blue" )
<table>
#tablerows( $color $greatlakes )
</table>
注意到$greatlakes 替代 $somelist。當#tablerows Velocimacro被調用時,就會產生下面的輸出:
<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>
Velocimacros能夠在Velocity模板內實現行內定義(inline),也就意味着同一個web site內的其餘Velocity模板不能夠得到Velocimacros的定義。定義一個能夠被全部模板共享的Velocimacro顯然是有不少好處的:它減小了在一大堆模板中重複定義的數量、節省了工做時間、減小了出錯的概率、保證了單點修改。
上面定義的#tablerows( $color $list )Velocimacro被定義在一個Velocimacros模板庫(在velocity.properties中定義)裏,因此這個macro能夠在任何規範的模板中被調用。它能夠被屢次應用而且能夠應用於不一樣的目的。例以下面的調用:
#set( $parts = ["volva","stipe","annulus","gills","pileus"] )
#set( $cellbgcol = "#CC00FF" )
<table>
#tablerows( $cellbgcol $parts )
</table>
當爲mushroom.vm實現一個請求時,Velocity會在模板庫中找到#tablerows Velocimacro(定義在velocity.properties文件),產生如下輸出:
<table>
<tr><td bgcolor="#CC00FF">volva</td></tr>
<tr><td bgcolor="#CC00FF">stipe</td></tr>
<tr><td bgcolor="#CC00FF">annulus</td></tr>
<tr><td bgcolor="#CC00FF">gills</td></tr>
<tr><td bgcolor="#CC00FF">pileus</td></tr>
</table>
Velocimacro arguments
Velocimacro可使用如下任何元素做爲參數:
l Reference:任何以$開頭的reference
l String literal:
l Number literal:
l IntegerRange:[1….3]或者[$foo….$bar]
l 對象數組:[「a」,」b」,」c」]
l boolean值:true、false
當將一個reference做爲參數傳遞給Velocimacro時,請注意reference做爲參數時是以名字的形式傳遞的。這就意味着參數的值在每次Velocimacro內執行時纔會被產生。這個特性使得你能夠將一個方法調用做爲參數傳遞給Velocimacro,而每次Velocimacro執行時都是經過這個方法調用產生不一樣的值來執行的。例如:
#macro( callme $a )
$a $a $a
#end
#callme( $foo.bar() )
執行的結果是:reference $foo的bar()方法被執行了三次。
在第一次掃描中,出現驚人的做用。可是當你考慮到Velocimacro的最原始動機:消除剪切、粘貼、複製,簡單地使用VTL使它更靈活。它容許你對傳遞對象到Velocimacro,例如一個產生重複序列顏色,着色表格的行的對象。
若是你不須要這樣的特性能夠經過如下方法:
#set( $myval = $foo.bar() )
#callme( $myval )
Velocimacro properties
Velocity.properties文件中的某幾行可以使Velocimacros的實現更加靈活。注意更多的內容能夠看Developer Guide。
Velocity.properties文件中的velocimacro.libraary:一個以逗號分隔的模板庫列表。默認狀況下,velocity查找惟一的一個庫:VM_global_library.vm。你能夠經過配置這個屬性來指定本身的模板庫。
Velocity.properties文件中的velocimacro.permissions.allow.inline屬性:有兩個可選的值true或者false,經過它能夠肯定Velocimacros是否能夠被定義在regular template內。默認值是ture――容許設計者在他們本身的模板中定義Velocimacros。
Velocity.properties文件中的velocimacro.permissions.allow.inline.replace.global屬性有兩個可選值true和false,這個屬性容許使用者肯定inline的Velocimacro定義是否能夠替代全局Velocimacro定義(好比在velocimacro.library屬性中指定的文件內定義的Velocimacro)。默認狀況下,此值爲false。這樣就阻止本地Velocimacro定義覆蓋全局定義。
Velocity.properties文件中的velocimacro.permissions.allow.inline.local.scale屬性也是有true和false兩個可選值,默認是false。它的做用是用於肯定你inline定義的Velocimacros是否僅僅在被定義的template內可見。換句話說,若是這個屬性設置爲true,一個inline定義的Velocimacros只能在定義它的template內使用。你可使用此設置實現一個奇妙的VM竅門:a template can define a private implementation of the second VM that will be called by the first VM when invoked by that template. All other templates are unaffected。
Velocity.properties文件中的velocimacro.context.localscope屬性有true和false兩個可選值,默認值爲false。當設置爲true時,任何在Velocimacro內經過#set()對context的修改被認爲是針對此velocimacro的本地設置,而不會永久的影響內容。
Velocity.properties文件中的velocimacro.library.autoreload屬性控制Velocimacro庫的自動加載。默認是false。當設置爲ture時,對於一個Velocimacro的調用將自動檢查原始庫是否發生了變化,若是變化將從新加載它。這個屬性使得你能夠不用從新啓動servlet容器而達到從新加載的效果,就像你使用regular模板同樣。這個屬性可使用的前提就是resource loader緩存是off狀態(file.resource.loader.cache = false)。注意這個屬性其實是針對開發而非產品的。
Velocimacro Trivia
Velocimacro必須被定義在他們被使用以前。也就是說,你的#macro()聲明應該出如今使用Velocimacros以前。
特別要注意的是,若是你試圖#parse()一個包含#macro()的模板。由於#parse()發生在運行期,可是解析器在parsetiem決定一個看似VM元素的元素是不是一個VM元素,這樣#parse()-ing一組VM聲明將不按照預期的樣子工做。爲了獲得預期的結果,只須要你簡單的使用velocimacro.library使得Velocity在啓動時加載你的VMs。
Escaping VTL directives
VTL directives can be escaped with 「\」號,使用方式跟VTL的reference使用逃逸符的格式差很少。
## #include( "a.txt" ) renders as <contents of a.txt>
#include( "a.txt" )
## \#include( "a.txt" ) renders as \#include( "a.txt" )
\#include( "a.txt" )
## \\#include ( "a.txt" ) renders as \<contents of a.txt>
\\#include ( "a.txt" )
在對在一個directive內包含多個script元素的VTL directives使用逃逸符時要特別當心(好比在一個if-else-end statement內)。下面是VTL的if-statement的典型應用:
#if( $jazz )
Vyacheslav Ganelin
#end
若是$jazz是ture,輸出將是:
Vyacheslav Ganelin
若是$jazz是false,將沒有輸出。使用逃逸符將改變輸出。考慮一下下面的狀況:
\#if( $jazz )
Vyacheslav Ganelin
\#end
如今不管$jazz是true仍是false,輸出結果都是:
#if($ jazz )
Vyacheslav Ganelin
#end
事實上,因爲你使用了逃逸符,$jazz根本就沒有被解析爲boolean型值。在逃逸符前使用逃逸符是合法的,例如:
\\#if( $jazz )
Vyacheslav Ganelin
\\#end
以上程序的顯示結果爲:
\ Vyacheslav Ganelin
\
爲了方便理解,注意到 #if(arg)當新一行的結束(return)在輸出中會省略新行。所以,#if()塊是接着第一個‘\’,顯示來自在#if()前面的‘\\’。最後的‘\’在跟文本不一樣的行,由於那裏有新的一行在‘Ganelin’後面,因此最後‘\\’在#end 的前面。
可是若是$jazz爲false,那麼將沒有輸出。注意:事情也有例外,若是script elements 沒有徹底的逃避。
\\\#if( $jazz )
Vyacheslave Ganelin
\\#end
在這裏#if 已經逃避了,可是#end沒有,有太多的#end 的產生解析錯誤。
VTL:Formatting issues
儘管在此用戶手冊中VTL一般都開始一個新行,以下所示:
#set( $imperial = ["Munetaka","Koreyasu","Hisakira","Morikune"] )
#foreach( $shogun in $imperial )
$shogun
#end
可是像下面這種寫法也是能夠的:
Send me #set($foo = ["$10 and ","a cake"])#foreach($a in $foo)$a #end please.
上面的代碼能夠被改寫爲:
Send me
#set( $foo = ["$10 and ","a cake"] )
#foreach( $a in $foo )
$a
#end
please.
或者
Send me
#set($foo = ["$10 and ","a cake"])
#foreach ($a in $foo )$a
#end please.
每一種的輸出結果將同樣。
其餘特性和雜項
math
在模板中可使用Velocity內建的算術函數,如:加、減、乘、除。下面的等式分別是:加、減、乘、除:
#set( $foo = $bar + 3 )
#set( $foo = $bar - 4 )
#set( $foo = $bar * 6 )
#set( $foo = $bar / 2 )
當執行除法時將返回一個Integer類型的結果。而餘數你可使用%來獲得:
#set( $foo = $bar % 5 )
在Velocity內使用數學計算公式時,只能使用像-n,-2,-1,0,1,2,n這樣的整數,而不能使用其它類型數據。當一個非整型的對象被使用時它將被logged而且將以null做爲輸出結果。
Range Operator
Range operator能夠被用於與#set和#foreach statement聯合使用。對於處理一個整型數組它是頗有用的,Range operator具備如下構造形式:
[n..m]
m和n都必須是整型,而m是否大於n則可有可無。例子:
First example:
#foreach( $foo in [1..5] )
$foo
#end
Second example:
#foreach( $bar in [2..-2] )
$bar
#end
Third example:
#set( $arr = [0..1] )
#foreach( $i in $arr )
$i
#end
Fourth example:
[1..3]
產生如下輸出:
First example:
1 2 3 4 5
Second example:
2 1 0 -1 -2
Third example:
0 1
Fourth example:
[1..3]
注意:range operator只在#set和#foreach中有效。
網頁設計者使用標準尺寸製做表格,可是某時候會沒有足夠的數據填入表格,就會發現 range 很是有用。
Advanced Issue:Escaping and!
當一個reference被「!」分隔時,而且在它以前有逃逸符時,reference將以特殊的方式處理。注意這種方式與標準的逃逸方式時不一樣的。對照以下:
#set( $foo = "bar" )
$\!foo
$\!{foo}
$\\!foo
$\\\!foo
這將顯示爲:
$!foo
$!{foo}
$\!foo
$\\!foo
\ 在 $ 前面跟逃避規則相比較;
\$foo
\$!foo
\$!{foo}
\\$!{foo}
這將顯示爲:
\$foo
\$!foo
\$!{foo}
\bar
Velocimacro雜記
這章節是一個小型涉及Velocimacros的常見問題解答。這章節會隨時間的變化而變化,因此它的做用有時是檢驗新的信息。
注意:在這章節'Velocimacro'簡稱爲‘VM’。
1. 我能用一個標識或者另外的VM 做爲一個VM的參數嗎?
例如:#center ( #bold( 「hello」 ) )
答:不能夠。一個directive的參數使用另一個directive是不合法的。
可是,仍是有些事情你能夠做的。最簡單的方式就是使用雙引號,因此你能夠這樣作:
#set($stuff = "#bold('hello')" )
#center( $stuff )
上面的格式也能夠縮寫爲一行:
#center( "#bold( 'hello' )" )
請注意在下面的例子中參數被evaluated在Velocimacro內部,而不是在calling level。例子:
#macro( inner $foo )
inner : $foo
#end
#macro( outer $foo )
#set($bar = "outerlala")
outer : $foo
#end
#set($bar = 'calltimelala')
#outer( "#inner($bar)" )
輸出結果爲:
Outer : inner : outerlala
由於#inner($bar)的賦值發生在#outer(),因此$bar的值在#outer()賦給的。
記住Veloctiy的特性:參數的傳遞是By Name的。例如:
#macro( foo $color )
<tr bgcolor=$color><td>Hi</td></tr>
<tr bgcolor=$color><td>There</td></tr>
#end
#foo( $bar.rowColor() )
以上代碼將致使rowColor()方法兩次調用,而不是一次。爲了不這種現象的出現,咱們能夠按照下面的方式執行:
#set($color = $bar.rowColor())
#foo( $color )
2.我能經過#parse()登記velocimacros嗎?
答:目前,Velocimacros必須在第一次被模板調用前被定義。這就意味着你的#macro()聲明應該出如今使用Velocimacros以前。
若是你試圖#parse()一個包含#macro() directive的模板,這一點是須要牢記的。由於#parse()發生在運行期,可是解析器在parsetiem決定一個看似VM元素的元素是不是一個VM元素,這樣#parse()-ing一組VM聲明將不按照預期的樣子工做。爲了獲得預期的結果,只須要你簡單的使用velocimacro.library使得Velocity在啓動時加載你的VMs。
3.什麼是velocimacro自動加載?
答:velocimacro.library.autoreload是專門爲開發而非產品使用的一個屬性。此屬性的默認值是false。
當<type>.resource.loader.cache = false
連同一塊兒設爲true ()(<type>是你用的資源器,例如‘file’),當你編譯它們的時候Velocity引擎會自動重載那些在你的
velocimacro庫文件中的修改,因此你不用servlet引擎(或者應用程序)或者其餘竅門來使你的
velocimacros重載。
這裏有一個簡單的屬性配置。
file.resource.loader.path = templates
file.resource.loader.cache = false
velocimacro.library.autoreload = true
不要在你的做品中出現上述的配置
字符串串聯
開發人員最常問的問題是我如何做字符拼接?在java中是使用「+」號來完成的。
在VTL裏要想實現一樣的功能你只須要將須要聯合的reference放到一塊兒就好了。例如:
#set( $size = "Big" )
#set( $name = "Ben" )
The clock is $size$name.
輸出結果將是:The clock is BigBen.。更有趣的狀況是:
#set( $size = "Big" )
#set( $name = "Ben" )
#set($clock = "$size$name" )
The clock is $clock.
上例也會獲得一樣的結果。最後一個例子,當你但願混合固定字段到你的reference時,你須要使用標準格式:
#set( $size = "Big" )
#set( $name = "Ben" )
#set($clock = "${size}Tall$name" )
The clock is $clock.
輸出結果是:The clock is BigTallBen.。使用這種格式主要是爲了使得$size不被解釋爲$sizeTall。
本文轉載自:http://www.cnblogs.com/alllearning/archive/2009/12/21/1628676.html