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
Velocity  也具有邏輯 AND, or    NOT  操作符。更進一步的信息,請看 VTL 參考手冊 VTL Reference Guide 。下面是一些演示如何使用邏輯操作符的例子:
## 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  文件中設爲從 或者 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  屬性
 velocity.properties  文件中有數行定義可以用來靈活實現 Velocimacros 。詳細情況請參見開發指南( Developer Guide )。
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]



 
   m  都必須是整數或者可以產生整數。不管  m  大於或者小於  都沒關係;在 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}
ar
 
 
 
 
 
 
 
 
 
 
 
 
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' 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章