Velocity
用戶指南手冊中文版(轉)
1.
關於
Velocity
用戶指南旨在幫助頁面設計者和內容提供者了解
Velocity
和其簡單而又強大的腳本語言(
Velocity Template Language (VTL)
)。本指南中有很多示例展示了用
Velocity
來講動態內容嵌入到網站之中,但是所有的
VTL examples
都同演示用於所有的頁面和模版。
感謝選擇
Velocity!
2.
什么是
Velocity?
Velocity
是一個基於
Java
的模版引擎。它允許
web
頁面設計者引用
JAVA
代碼預定義的方法。
Web
設計者可以根據
MVC
模式和
JAVA
程序員並行工作,這意味着
Web
設計者可以單獨專注於設計良好的站點,而程序員則可單獨專注於編寫底層代碼。
Velocity
將
Java
代碼從
web
頁面中分離出來,使站點在長時間運行后仍然具有很好的可維護性,並提供了一個除
JSP
和
PHP
之外的可行的被選方案。
Velocity
可用來從模板產生
web
頁面,
SQL, PostScript
以及其他輸出。他也可用於一個獨立的程序以產生源代碼和報告,或者作為其它系統的一個集成組件。這個項目完成后,
Velocity
將為
Turbine web
應用程序框架提供模板服務。
Velocity+Turbine
方案提供的模板服務將允許
web
應用按真正的
mvc
模式進行開發。
3.
Velocity
可以做什么
?
3.1.
Mud Store
示例
假設你是一個專門銷售泥漿(
MUD
)的在線商店的頁面設計者。我們稱他為
"The Online Mud Store"
。生意很好。客戶訂購各種各樣的類型和數量的泥漿。他們使用他們的用戶名和密碼登陸到商店中來,就可以瀏覽他們的訂貨和購買其他東西。現在,赤土陶泥正在促銷,這是一種很常用的泥巴。一少部分顧客很有規律的購買一種亮紅土
Bright Red Mud
,這也是促銷產品,但是不太常用,因此被移到頁面的邊緣。所有顧客的信息都在數據庫中被跟蹤,因此有一天問題出現了:為什么不使用
Velocity
來定位目標客戶,這些客戶對某種類型的產品特別感興趣?
Velocity
使針對訪問者個性的
WEB
頁面客戶化(個性化)非常容易。作為一個在線泥巴商店的站點設計者,以想在客戶以登陸進展點后就看到它們想看的頁面。
你遇到你公司的軟件工程師,每個人都認為
$customer
將保持當前登陸進入的客戶信息,而
$mudsOnSpecial
將士當前所有促銷的泥巴。
$flogger
對象包含有助於促銷的方法。對於當前的任務,讓我們僅關注這三個問題。記住,你不需要擔心軟件工程師如何從數據庫中取得顧客信息,但你必須知道他們可以。這樣可以使你專注於你的工作而軟件工程師則忙於他們自己的工作。
你可以在你的頁面中嵌入如下的
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
語句的細節將進一步細說,但重要的是這個短小的腳本居然可以在你的站點上運行。當有一個傾向於亮紅土的顧客登陸進來時,亮紅土正在促銷,這就是這個顧客所看到的,並且促銷顯示非常顯著。如果另外一個長期購買赤陶土的顧客登陸進來,赤陶土促銷的提示信息則應該在前面中間位置。
Velocity
是非常靈活的,受限的只是你的創造力。
寫在
VTL
參考文檔中的是其他
Velocity
元素,他們一起給你很強大的能力和靈活性以創建很好的站點。待你更加了解這些元素,就可以開始釋放
Velocity
的強大動力。
4.
Velocity
模板語言
(VTL):
介紹
Velocity
模板語言
(VTL)
旨在為
Web
頁面結合動態內容提供最容易、簡單和簡潔的方法。即使有一點或者沒有編程經驗的頁面設計者也可以很快能為頁面提供動態內容。
VTL
使用引用(
references
)來將動態內容嵌入
web
頁面,每個變量就是某一個類型的引用。變量實際上是一個可以調用定義在
java
代碼中的內容的引用,或者它可以從頁面內的
VTL
語句得出自身的值。下面是一個例子,說明可以嵌入到
HTML
文檔中的
VTL
語句。
#set( $a = "Velocity" )
|
這個
VTL
語句,就像所有的
VTL
語句一樣,以
#
字符開始,並跟着一個指令
set
。當一個在線訪問這請求頁面時,
Velocity
模伴引擎在頁面內搜索所有
#
字符,然后決定是哪一個標記了
VTL
語句的開始,哪個標記不需要
VTL
做什么動作。
#
字符后面緊跟一個指令
set
.
。
set
指令使用一個括在括號內的表達式
---
一個等式將一個值指派給一個變量。變量在等號的左邊而值在等號的右邊。
在上面的示例中,變量是
$a
值是
Velocity
。這個變量就象其他引用一樣,以一個
$
字符開始。值通常在引號之中,對
Velocity
來說一般沒有類型沖突的問題,因為只有字符串
(
基於文本的信息
)
可以傳遞給變量。
下面的主要規則可能有助於理解
Velocity
是如何工作的:引用以
$
開頭用於取得什么東西,而指令以
#
開始用於做什么事情。
在上面的例子中,
#set
用於將一個值指派給一個變量。而變量
$a
則可以用來在模板中輸出
"Velocity"
。
5.
Hello Velocity World!
一旦一個值被賦給一個變量,便可以在
HTML
中隨處引用它。在下面的示例中,先給變量
$foo
賦值然后引用它。
<html>
<body>
#set( $foo = "Velocity" )
Hello $foo World!
</body>
<html>
|
這個頁面的結果是輸出
"Hello Velocity World!"
。
為了使包含
VTL
指令的語句具有可讀性,我們鼓勵每個
VTL
語句在一個新行開始,雖然並不一定要這樣做。
set
將隨后深入解釋。
6.
注釋
可以用注釋加入描述性文本,他們並不在模板引擎中輸出。注釋可以有助於你的記憶或者想其他人解釋你的
VTL
語句正在做什么。
## 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.
|
還有第三種注釋,
VTL
注釋塊,可以用來存儲諸如文檔作者、版本信息等。
#**
This is a VTL comment block and
may be used to store such information
as the document author and versioning
information:
@author
@version 5
*#
|
7.
引用
VTL
中有三種類型的引用:變量,屬性和方法。作為使用
VTL
的設計者,你和你的工程師必須在飲用的特定命名上取得一致,以便在你的模板中正確的使用他們。
有關引用的所有參數都處理為字符串對象。
Everything coming to and from a reference is treated as a String object.
假如有一個對象表示
$foo (
比如說是整型對象
)
,
Velocity
將調用其
toString()
方法來將此對象轉換為一個字符串。
7.1.
變量
Variables
變量的簡略標記是有一個前導
"$"
字符后跟一個
VTL
標識符(
Identifier.
)組成。一個
VTL
標識符必須以一個字母開始
(a .. z
或
A .. Z)
。剩下的字符將由以下類型的字符組成:
字母
(a .. z, A .. Z)
數字
(0 .. 9)
連字符
("-")
下划線
("_")
下面是一些有效的變量引用
:
$foo
$mudSlinger
$mud-slinger
$mud_slinger
$mudSlinger1
|
當
VTL
引用一個變量時,比如
$foo
,變量可以從模板的
set
指令取得值,也可以從
Java
代碼中取得。例如,如果
Java
變量
$foo
在模板被請求的時候具有值
bar
,則
bar
將替換頁面中的所有
$foo
的實例。或者,如果包含下面的語句:
#set( $foo = "bar" )
|
緊跟指令后的所有
$foo
的實例的輸出將會一樣值。
7.2.
屬性
VTL 引用的第二種元素是屬性,而屬性具有獨特的格式。屬性的簡略標記識前導符 $ 后跟一個 VTL 標識符,在后跟一個點號 (".") 最后又是一個 VTL 標識符。這是一些有效的示例:
$customer.Address
$purchase.Total
|
請看第一個例子,
$customer.Address
.
。他有兩種意思。它可以意味着,查詢由
customer
標是的哈希表並按關鍵字
Address
返回值。但是
$customer.Address
也可能引用一個方法(下述,
$customer.Address
可能是
$customer.getAddress()
.
的縮寫。當一個頁面被請求時,
Velocity
將決定這兩種可能到底是哪一個,然后返回相應的值。
7.3.
方法
方法在
JAVA
代碼中定義,並作一些有用的事情,比如運行一個計算器或者作出一個決定。方法是實際上也是引用,由前導符
"$"
后跟一個
VTL
標識符,后跟一個
VTL
方法體(
Method Body
)。
VTL
方法體由一個
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"] )
##
不能將參數列表傳遞給
$sun.Planets
$sisyphus.pushRock()
## Velocity
假定我意思是
$sisyphus.getRock()
$book.setTitle( "Homage to Catalonia" )
##
不能傳遞一個參數列表
|
7.4.
形式引用符
Formal Reference Notation
引用的簡略符號如上所述,但是另外還有一種引用的形式符號,示例如下:
${mudSlinger}
${customer.Address}
${purchase.getTotal()}
|
在大多數情況下,我們將使用引用的簡略符號,但在一些情況下,也需要擁戴哦形式引用符以便正確處理。
假定你正在紙片上構件一個句子,將使用
$vice
作為句子中名詞的詞根。我們的目標是允許人們選擇詞根,然后產生以下兩種結果之一:
"Jack is a pyromaniac."
或者
"Jack is a kleptomaniac."
。
在這種情況下,使用簡略符號是不太充分的。考慮到下面的例子:
Jack is a $vicemaniac.
|
這里有個不確定性,
Velocity
假定
$vicemaniac
,(而不是
$vice
)是一個你想要使用的標識符。找不到
$vicemaniac
的值,他將返回
$vicemaniac
。使用形式符號便可解決這個問題:
Jack is a ${vice}maniac
|
現在
Velocity
知道
$vice
(而不是
$vicemaniac
)是一個引用。形式符號常用在飲用咋模板中和文本直接鄰近的地方。
7.5.
安靜引用符
Quiet Reference Notation
當
Velocity
遇到一個位定義的引用時,其通常行為是輸出這個引用的映像。比如,假設下面的引用出現在模板中的一部分:
<input type="text" name="email" value="$email"/>
|
當表單初次裝入時,變量引用
$email
無值,你寧願是一個空白域而不是具有值
"$email"
。使用安靜引用符可以繞過
Velocity
的常規行為,在
VTL
中不用
$email
而是用
$!email
符號。
所以,上面的例子將會看起來像下面的樣子:
<input type="text" name="email" value="$!email"/>
|
現在,當表單初次裝入時,
$email
仍然沒有值,但是將輸出空字符串而不是
"$email"
。
形式和安靜引用符可以一起使用,如下所示:
<input type="text" name="email" value="$!{email}"/>
|
1.
取得語義
Getting literal
VTL
特別的字符,比如
$
和
#
,來做這個工作,因此在模板中使用這些自負的時候必須格外小心。本節講述
$
的轉義。
1.1.
貨幣
我們寫下句子
"I bought a 4 lb. sack of potatoes at the farmer's market for only $2.50!"
,這並沒有什么問題。但如前所述,
VTL
標識符總是以大寫或是小寫字母開始,所以
$2.50
在引用中將不能出錯。
1.2.
轉義有效的
VTL
引用
問題將會出現,因為
Velocity
將有一個潛在的沖突。轉義特殊字符是處理
VTL
模板種特殊字符的最好的辦法,者可以用一個反斜線來進行。
foo
$email
/foo
/$email
|
如果
Velocity
在
VTL
模板中遇到一個
$email
引用,他將在上下文中查找相應的值。這里,輸出將是
foo
,因為
$email
是定義了的。如果
$email
未定義,輸出將是
$email
。
假設
$email
是定義了的(比如,具有值
foo)
,但是你想輸出
$email
。可以有幾種方法來做這個事情,不是最簡單的是使用轉義符。
## The following line defines $email in this template:
#set( $email = "foo" )
$email
/$email
//$email
///$email
|
將輸出是
foo
$email
/foo
/$email
|
注意:
/
綁定在
$
的左邊。從做綁定原則使
///$email
被解釋為
//$email
。和上面例子比較下面的例子,這里
$email
未定義。
$email
/$email
//$email
///$email
|
輸出
$email
/$email
//$email
///$email
|
注意,
Velocity
處理定義和未定義的引用是不同的。下面一個
set
指令將
$foo
設為值
gibbous.
。
#set( $foo = "gibbous" )
$moon = $foo
|
輸出將是
$moon = gibbous
--
這里
$moon
作為字面輸出,因為他並沒有定義。而
gibbous
將在
$foo
的位置輸出。
我們也可以轉義
VTL
指令,這將在指令一節祥述。
2.
Case Substitution
現在你大致了解了引用,可以在模板中使用它們了。
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}
|
這個例子顯示了引用的一些其他用法。
Velocity
借鑒了
Java
的自省和組件
bean
特征,來解決引用名在上下文中作為對象和對象方法的問題。可以在你的模板的任何地方插入引用和求值。
Velocity,
建模在
Sun Microsystems
定義的
BEAN
規范之上,是大小寫敏感的;開發者努力捕捉和糾正可能出現的用戶錯誤。當方法
getFoo()
在模板中通過
$bar.foo
引用時,
Velocity
首先嘗試
$getfoo
。如果失敗,他會再嘗試
$getFoo
。類似地,當一個模板引用到
$bar.Foo
,
Velocity
將嘗試
$getFoo()
先,然后嘗試
getfoo()
。
注意:模板中引用示例變量的問題仍然沒有解決。只有引用等價於
JavaBean
的
getter/setter
方法解決了。
(
比如
$foo.Name
解決了到類
Foo
的
getName()
示例方法的引用,但不能引用
Foo
的一個公共實例變量
Name)
。
3.
指令
因為指令(使用腳本來有效操控
JAVA
代碼的輸出)允許頁面設計員真正專注於咱點的外觀和內容設計,引用允許模板設計員為
Web
頁面產生動態內容。
3.1.
#set
#set
指令用來為引用設置相應的值。值可以被值派給變量引用或者是屬性引用,而且賦值要在括號里括起來。
#set( $primate = "monkey" )
#set( $customer.Behavior = $primate )
|
賦值的左邊必須是一個變量應用或者是屬性引用。右邊可以是下面的類型之一:
變量引用
字面字符串
屬性引用
方法引用
字面數字
數組列表
這些例子演示了上述的每種類型:
#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
|
注意:最后一個例子中,在方括號
[..]
中定義的項目可以被
ArrayList
類定義的方法訪問。比如,你可以使用
$monkey.Say.get(0)
訪問上述的第一個元素。
右邊也可以是一個簡單的算術表達式
:
#set( $value = $foo + 1 )
#set( $value = $bar - 1 )
#set( $value = $foo * $bar )
#set( $value = $foo / $bar )
|
如果右邊是一個屬性或方法引用,取值是
NULL
,他將不會賦值給左邊。通過這種機制將一個存在的引用從上下文中刪除是不可能的。這對
Velocity
的新手可能會混淆。例如:
#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
,上述
VTL
將解釋為:
The result of the first query is bill
The result of the second query is bill
|
這往往會給那些想構建
#foreach
循環來試圖通過屬性和方法引用來設置一個引用的新手帶來困惑,下面馬上通過
#if
指令測試一下。例如:
#set( $criteria = ["name", "address"] )
#foreach( $criterion in $criteria )
#set( $result = $query.criteria($criterion) )
#if( $result )
Query was successful
#end
#end
|
在上面的例子中,依靠
$result
的去值來決定查詢是否成功恐怕不是英明的做法。當
$result
被
#set
設置后
(
添加到上下文中
)
,他就不能再被設值為
null (
從上下文中刪除
)
。
我們對此的解決方法是預設
$result
為
false
。然后如果
$query.criteria()
調用失敗,你就可以檢查之。
#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
語句。
3.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
來改變。
3.3.
條件
3.4.
If / ElseIf / Else
Velocity
中的
#if
指令允許在頁面生成時,在
IF
條件為真的情況下包含文本。例如:
#if( $foo )
<strong>Velocity!</strong>
#end
|
變量
$foo
先求值,以決定是否為真。在這兩種情況下為真:
(i) $foo
是一個邏輯變量並具有真的值,或者
(ii)
值非空。要記住
Velocity
上下文僅包括對象,所以當我們說
“
布爾
”'boolean'
時,他會被表示為
“
布爾類
”(Boolean class)
。這對即使是返回布爾類型的方法也是真的
—
自省架構將返回一個具有相同邏輯值的布爾類。
如果求值為真時,
#if
和
#end
語句之間的內容將輸出。在這種情況下,如果
$foo
為真,輸出將是
"Velocity!"
。相反,如果
$foo
具有一個
null
值,或者邏輯假,語句求值為假,則沒有輸出。
一個
#elseif
或者
#else
項可以用在
#if
語句中。請注意,
Velocity
模板引擎將在第一個為真的表達式時停止。下面的例子中,假設
$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
的數值比較約束為整型
—
其他類型都將求值為
false
。僅有一個例外是等於
'=='
,這時
Velocity
要求等號兩邊的對象具有相同的類型。
3.5.
關系和邏輯操作符
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
|
## logical AND
#if( $foo && $bar )
<strong> This AND that</strong>
#end
|
例子中
#if()
指令僅在
$foo
和
$bar
斗為真的時候才為真。如果
$foo
為假,則表達式也為假;並且
$bar
將不被求值。如果
$foo
為真,
Velocity
模板引擎將繼續檢查
$bar;
的值,如果
$bar
為真,則整個表達式為真。並且輸出
This AND that
。如果
$bar
為假,將沒有輸出因為整個表達式為假。
邏輯
OR
的工作方式相同,唯一的例外是其中一個表達式要被求值,以便決定整個表達式是否為真。請看下面的例子:
## logical or
#if( $foo || $bar )
<strong>This or That</strong>
#end
|
如果
$foo
為真,
Velocity
模板引擎就不需要去察看
$bar
的值,不管
$bar
是否為真,真個表達式都為真,因此輸出
This or That
。如果
$foo
為假,
$bar
就必須檢查其值了。在這種情況下,如果
$bar
也是為假,表達式將為假,沒有任何輸出。當然,如果
$bar
為真,則真個表達式為真,輸出
This or That
。
對於邏輯
NOT
操作符,只有一個操作數:
##logical NOT
#if( !$foo )
<strong>NOT that</strong>
#end
|
這里,如果
$foo
為真,
!$foo
求值為假,沒有輸出。如果
$foo
為假,
!$foo
求值為真,輸出
NOT that
。請當心,不要和安靜引用
quiet reference $!foo
混淆它們是完全不同的。
1.
循環
1.1.
Foreach
循環
#foreach
元素允許進行循環,例如:
<ul>
#foreach( $product in $allProducts )
<li>$product</li>
#end
</ul>
|
這個
#foreach
循環將導致
$allProducts
列表
(
對象
)
為查詢所有的產品
$products (
目標
)
遍歷一遍。每次經過循環,從
$allProducts
取得的值將置於
$product
變量之中。
$allProducts
變量的內容是一個矢量,一個哈希表或者數組。賦給
$product
變量的值是一個
Java
對象並且可以從一個類似的變量引用。例如,如果
$product
真是一個
Java
的產品類,其名稱可以通過引用
$product.Name
方法來檢索
(
即
: $Product.getName())
。
我們假定
$allProducts
是一個哈希表。如果你想檢索關鍵字的值或者在哈希表中的對象,你可以使用以下的代碼:
<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.properties
配置文件中標明。默認情況下,該變量從
1
開始計數,但是可以在
velocity.properties
文件中設為從
0
或者
1
開始。下面是
velocity.properties
文件中循環變量設置一節
:
# 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
|
2.
包含
#include
腳本元素允許模板設計人員包含(導入)本地文件,這個文件將插入到
#include
指令被定義的地方。文件的內容並不通過模板引擎來渲染。處於安全的原因,被包含的文件只可以放在
TEMPLATE_ROOT
下。
#include( "one.txt" )
|
#include
指令引用的文件在雙引號內。如果超過一個文件,其間用逗號隔開。
#include( "one.gif","two.txt","three.htm" )
|
被包含的文件並不是一定要用文件名來引用,事實上,最好的辦法是使用變量而不是文件名。這在根據規則決定何時提交頁面時,決定目標輸出是很有用的。
#include( "greetings.txt", $seasonalstock )
|
3.
解析
#parse
腳本元素允許頁面設計員導入包含
VTL
的本地文件。
Velocity
將解析和渲染指定的模板。
#parse( "me.vm" )
|
就象
#include
指令,
#parse
可以使用變量而不是一個實在的模板文件。
#parse
引用的模板文件必須包含的
TEMPLATE_ROOT
指定的目錄之下。和
#include
指令不一樣,
#parse
只有一個參數。
VTL
模板
templates can have #parse statements referring to templates that in turn have #parse statements. By default set to 10, the parse_directive.maxdepth line of the velocity.properties allows users to customize maximum number of #parse referrals that can occur from a single template. (Note: If the parse_directive.maxdepth property is absent from the velocity.properties file, Velocity will set this default to 10.) Recursion is permitted, for example, if the template dofoo.vm contains the following lines:
Count down.
#set( $count = 8 )
#parse( "parsefoo.vm" )
All done with dofoo.vm!
|
It would reference the template parsefoo.vm, which might contain the following VTL:
$count
#set( $count = $count - 1 )
#if( $count > 0 )
#parse( "parsefoo.vm" )
#else
All done with parsefoo.vm!
#end
|
After "Count down." is displayed, Velocity passes through parsefoo.vm, counting down from 8. When the count reaches 0, it will display the "All done with parsefoo.vm!" message. At this point, Velocity will return to dofoo.vm and output the "All done with dofoo.vm!" message.
4.
停止
#stop
腳本允許模板設計員停止模板引擎的執行,並返回。這通常用作調試。
#stop
|
1.
宏
#macro
腳本元素允許模板設計者在
VTL
模板中定義重復的段。
Velocimacros
不管是在復雜還是簡單的場合都非常有用。下面這個
Velocimacro
,僅用來節省擊鍵和減少排版錯誤,介紹了一些
Velocity
宏的概念。
#macro( d )
<tr><td></td></tr>
#end
|
在例子中,
Velocimacro
定義為
d
,它可以象調用其他
VTL
指令一樣的形式來進行調用:
#d()
|
當這個模板被調用時,
Velocity
將
#d()
替換為一個單行的空表格。
Velocimacro
可以帶一些參數,也可以不帶參數(如上例所示)。但在他被調用時,所帶的參數必須和其定義時的參數一樣。很多
Velocimacros
定義為不止一個參數。下面這個宏帶有兩個參數,一個顏色,一個數組。
#macro( tablerows $color $somelist )
#foreach( $something in $somelist )
<tr><td bgcolor=$color>$something</td></tr>
#end
#end
|
在這個例子中定義的
Velocimacro
,名為
tablerows,
要求兩個參數。第一個參數代替
$color,
第二個代替
$somelist
。
可以寫進
VTL
模板中的東西都可以寫進
Velocimacro
的主體部分。
tablerows
宏其實是一個
foreach
語句。在
#tablerows
宏的定義中有兩個
#ende
語句,第一個屬於
#foreach,
第二個結束宏定義。
#set( $greatlakes = ["Superior","Michigan","Huron","Erie","Ontario"] )
#set( $color = "blue" )
<table>
#tablerows( $color $greatlakes )
</table>
|
請注意
$greatlakes
替換了
$somelist
。這樣,當
#tablerows
宏被調用時,將產生以下輸出:
<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
模板語句內定義,這意味着它在同一站點內的其他
Velocity
模板中並不有效。定義一個宏,並使其與其他模板共享很具有明顯的優點:他減少了在大量的模板內重復定義宏的工作,並減少了出錯的機會,並確保對其他宏的改變對其他所有模板有效。
但如果
#tablerows($color $list)
宏是在一個
Velocimacros
模板庫內定義的,它就可以被其他常規模板所用。當然,它可以用於各種目的,也可重用多次。在表示所有真菌類(
fungi
)的
mushroom.vm
模板中,
#tablerows
宏可以被用來列出典型的蘑菇。
#set( $parts = ["volva","stipe","annulus","gills","pileus"] )
#set( $cellbgcol = "#CC00FF" )
<table>
#tablerows( $cellbgcol $parts )
</table>
|
我們對
mushroom.vm
執行請求,
Velocity
將在模板庫內找到
#tablerows
宏
(
在
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
參數
Velocimacros
的參數可以是以下的
VTL
元素:
引用(
Reference
)
:
以
'$'
打頭的元素
字面字符串(
String literal
)
:
比如
"$foo"
或
'hello'
字面數字
: 1, 2 ….
整數范圍
: [ 1..2]
或
[$foo .. $bar]
對象數組
: [ "a", "b", "c"]
布爾真
布爾假
當把引用作為參數傳遞給
Velocimacros
時,請注意引用是按
“
名字
”
傳遞的。這意味着他們的值在每次使用他們的
Velocimacro
中產生。這個特性允許你在方法調用是傳遞引用,並在每次使用時進行方法調用。例如,
Fo
,當調用下面的
Velocimacro
時,
#macro( callme $a )
$a $a $a
#end
#callme( $foo.bar() )
|
結果是,在方法
bar()
中,引用
$foo
被調用了
3
次。
咋看時,這個特征讓人吃驚,當當你考慮一下
Velocimacros
的原本動機
–
在
VTL
模板中避免很多
“
剪切復制
”
操作
—
你就會明白。它允許你將無狀態對象,比如在一個顏色表格行內重復產生一些顏色次序的對象,傳遞給
Velocimacro
。
如果你需要使用這個特征,你通常可以從方法內取得一個值,作為一個新的引用傳遞給宏:
#set( $myval = $foo.bar() )
#callme( $myval )
|
Velocimacro
屬性
velocimacro.library
–是一個逗號分隔的所有
Velocimacro
模板庫的列表。默認情況下,
Velocity
搜尋一個單一的庫
VM_global_library.vm.
。預先配置的模板路徑用來查找
Velocimacro
庫。
velocimacro.permissions.allow.inline
–這個屬性決定
Velocimacros
是否可以在常規模板內定義,取值為邏輯
True
或者
False
。默認情況下,設置為
true
,允許設計者在產規模板內定義宏。
velocimacro.permissions.allow.inline.to.replace.global
–邏輯
true
或者
false
,允許標明是否允許在常規模板內定義的
Velocimacro
代替在模板庫中定義並通過
velocimacro.library
屬性在啟動時裝入的全局宏。默認設置為
false
。
velocimacro.permissions.allow.inline.local.scope
–邏輯
true
或者
false
,默認值為
false
。控制是否在模板內定義的
Velocimacros
僅在定義它的模板內可見。換句話說,如果設置為
true
,一個模板可以定義僅能被他所用的宏。你可以用它來做一些漂亮的宏,如果一個全局調用另一個全局宏,在局部(
inline
)范圍內,當被一個模板調用時,該模板可以定義一個被第一個全局宏調用的第二個全局宏的私有實現。其他所有模板都不受影響。
velocimacro.context.localscope
–邏輯值
true
或者
false
,缺省值為
false
。但設置為
true
時,所有在
Velocimacro
內通過
#set()
進行的修改都將被視為
Velocimacro
的本地行為,不會影響到其上下文。
velocimacro.library.autoreload
–此屬性控制
Velocimacro
庫的自動載入。缺省值為
false
。如果設置為
true
,被調用的
Velocimacro
得源庫將被檢查是否改變,並在必要是重新載入。這將使你可以改變和測試
Velocimacro
庫,而不必重新啟動應用服務器或者
servlet
容器,就象你工作在常規模板一樣。這個模時僅在資源載入器的緩存模時被關閉的情況下有效
(
如
file.resource.loader.cache = false )
。此特征為開發時設計,不要在生產模式時使用。
Velocimacro Trivia
當前,
Velocimacros
在其首次在模版中使用前必須首先定義它。這意味着,
#macro()
宣稱應該在使用
Velocimacros
之前。
如果你想
#parse()
一個包含
#macro()
指令的模板,記住這個非常重要。因為
#parse()
在運行時發生,解析器在解析時要決定是否模版中一個看起來像
VM
的元素真是
VM
,所以解析一系列
VM
宣稱可能並不能如願地工作的很好。為避免如此,可以簡單地使用
velocimacro.library
的辦法,使
Velocity
在啟動時載入
VM
。
2.
轉義
VTL
指令
VTL
可以通過反斜杠
("/")
來進行轉義,
directives can be escaped with the backslash character in a manner similar to valid VTL references.
## #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" )
|
在轉義在一個單一指令內包含多個腳本元素(比如
f-else-end
語句)的指令時應多加小心。下面是一個典型的
VTL if
語句;
#if( $jazz )
Vyacheslav Ganelin
#end
|
如果
$jazz
為
true
,輸出是
Vyacheslav Ganelin
|
如果
$jazz
為
false
,將沒有輸出。轉義腳本元素將改變輸出。考慮下面的情況;
/#if( $jazz )
Vyacheslav Ganelin
/#end
|
不管
$jazz
是真或假,輸出都是
#if($ jazz )
Vyacheslav Ganelin
#end
|
事實上,因為所有腳本元素都被轉義了,
$jazz
永遠不會被求值。將設反斜杠在被合法轉義的腳本元素之前
//#if( $jazz )
Vyacheslav Ganelin
//#end
|
這時,如果
$jazz
為真,輸出是
/ Vyacheslav Ganelin
/
|
為理解這個情況,請注意在一個新行結束是將在輸出中忽略新的一行。因此,經過
#if()
前的
'//'
加工后,
#if()
塊緊跟第一個
'/'
。最后一個
/
位於新的一行,因為在
'Ganelin'
后又一個新行,所以,最后的那個位於
#end
之前的
//是語句塊的一部分
。
如果
$jazz
為
false
,這里將沒有輸出。注意,在開始破壞了
if
語句的情況將不能被正確轉義:
///#if( $jazz )
Vyacheslave Ganelin
//#end
|
這里,
#if
被轉義,但有一個
#end
被保留了;所以有多個結束語句將導致解析錯誤。
1.
VTL:
格式化
雖然在本指南中的
VTL
經常顯示在新行中或者有空格,但是下面的
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.
|
Velocity
的行為並不受空格的影響,前述的指令也可以寫成:
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.
|
上面每種寫法結果都一樣。
2.
其它特征和雜項
2.1.
數學特征
Velocity
有一些內建的數學功能,可以使用
set
指令用在模版中。下面的共識分別演示了加減乘除運算:
#set( $foo = $bar + 3 )
#set( $foo = $bar - 4 )
#set( $foo = $bar * 6 )
#set( $foo = $bar / 2 )
|
當進行除法運算時,結果將會是整數。
When a division operation is performed, the result will be an integer.
余數則可以通過模
(%)
運算獲得。
#set( $foo = $bar % 5 )
|
在
Velocity
中,只有整數可以進行數學運算;如果執行非整數的數學運算,將被記錄下來,並返回
null
。
2.2.
范圍操作符
范圍操作符可以和
#set
和
#foreach
語句一起使用。有助於產生一個整數的目標數組,范圍操作符有以下的結構:
[n..m]
|
n
和
m
都必須是整數或者可以產生整數。不管
m
大於或者小於
n
都沒關系;在
m
小於
n
這種情況下,范圍可以向下計數。下面是使用范圍操作符的例子:
第一個例子
#foreach( $foo in [1..5] )
$foo
#end
第二個例子
#foreach( $bar in [2..-2] )
$bar
#end
第三個例子
#set( $arr = [0..1] )
#foreach( $i in $arr )
$i
#end
第四個例子
[1..3]
|
他們分別產生一下輸出
1 2 3 4 5
2 1 0 -1 -2
0 1
[1..3]
|
范圍操作符和
#set
和
#foreach
指令一起使用時,只是產生數組。
頁面設計人員在設計具有相同尺寸的表格時,有時沒有足夠的數據來填充,他們會發現范圍操作符非常有用。
2.3.
進階:轉義和
!
當一個引用被
!
字符處於靜寂模式,並且
!
字符在轉義符
/
前出現,應用將用一種特別的方式處理。請注意他和常規轉義的不同,下面這種情況
/
先於
!
出現
:
#set( $foo = "bar" )
$/!foo
$/!{foo}
$//!foo
$///!foo
|
這樣將被加工成
$!foo
$!{foo}
$/!foo
$//!foo
|
對比常規轉義,
/
先於
$:
/$foo
/$!foo
/$!{foo}
//$!{foo}
|
這是結果是:
/$foo
/$!foo
/$!{foo}
/bar
|
3.
Velocimacro
雜記
本節是關於
Velocimacros
的一個小型
FAQ
。本屆內容會不時更新,所以請常來檢查新的內容,
注
:
本節中,
'Velocimacro'
將簡寫為
'VM'
。
Q:
是否可以使用指令
directive
或者
VM
作為另一個
VM
的參數
?
例如
: #center( #bold("hello") )
A:
不行。指令不能用作指令的參數,而大多數情況下,作為實際的應用,
VM
就是指令。
不過也有一些辦法。一個簡單的做法是使用雙引號來加工你的內容。所以,你可以這樣:
#set($stuff = "#bold('hello')" )
#center( $stuff )
|
甚至可以節省一個步驟:
#center( "#bold( 'hello' )" )
|
請注意,后面這個例子中,參數是在
VM
內部被求值,不是在調用的那一層次上。換句話說,被傳入的
VM
的參數是整個被傳入的,並且在傳入的
VM
內部被求值。所以我們可以這樣做:
#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()
內部,所以在
#outer()
內設置的
$bar
得值會是其使用的值。
這是一個有意的保護特征
—
參數按名稱傳遞給
VM
,所以可以將象狀態引用的東西傳給
VM
,比如:
#macro( foo $color )
<tr bgcolor=$color><td>Hi</td></tr>
<tr bgcolor=$color><td>There</td></tr>
#end
#foo( $bar.rowColor() )
|
rowColor()
被重復調用而不是一次。為避免如此,可以調用
VM
外部的方法,然后將值傳遞給
VM.
#set($color = $bar.rowColor())
#foo( $color )
|
Q:
是否可以通過
#parse()
注冊
VM ?
A
:當前,
Velocimacros
在其首次在模版中使用前必須首先定義它。這意味着,
#macro()
宣稱應該在使用
Velocimacros
之前。
如果你想
#parse()
一個包含
#macro()
指令的模板,記住這個非常重要。因為
#parse()
在運行時發生,解析器在解析時要決定是否模版中一個看起來像
VM
的元素真是
VM
,所以解析一系列
VM
宣稱可能並不能如願地工作的很好。為避免如此,可以簡單地使用
velocimacro.library
的辦法,使
Velocity
在啟動時載入
VM
。
Q.
什么是
VM
自動載入(
Velocimacro Autoreloading
)
?
A.
這是一個屬性,在開發時使用,而不時運行時:
velocimacro.library.autoreload
默認值為
false
。當設置為
true
時,連同
<type>.resource.loader.cache
屬性設置為
false
(這里
<type>
是使用的資源載入器的名稱,比如
'file')
,
Velocity
引擎在你創建
VM
庫文件是將自動載入其改變,這樣你就不必將其導入
servlet
引擎(或者應用程序)中,或者用其他手段來使其自動重新載入。
下面是一個簡單的設置配置組合:
file.resource.loader.path = templates
file.resource.loader.cache = false
velocimacro.library.autoreload = true
|
注意在生產狀態(運行時)不要使其打開。
4.
字符串聯
開發者常問的一個問題是“我如何進行字符串串聯?”是否有類似於
JAVA
中的
'+'
操作符?
為了串聯
VTL
中的引用,你不得不將它們
“
放在一起
”
。而你想要放置在一起的上下文很重要,下面舉例說明。
在常規“笨辦法”模板中:
#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.
|
結果是一樣的。作為最后一個例子,當你想混合“靜態”字符串到引用中,你可能需要使用“形式引用”:
#set( $size = "Big" )
#set( $name = "Ben" )
#set($clock = "${size}Tall$name" )
|
現在,輸出將會是
'The clock is BigTallBen'
。
|