Apache Velocity開發者指南

owes 8年前發布 | 48K 次閱讀 Velocity 模板引擎

Velocity–Quick Start

本項目是 Apache Velocity官方文檔的中文翻譯版,Velocity類似與JSP,是一種基于Java的模板引擎。它可以在web頁面中引用Java代碼中定義的數據和對象,而Velocity的作用就是把Web視圖和java代碼進行組裝在一起。本次翻譯主要針對對Velocity感興趣和工作中使用到Velocity的開發人員提供有價值的中文資料,希望能夠對大家的工作和學習有所幫助。

由于我也是第一次接觸Velocity,還不是很深入,翻譯的時候也查看了一些博客以及其他網上資料。也嘗試著去了解它和JSP方面的差別以及優缺點,同時也去了解了下它和其他Java引擎模板的區別,比如freemaker的區別,等等。但是還是因為能力見識有限,翻譯過程中難免出現個人的主觀或者客觀原因導致與官方文檔存在差異。在此,我還是建議有能力的童鞋能夠自己去Velocity官方看看。

譯者注:由于本次翻譯比較倉促,內部難免出現一些不合理的地方,小村長在此懇請大家發現錯誤能夠第一時間在評論中指出來,我會第一時間進行修改,避免給熱愛學習的同學造成誤解。同時,也希望大家多多提出錯誤和建議,小村長在此拜謝 ! ! !

  1. About this Guide(導讀)
  2. What is Velocity?(什么是Velocity)
  3. What can Velocity do for me?(Velocity能做什么)
    1. The Mud Store example(Mud 商店實例)
  4. What jar should I use?(怎么使用Velocity jar)
    1. Maven users(Maven用戶)
    2. Other users(其他用戶)
  5. Velocity Template Language (VTL): An Introduction(Velocity模板語言 (VTL): 簡介)
  6. Hello Velocity World!(Velocity簡單實例:Hello Velocity World)
  7. Comments(注釋)
  8. References(引用)
    1. Variables(變量)
    2. Properties(屬性)
    3. Methods(方法)
    4. Property Lookup Rules(屬性調用規則)
    5. Rendering(渲染輸出)
    6. Index Notation(索引標識符)
  9. Formal Reference Notation(正式引用標識符)
  10. Quiet Reference Notation(靜態引用標識符)
  11. Strict Reference Mode(嚴格引用模式)
  12. Case Substitution(大小寫轉換)
  13. Directives(指令)
    1. Set(集合)
    2. Literals(字面量)
    3. If-Else Statements(if-else語句)
      1. Relational and Logical Operators(關系和邏輯運算符)
    4. Foreach Loops(foreach循環)
    5. Include(引用,包含)
    6. Parse(解析)
    7. Break(中止)
    8. Stop(停止)
    9. Evaluate(計算)
    10. Define(定義)
    11. Velocimacros(宏)
  14. Getting literal(獲取字符)
    1. Currency(并發)
    2. Escaping Valid VTL References(轉義VTL引用)
    3. Escaping Invalid VTL References(轉義不可用VTL引用)
    4. Escaping VTL Directives(轉義VTL指令)
  15. VTL: Formatting Issues(VTL:格式討論)
  16. Other Features and Miscellany(其它特征和功能)
    1. Math(算術)
    2. Range Operator(范圍操作符)
    3. Advanced Issues: Escaping and !(高級討論:轉義和!)
    4. Velocimacro Miscellany(Velocimacro雜談)
    5. String Concatenation(字符串拼接)
  17. Feedback(反饋)

導讀

Velocity用戶向導,用于幫助頁面設計者和內容提供者,了解Velocity和它簡單有效的腳本語言, 這個腳本語言就是Velocity模板語言,簡稱 (VTL)。 在接下來的章節中,有很多實例使用Velocity嵌入動態內容到網頁中,但所有的VTL的實例在其他頁面和模板同樣適用。

感謝你選擇Velocity!

什么是 Velocity?

Velocity是基于Java的模板引擎,它允許頁面設計者引用Java中定義的方法。頁面設計者和Java開發者能夠同時使用MVC的模式開發網站,這樣網頁設計者能夠把精力放在頁面的設計上,程序員也可以把精力放在代碼開發上。Velocity把Java代碼從Web頁面中分離, 使網站可維護性更強,同時也在Java服務器頁面(JSPs)或者PHP中提供了可視化交互的選擇。

Velocity能夠使用模板生成Web頁面,  SQL,PostScript 和其他內容。并能夠生成的源代碼和報表中的一個獨立的單元,或者作為一個其他系統的組件。配置完成后,Velocity將提供為Turbine 頁面應用框架提供模板服務。 Velocity+Turbine將提供一個模板服務,它將允許網頁應用按照MVC的模式進行開發。

Velocity能夠做什么?

Mud商店實例

假如你是一個專賣mub的網上商城頁面設計者.。我們暫時稱它為”The Online Mud Store”。顧客訂購各種類型和數量的商品. 他們使用用戶名和密碼登陸你的網站, 登陸之后準許他們看到訂單,并購買更多的mud。就在現在, Terracotta Mud正在銷售,,而且十分暢銷。少部分用戶也購買 Bright Red Mud, 它也在銷售,但是并不十分暢銷,把它放在Web頁面的邊緣。通過數據庫來跟蹤每個顧客的信息,現在新問題出現了, 為什么不使用Velocity來對顧客感興趣的mud的類型進行特性處理呢?

Velocity很容易實現頁面按照訪問者來進行特殊定制。作為一個Mud商城的設計者,你思考一副這樣的場景,當你的顧客登陸網站之后,你將向他展示一個怎么樣的頁面。

你和你們公司的軟件工程師進行交流, 每一個人都贊同使用 $customer存儲當前登陸顧客的信息, $mudsOnSpecial將展示所有當前在售的mud類型信息。$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語句具體細節將在后面章節中詳細描述; 重要的是這個簡單的腳本在你網頁中的作用。當一個偏好Bright Red Mud登陸時, 并且Bright Red Mud 正處于銷售狀態,這就是消費者將要看到的,將會突出顯示。如果另一個長時間購買Terracotta Mud 記錄用戶登陸了,Terracotta Mud 將放在中間顯眼位置.。Velocity是很靈活的,受限制的僅僅是你的創造力 .

VTL文檔中應用了許多其他的 Velocity元素, 它們將給你展示一個靈活的有利的頁面。當你越熟悉這些元素,你將開始了解Velocity的力量。

</div>

</div>

怎么應用Velocity jar?

Velocity2.x版本需要幾個jar,已經發布到Maven倉庫,可以通過Maven來引用。

Maven 用戶

在你的POM文件中引用下面依賴:

<dependency>
  <groupId>org.apache.velocity</groupId>
  <artifactId>velocity-engine-core</artifactId>
  <version>x.x.x</version>
</dependency>

如果你想在Velocity中引入Logging, SLF4J, Log4j或者服務器logger日志, 在POM文件中添加一下依賴:

<dependency>
  <groupId>org.apache.velocity</groupId>
  <artifactId>velocity-engine-commons-logging</artifactId>
  <version>x.x.x</version>
</dependency>

<dependency>
  <groupId>org.apache.velocity</groupId>
  <artifactId>velocity-engine-slf4j</artifactId>
  <version>x.x.x</version>
</dependency>

<dependency>
  <groupId>org.apache.velocity</groupId>
  <artifactId>velocity-engine-log4j</artifactId>
  <version>x.x.x</version>
</dependency>

<dependency>
  <groupId>org.apache.velocity</groupId>
  <artifactId>velocity-engine-servlet</artifactId>
  <version>x.x.x</version>
</dependency>

</div>

其他用戶

首先,下載發布的Velocity版本。

假如你想快速安裝你的應用, 很簡單把velocity-x.x.x.jar放到你的classpath中:它包括所有的Velocity類 (還包括一些擴展實例)。包括所有的子目錄lib中的所有jar.

其他的jar你可能使用到.

  • velocity-engine-core-x.x.x.jar: Velocity的核心jar包,它必須被引用.
  • velocity-engine-commons-logging-x.x.x.jar: 它用來綁定通用的日志信息Logging, 所有的日志信息將指向它. 用在連接Logging (包括”lib” 目錄).
  • velocity-engine-slf4j-x.x.x.jar:它主要用來綁定SLF4J,所有的日志信息將指向它. 用在連接SLF4J (包括”lib” 目錄).
  • velocity-engine-log4j-x.x.x.jar: 它主要是綁定Log4j日志,所有的日志消息將使用它. 用在連接Log4j (包括 “lib” 的目錄).
  • velocity-engine-servlet-x.x.x.jar: 它主要用來綁定服務器日志. 使用在服務器容器中.

擴展的jar中你將需要 Commons Collections 和Commons Lang, 它已經包含在 “lib” 目錄中.

</div>

Velocity模板語言(VTL): 入門指南

Velocity模板語言 (VTL)提供了容易,簡單,和清潔方式合并動態內容在你的網頁上。即使一個網頁開發者有少量或者沒有編程經驗也能很快有能力使用VTL嵌入動態內容到你的Web頁面。

VTL使用引用嵌入動態內容到Web頁面, 一個引用也是一個引用類型. 變量是一種引用類型能夠引用Java中定義變量,或者能夠獲取它的值在你的Web頁面中通過VTL語句。這里有一個例子 VTL語句能夠被嵌入到你的HTML文檔中:

#set( $a = "Velocity" )

這個VTL 語句, 像所有的VTL語句一樣,通過 # 字符開始并包含一個指令: set. 當一個用戶訪問你的頁面時,Velocity模板 將在你的Web頁面中搜索所有的#字符, 然后認為它是VTL語句的開始,但是#字符并沒有實際意義。

字符 #后面緊跟著, set.set 指向一個表達式 (放在括號里面) — 一個等式為變量分配一個值。變量的定義在左邊賦值在右邊; 它們之間通過 = 分開。

在上面的實例中, 變量是 $a ,它的值是Velocity。這個變量像其它的引用一樣, 通過 $ 字符開始。字符串的值放在引號中,單引號或雙引號都可以。單引號保證引號里面的值分配給變量。雙引號準許你使用velocity的引用和指令,例如  “Hello $name”,  $name 將被定義的變量值=右邊的內容所替換

下面的規則能使你更好的了解Velocity的工作原理:引用是通過$ 開始的,用來獲取值。指令# 用來定義值。

在上面實例中, #set 被用來給變量分配一個值。這個變量是 $a, 能夠在模板中使用并輸出 “Velocity”。

</div>

Hello Velocity World實例

當一個值分配給一個變量時, 你能夠引用這個變量在你的HTML 文檔中.在下面的實例中, 先對 $foo 進行賦值,然后引用它.

<html>
<body>
#set( $foo = "Velocity" )
Hello $foo World!
</body>
<html>

這個網頁的結果是答應出 “Hello Velocity World!”.

為了是包含VTL語句指定可讀性更強, 我們鼓勵你開始每個VTL語句在新的一行, 但并不強制要求你這么做.set 指令將在后面章節詳細介紹.

</div>

注釋

注釋以一種不被Velocity模板修改的原樣輸出描述文本。注釋是一種很有用的方式,提醒你并且告訴其他人VTL語句的作用, 或者存放對你有用的其他信息。下面就是VTL注釋的實例:

## 這是一個單行注釋.

## 表示的是單行注釋表示本行都被注釋。假如你需要多行注釋, 不需要一行一行的注釋。你可以使用多行注釋, 多行注釋以 #* 開始,以 *#做為結束, 可以用它來處理多行注釋的情況.

這是多行注釋,瀏覽者能看到它。

#*
 Thus begins a multi-line comment. Online visitors won't
 see this text because the Velocity Templating Engine will
 ignore it.
*#

這里多行注釋; 它是可見的.

這里有很多實例闡明多行注釋和單行注釋:

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注釋塊, 它被用來儲存一些你需要關注的信息模板 (例如. javadoc作者版本信息):

#**
This is a VTL comment block and
may be used to store such information
as the document author and versioning
information:
@author
@version 5
*#

</div>

引用

在VTL中有三種類型的引用: 變量,屬性和方法。作為一個使用VTL的設計者, 你和工程師必須一起在你的模板中,指定名字以及它所代表的引用。

變量
VTL中變量標識符前面需要添加 “$” 來進行標記. AVTL標識符必須以字母 (a .. z or A .. Z)開始. 其他的字符可以使用下面幾種:

  • alphabetic (a .. z, A .. Z)
  • numeric (0 .. 9)
  • hyphen (“-“)
  • underscore (“_”)

下面有一些可用的變量引用實例在VTL中:

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

當VTL應用一個變量時, 例如$foo,這個變量可以獲取一個值從模板的 set指令中, 或者從Java代碼中。例如,假如在Java中定義了一個變量$foo,java中定義的值Web頁面中所有的 $foo引用. 或者, 我在頁面中定義下面語句

#set( $foo = "bar" )

$foo輸出的結果將和你定義的是一樣的。

屬性
VTL中第二個特點鮮明的引用是屬性引用, 屬性有一個與眾不同的格式. 它的標識符前面需要添加一個$變量標識符, 緊跟著后面一個點(“.”) . 下面是一個在VTL中屬性引用的實例:

$customer.Address
$purchase.Total

就拿第一個實例來說, $customer.Address.它有兩個意思. 它意味著,查詢被customer 標識的哈希表返回和它相關聯的Address 的值。同時$customer.Address也能被一個方法引用 (方法的引用在下一章在討論); $customer.Address$customer.getAddress()的一種縮寫形式。如果你的網頁有需求, Velocity 將可以使這兩種形式變的有意義, 然后返回正確的值。

方法
Java中定義的方法能夠定義很多有用的事情, 像進行計算或者達到某種目的. 方法的引用是通過 “$” 標識符, 后面緊跟著方法體. VTL方法體緊跟著左括號符  (“(“), 緊跟著參數列表, 緊跟著右括號符(“)”). 下面是VTL中方法引用的實例:

$customer.getAddress()
$purchase.getTotal()
$page.setTitle( "My Home Page" )
$person.setAttributes( ["Strange", "Weird", "Excited"] )

前兩個實例 — $customer.getAddress() 和 $purchase.getTotal() — 可以看著是屬性的引用, $customer.Address 和$purchase.總之.這些引用在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

自從Velocity 1.6, 所有的數組引用被看這固定長度列表. 這意味著你能夠調用java.util.Lis方法在數組引用。所以, 假如你有一個引用在數組上 ( 假定這里有一個字符數組后三個字),你能夠這樣做:

$myarray.isEmpty()
$myarray.size()
$myarray.get(2)
$myarray.set(1, 'test')

在Velocity 1.6支持可變參數方法. 一個方法 public void setPlanets(String... planets) 或者甚至是 public void setPlanets(String[] planets) (假如你使用Java 5 JDK), 現在可以接受任何數量的參數時調用的模板.

$sun.setPlanets('Earth', 'Mars', 'Neptune')
$sun.setPlanets('Mercury')
$sun.setPlanets()
## Will just pass in an empty, zero-length array

屬性調用規則
正如前面提到的, 屬性經常涉及到父類方法的引用. Velocity是十分擅長解決方法對應的屬性獲取,它可以根據幾種不同的命名約定進行選擇,準確的查找規則依賴是否屬性的名字以大寫開始。對于小寫名字,例如 $customer.address, 調用的順序是

  1. getaddress()
  2. getAddress()
  3. get(“address”)
  4. isAddress()

對于大寫的屬性名字像 $customer.Address, 它稍微不同:

  1. getAddress()
  2. getaddress()
  3. get(“Address”)
  4. isAddress()

渲染
每一個引用的值(變量,屬性,或者方法)都被轉換為一個字符串并作為最終的輸出。假如這里有一個對象表示為$foo (例如一個整數對象), 當Velocity調用它時,Velocity會調用它的.toString() 方法轉化為字符串.

索引標識符
使用$foo[0] 的符號形式能夠訪問被定義的索引對象。這個形式和通過get調用一個對象是相同的例如$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")

指定的元素被賦值給定的值。Velocity 嘗試第一次 ‘set’ 方法在元素上, 然后通過’put’ 來進行賦值.

正式引用標識符
上面的實例向大家展示了引用標識符的使用, 然后,Velocity也提供了正式引用標識符的引用, 請看下面實例:

${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. 正式引用經常被使用在引用指向鄰近文本的模板中.

靜態引用標識符
當Velocity遇到一個沒有定義的引用時,正常的是輸出圖像引用. 例如, 假如下面的引用是VTL模板的一部分.

<input type="text" name="email" value="$email"/>

當它初始化時, 變量 $email應用并沒有值, 但是你寧愿”$email”是一個空白文本字段 . 使用靜態引用標識符避免這種正規的行為; 通過在你的VTL模板中使用$!email代替$email。上面的實例可以改成下面這種形式:

<input type="text" name="email" value="$!email"/>

現在當初始化時如果$email沒有值, 一個空的字符串將輸出代替”$email”。

正式應用和靜態引用經常一起使用,就像下面實例一樣.

<input type="text" name="email" value="$!{email}"/>

</div>

嚴格引用模式

Velocity 1.6介紹了一種新的概念,就是嚴格引用模式,它是通過配置屬性的模式來實現靈活的設置。這種設置的目的是使Velocity的特性更加嚴格區分沒有定義或者模棱兩可的實例中, 類似與編程語言, 它更適合Velocity的使用。當遇到沒有定義或者模棱兩可的情況Velocity將拋出異常。下面將討論嚴格應用和傳統引用的不同之處。

設置引用要求在上下文中或者被#set 指令定義否則Velocity將拋異常。在上下文中引用一個null值并不會產生異常。此外,假如你企圖在一個對象中調用一個沒有定義的方法或者屬性時,它將拋異常。如果調用的方法或屬性是一個null值也會產生異常。

在下面的實例中 $bar被定義了但是 $foo卻沒有被定義,所有這些語句將拋出異常:

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

同時, 你調用一個并不存在的方法或屬性時,也會產生異常。在下面的實例中 $bar對象定義一個屬性 ‘foo’ 返回一個字符串 , ‘retnull’ 將返回null.

$bar.bogus          ## $bar does not provide property bogus, Exception
$bar.foo.bogus      ## $bar.foo does not provide property bogus, Exception
$bar.retnull.bogus  ## cannot call a property on null, Exception

一般嚴格引用使用所有情況除了特殊的 #if 指令.假如一個引用使用 #if 或者#elseif 指令沒有任何方法或屬性,假如它并沒有和其他值進行比較,這種引用是準許的.這種方式通常用來判斷一個引用是否被定義. 在下面的實例中$foo 并沒有定義但是它也不會拋異常.

#if ($foo)#end                  ## False
#if ( ! $foo)#end               ## True
#if ($foo && $foo.bar)#end      ## False and $foo.bar will not be evaluated
#if ($foo && $foo == "bar")#end ## False and $foo == "bar" wil not be evaluated
#if ($foo1 || $foo2)#end        ## False $foo1 and $foo2 are not defined

嚴格模式在 #if 指令中可以使用 >, <, >= or <=. 同時,參數 #foreach必須可以迭代的 (這種特性可以被屬性指令.foreach.skip.invalid修改). 不過,在嚴格模式下沒有定義的引用也將拋異常。

Velocity試圖調用一個null值將導致異常. 對于簡單的調用在這個實例中你可以用 ‘$!’代替 ‘$’, 這種類似于非嚴格模式。請記住,當你使用嚴格引用調用不存在的變量時會出現異常。例如, 下面的$foo 在上下文中值為null

this is $foo    ## throws an exception because $foo is null
this is $!foo   ## renders to "this is " without an exception
this is $!bogus ## bogus is not in the context so throws an exception

</div>

模式替換

現在你已經熟悉了引用, 你可以在你的模板中使用它們。Velocity引用利用了一些Java的設計原則進行設計,很容易使用。 例如:

$foo

$foo.getBar()
## is the same as
$foo.Bar

$data.setUser("jon")
## is the same as
#set( $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公司的bean定義的規范,大小寫敏感的; 然而,開發者盡可能的避免和糾正用戶可能出現的錯誤 . 當getFoo() 方法在模板中被 $bar.foo引用時, Velocity首先將嘗試著調用$getfoo。假如失敗了, 它將嘗試著調用$getFoo。同樣的, 當一個模板引用 $bar.Foo, Velocity首先將嘗試著調用 $getFoo() 然后在調用getfoo().

注意: 在模板中引用實例變量是不允許的。僅僅引用屬性等同于 JavaBean getter/setter 方法是可以的 (例如. $foo.Name能夠通過 Foo’s getName()實例方法來引用 , 但是不是對一個公共的Name 實例的變量Foo).

</div>

指令

引用允許設計者在網頁上生成動態的內容, 指令很容易使用腳本元素來創建和操縱輸出的Java代碼,并允許Web設計者關注網頁的內容。

指令一直以 #開始. 像引用一樣,指令的名字可能是相等的通過{ 和 } 符號. 這是好的方式在指令后跟文本. 例如下面的程序有一個錯誤:

#if($a==1)true enough#elseno way!#end

在這個實例中, 使用方括號把 #else 與其他行分開.

#if($a==1)true enough#{else}no way!#end

#set #set 指令被用來設定一個引用的值. 這個值能夠被分配一個變量引用或者屬性引用,這種情況發生在括號中, 如下實例:

#set( $primate = "monkey" )
#set( $customer.Behavior = $primate )

左邊的(LHS)必須分配一個變量引用或者屬性引用. 右邊的(RHS)可以是以下類型:

  • Variable reference
  • String literal
  • Property reference
  • Method reference
  • Number literal
  • 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($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

注釋: 對于定義的ArrayList 實例元素可以使用ArrayList 類里面定義的方法, 例如, 你能夠訪問上面第一個元素使用$monkey.Say.get(0).

相似的, 對于Map實例, 元素通過 { } 操作符來定義你能夠使用Map類中定義的方法. 例如, 你能夠訪問上面實例中第一個元素通過$monkey.Map.get(“banana”) 并且返回 ‘good’, 甚至你可以使用 $monkey.Map.banana來返回一樣的值.

RHS也能使用簡單的算術表達式:

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

假如RHS是一個null的屬性和方法引用, 它將不能分配給LHS.這主要依賴你的配置,通過這種機制通常不能移除一個已經存在的引用. (注意它準許你改變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 循環企圖#set一個應用通過一個屬性或者方法引用是很迷惑的,接著通過 #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  (被移除從上下文中). #if 和 #foreach指令相關的細節將在之后的文檔中都涉及到.

一種解決這種情況通過預設 $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語句.

Literals當你使用 #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配置來改變這種默認設置.

或者,  #[[don’t parse me!]]# 語法準許模板設計者很容易的使用大量的語句塊,而這些語句塊中的變量不會被解析. 它特別有用尤其在避免有大量的指令上地方或者其他無效的內容(不想被解析的)VTL.

#[[
#foreach ($woogie in $boogie)
  nothing will happen to $woogie
#end
]]#

顯示如下:

#foreach ($woogie in $boogie)
  nothing will happen to $woogie
#end

</div>

條件語句

If / ElseIf / Else

Velocity中 #if 指令可以包含一段文本當生成Web網頁時, 當條件語句為true時. 例如:

#if( $foo )
   <strong>Velocity!</strong>
#end

變量$foo計算出是否是true,下面三種情況哪種情況將發生:

  • 如果是true值時,$foo是一個 boolean類型 (true/false)
  • 如果不為空對象或空值時,$foo是一個字符串或條件表達式。
  • 如果不為空對象,且不是字符串或條件表達式時,$foo是一個對象。

記住 Velocity上下文僅僅包含對象,所以當我們說 ‘boolean’,它將代表 Boolean (類)。這是真實的即使這個方法返回的值為布爾值,它內部其實返回的是一個Boolean 值。如果if為true #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,所以第一個兩個比較是false。下一個$bar 和6相等, 所以顯示true, 所以輸出 Go South。

關系和邏輯操作符

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中的語法是不同,Java中==僅僅表示對象是否相等. Velocity中的等號操作符僅僅表示兩個數字,字符串,或對象的比較。當兩個類對象是不同時, 字符串是通過調用toString()來獲取的然后來比較.

Velocity的邏輯操作符有AND, OR 和NOT 操作符. 下面的邏輯操作符顯示了 AND, OR 和NOT 操作符的使用.

## logical AND

#if( $foo && $bar )
   <strong> This AND that</strong>
#end

#if() 指令結果為true 假如 $foo$bar都為true. 如果 $foo為false,表達式的結果為 false; $bar將不會計算. 如果 $foo 為 true,Velocity模板將計算$bar的值; 如果 $bar為 true, 然后整個表達式為true輸出 This AND that . 如果 $bar為 false,如果表達式為false這里將沒有輸出.

邏輯表達OR 操作符也是這種情況,僅僅只有一種情況需要計算總個表達式,就是整個表達式為true.思考下面的實例.

## logical OR

#if( $foo || $bar )
    <strong>This OR That</strong>
#end

如果$foo為 true, Velocity模板不需要計算$bar; 不管$bar 是否為 true 或 false, 這整個表達式為true,This OR That 將被輸出. 如果 $foo 為 false, 然而, $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 . 注意不要把它和靜態引用 $!foo which混淆,它們是不同的。(ifeve.com校對注:一個!在前,一個在后)

這里也有字符形式的邏輯運算符如 eq, ne, and, or, not, gt, ge, lt, 和le.

溫馨提示.當你希望在#else 指令后面包含一個文本你需要把else放在一個大括號 里面來表示它與后面的文本是不同的. (任何指令都能被放在括號里面, 通常用在#else中).

#if( $foo == $bar)it's true!#{else}it's not!#end</li>

</div>

循環

Foreach LoopThe #foreach元素用來循環操作. 例如:

<ul>
#foreach( $product in $allProducts )
    <li>$product</li>
#end
</ul>

#foreach循環將把 $allProducts列表里面的值賦值給products . 每次遍歷, $allProducts 里面的值將賦值給$product.

$allProducts 變量的內容是一個數組, Hashtable 或者 Array. 分配給$product 變量的值是Java的對象和一個變量的引用. 例如, 假如 $product是Java里面一個真實的Product類, 它的名字能夠被引用 $product.Name 方法(ie: $Product.getName()).

比方說 $allProducts 是一個Hashtable. 假如你想引用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>$foreach.count</td><td>$customer.Name</td></tr>
#end
</table>

Velocity也提供了一種簡單的方式來判斷是否是最后一次迭代 :

#foreach( $customer in $customerList )
    $customer.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 的配置文件里面. This is useful as a fail-safe.

# The maximum allowed number of loops.
directive.foreach.maxloops = -1

如果你想停止一個foreach 循環在你的模板中, 你可以使用 #break指令在任何時候停止循環:

## list first 5 customers only
#foreach( $customer in $customerList )
    #if( $foreach.count > 5 )
        #break
    #end
    $customer.Name
#end

</div>

引入

#include腳本元素準許設計者引入一個本地文件, 然后插入到你#include 指令所在的地方。文件的內容不經過模板引擎處理. 由于安全的原因,這個文件僅僅能夠放在 TEMPLATE_ROOT下面.

#include( "one.txt" )

#include 指定指向的文件放在括號之內. 假如包含多個文件,通過逗號進行分開.

#include( "one.gif","two.txt","three.htm" )

被引用的文件不需要通過名字引用; 實際上,通常使用一個變量來代替文件名。當你請求輸出標準頁面時非常方便。下面實例展示了文件名和變量.

#include( "greetings.txt", $seasonalstock )

</div>

解析

#parse腳本元素準許模板設計者引用一個包含VTL的本地文件。Velocity將解析其中的VTL并輸出里面的元素。

#parse( "me.vm" )

向 #include指令, #parse可以被看著攜帶一個變量而不是模板. 任何被 #parse 指令引用的模板必須放在TEMPLATE_ROOT下面. 不像 #include指令, #parse 僅僅攜帶了一個參數.

VTL模板中#parse應用的文件能夠夠嵌套引用包含#parse的模板. 默認為 10, 用戶可以通過velocity.properties 中directive.parse.max.depth來自定義設置單個文件中#parse引用文件個數. (注意: 如果 velocity.properties文件中directive.parse.max.depth沒有設置, Velocity默認為10.) 準許遞歸調用, 例如,如果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, 把count設置為8. 當count大于0, 它將顯示 “All done with parsefoo.vm!” . 本實例中, Velocity將返回 dofoo.vm 并輸出 “All done with dofoo.vm!” 語句.

</div>

Break

#break指令停止任何正在執行的作用域中的輸出. 執行作用域是本質上是 with content (i.e. #foreach, #parse, #evaluate, #define, #macro, 或者 #@somebodymacro) 或者 任何”root” 作用域(例如. template.merge(…), Velocity.evaluate(…) or velocityEngine.evaluate(…)). 不像#stop, #break 它僅僅停止的是循環內部, 作用域內部, 而不是整個程序.

如果你希望停止一個正在執行的作用域, 你可以使用作用域控制引用(例如. $foreach, $template, $evaluate, $define, $macro, or $somebodymacro) 作為一個參數#break. (例如. #break($macro)). 它將停止輸出所有的到指定的一個. 在同一類型的嵌套范圍內, 你能夠訪問它的父親通過 $<scope>.parent 或者 $<scope>.最高的和傳遞這些到#break 代替(例如. #break($foreach.parent) o或者 #break($macro.topmost)).

Stop指令

#stop 指令停止任何正在執行的輸出。這是真實的即使嵌套另一個模板通過 #parse 指令或者位于一個velocity macro. 合并輸出將包括所有的內容到遇到 #stop 指令的位置. 它是很方便的隨時終止模板解析.出入調試的目的, 你可以提供一個將被寫到stop命令執行前日志 (DEBUG 級別, 當然是)消息參數 (例如. #stop(‘$foo 并不在內容中’) ).

Evaluate指令

#evaluate指令用來動態的計算。它可以在加載的時候適時計算一個字符串. 例如一個字符串可能被用來國家化或則包括一部分數據庫模板.

下面的實例將顯示abc.

#set($source1 = "abc")
#set($select = "1")
#set($dynamicsource = "$source$select")
## $dynamicsource is now the string '$source1'
#evaluate($dynamicsource)

</div>

Define指令

#define指令可以指定對VTL一個塊的引用.

下面的實例將顯示: Hello World!.

#define( $block )Hello $who#end
#set( $who = 'World!' )
$block

</div>

宏調用

#macro 腳本元素準許模板設計者定義一個可重用的VTL模板片段. Velocimacros(宏調用)被廣泛用在簡單和復雜的場景中.Velocimacro可以用來保存用戶的點擊次數和最少的板式錯誤, 提供一個簡單的概念介紹。

#macro( d )
<tr><td></td></tr>
#end

上個實例中Velocimacro被定義為d, 它可以像其他VTL方式一樣被調用:

#d()

#d()被調用的時, Velocity將用定義的一行內容來替換#d().如果你想在行里面添加內容, 你也可以向下面這樣來改變macro的定義:

#macro( d )
<tr><td>$!bodyContent</td></tr>
#end

現在, 如果你想調用macro會和之前有點不同, 名字之前需要加上#@ 加上一個內容體,同時以#end調用, 當Velocity加載時遇見 $!bodyContent會進行顯示:

#@d()Hello!#end

如果你一直堅持像之前那種方式調用, 我們使用隱形的引用代替body引用($!bodyContent 代替$bodyContent), 它將一直顯示一個空的單元格.

Velocimacro也可以攜帶許多參數 — 甚至是不帶參數, 如同第一個實例中, 參數是可選項– 但是當Velocimacro執行時, 它必須調用和你定義的方法的參數匹配. 被執行的Velocimacros要多于上面定義的. 下面實例所示一個Velocimacro攜帶兩個參數一個是color和一個數組.

#macro( tablerows $color $somelist )
#foreach( $something in $somelist )
    <tr><td bgcolor=$color>$something</td></tr>
#end
#end

上面的Velocimacro實例中, 定義一個tablerows,帶兩個參數. 第一個參數是$color, 第二個參數是 $somelist.

任何可以被放到VTL模板中都可以作為Velocimacro的函數體.  tablerows 是Velocimacro的一個 foreach語句. 這里有兩個 #end語句被定義在#tablerows中; 第一個是屬于 #foreach, 第二個是屬于Velocimacro .

#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模板。定義一個Velocimacro并在所有模板中共享,這使它具有明顯的優勢: 它避免了在各個頁面中重復定義Velocimacro, 減少工作量并且可以避免錯誤, 這種也可以通過改變一個地方而達到其他地方一起修改的目的.

#tablerows($color $list) Velocimacro 被定義在 Velocimacros 模板的依賴包中, 它可以保證在其他地方被大量使用. 它能夠被多次重復使用來解決不同的問題. 在模板 mushroom.vm 中專注與正真的事情,#tablerows Velocimacro 能夠被遍歷,顯示所有部分:

#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 ArgumentsVelocimacros可以攜帶下面的VTL元素作為參數 :

  • Reference : anything that starts with ‘$’
  • String literal : something like “$foo” or ‘hello’
  • Number literal : 1, 2 etc
  • IntegerRange : [ 1..2] or [$foo .. $bar]
  • ObjectArray : [ “a”, “b”, “c”]
  • boolean value true
  • boolean value false

當傳遞一個引用作為Velocimacros的參數時,注意引用是通過名字傳遞的. 這意味著它們的值是在Velocimacro中已經生成了. 這個特性準許你傳遞一個方法的調用引用在方法中也可以使用方法調用. 例如, 當我們調用下面的Velocimacro將顯示

#macro( callme $a )
         $a $a $a
     #end

     #callme( $foo.bar() )

在方法中 bar() 的結果將被調用三次.

第一次看到這個特性會發現很驚奇, 當你仔細的思考Velocimacros背后的動機–消除VTL中公共的重復使用 –它變的有意義. 它準許你做一些事情,比如傳遞一個對象的狀態, 例如在Velocimacro中重復生成有顏色的表格對象.

如果你不想使用這個特性,你就想從一個引用的方法中獲取值,你可以這樣做 :

#set( $myval = $foo.bar() )
     #callme( $myval )

Velocimacro Propertiesvelocity.properties 文件中準許靈活的實現Velocimacros. 這里也提供了開發者文檔Developer Guide.

velocimacro.library – 一個通用的和其他依賴包分開的 Velocimacro模板依賴包. 默認, Velocity看起來想一個單獨的 函數庫: VM_global_library.vm. 配置模板的路徑用來使用找到Velocimacro 函數庫.

velocimacro.permissions.allow.inline – 這個屬性的值可以是true或者false, 決定是否可以在模板中定義Velocimacros. 默認情況是, true, 準許模板設計者可以自行定義Velocimacros.

velocimacro.permissions.allow.inline.to.replace.global -它的值可以設定為true或者false, 這個設置準許用戶指定一個模板中定義的Velocimacro能代替全局定義, 它在啟動的時候被 velocimacro.library屬性加載. 默認是, false, 避免在啟動時候模板中定義的Velocimacros成為全局Velocimacros.

velocimacro.permissions.allow.inline.local.scope – 這個屬性可能值為true 或者 false, 默認為 false, 控制 定義的Velocimacros對定義中的模板是可見的.簡而言之, 如果這個屬性設置為 true, 一個模板能夠定義能夠被定義的模板使用的VMs內 . You can use this for fancy VM tricks – if a global VM calls another global VM, 在行內的作用域內, 一個模板能夠定義一個私有的實現第二個VM,它能被第一個VM調用. 但是對其他模板沒有影響.

velocimacro.library.autoreload – 這個屬性控制Velocimacro依賴包自動加載. 這個默認是的是false.當把屬性設置為 true,當Velocimacro被執行時它將檢查Velocimacro是否改變, 它重載很有必要的.它準許你改變和測試Velocimacro 不需要重慶你的應用和服務器容器, 僅僅像你可以用普通的模板. 這個模式需要關閉緩存才起作用(e.g.file.resource.loader.cache = false ). 這個特征主要用于開發模式, 而不是生產模式.

</div>

獲取字面量

VTL使用了特殊字符,例如 $ 和 #, 做為關鍵字, 所以一些使用者關注在模板中怎么使用這些字符.這章將討論轉義字符 .

Currency(通用)
你這樣寫是沒有問題的 “I bought a 4 lb. sack of potatoes at the farmer’s market for only $2.50!” 像上面提到的一樣, VTL 標識符一直都是以大寫或者小寫的字母開始的, 所以 $2.50 不會被錯誤引用.

Escaping Valid VTL References(屏蔽VTL中的引用)
你可能遇到這種情況,在Velocity中不想有一個引用輸出. 屏蔽特殊的字符是輸出特殊字符的最好的方式, 你可以使用反斜杠字符,當遇見這些特殊的字符是VTL引用的一部分時. *

#set( $email = "foo" )
$email

假如在你的Velocity 模板中遇到一個 $email,它將在上下文中查詢并輸出正確的值. 上實例中將輸出 foo, 因為$email 已經被定義了.如果 $emailis沒有被定義, 它將輸出$email.

加入 $email 已經定義了 (例如, 它的值為 foo), 但是你想輸出 $email. 這里有幾種方式可以實現, 最簡單的方式是使用轉義字符. 請看下面實例:

## The following line defines $email in this template:
#set( $email = "foo" )
$email
\$email

輸出

foo
$email

如果,由于某種原因, 你需要在它之前添加一個反斜杠, 你需要按照下面實例做:

## The following line defines $email in this template:
#set( $email = "foo" )
\\$email
\\\$email

輸出結果

\foo
\$email

注意 \ 字符綁定到$ 左邊的字符. 左邊綁定規則導致 \\\$email 輸出為\$email. 比較下面實例看看$email是否被定義.

$email
\$email
\\$email
\\\$email

輸出

$email
\$email
\\$email
\\\$email

注意Velocity定義的引用不同于那些沒有定義的引用 . 本實例中$foo 定義值為gibbous.

#set( $foo = "gibbous" )
$moon = $foo

輸出結果為: $moon = gibbous$moon將作為字符輸出而$foo的地方將輸出gibbous.

Escaping Invalid VTL References(轉義不可用VTL引用)
有時候你可能會遇到這種情況,當你的Velocity解析你的模板時遇見了一個你從來都沒有打算把它當著引用的不可用的引用. 屏蔽特殊的字符, 最好的方式是你能夠處理把握這種情況,在這種情況下, 反斜杠可能會失敗. 你可以使用簡單的方式來屏蔽關于 $ 或 #問題, 你可能僅僅是替換一下:

${my:invalid:non:reference}

可以想這樣

#set( $D = '$' )
${D}{my:invalid:non:reference}

你也可以通過Java代碼把  $ 或 #字符串指令放到你的文本中  (例如 context.put("D","$");)來避免在你的模板中添加額外的 #set() 指令. 或者, 你也可以使用VelocityTools, 你可以使用EscapeTool:

${esc.d}{my:invalid:non:reference}

有效的和無效的VTL 指令使用同樣的方式進行轉義的; 在指令章節將對此進行詳細描述.

Escaping VTL Directives(轉義VTL指令)
VTL 指令能夠被屏蔽通過反斜杠(“\”) 字符和疲敝VTL引用方式是一樣的.

## #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" )

需要特別關心的是轉義在一個單獨的指令中包含多個腳本元素VTL 指令(例如在一個 if-else-end語句). 這里是一個典型的VTL if語句:

#if( $jazz )
    Vyacheslav Ganelin
#end

如果 $jazz為 true, 輸出結果為

Vyacheslav Ganelin

如果$jazz 為false,這里沒有任何輸出. Escaping 腳本元素修改輸出結果. 考慮下面實例:

\#if( $jazz )
    Vyacheslav Ganelin
\#end

它將導致指令被忽略, 但是變量 $jazz 正常顯示. 所以, 如果$jazz 為 true,輸出結果是

#if( true )
     Vyacheslav Ganelin
 #end

如果腳本之前的元素被反斜杠轉義:

\\#if( $jazz )
   Vyacheslav Ganelin
\\#end

在本實例中, 如果$jazz 為 true,輸出為

\ Vyacheslav Ganelin
\

為了了解這一點,注意 #if( arg ) 如果在新的一行結束時,輸出時將省略這一行. 另外,  #if() 的語句塊將緊跟著 ‘\’,   在#if()之前加入兩個'\\'. 最后的 \和文本在不同的行因為在 ‘Ganelin’之后有一個新行, 所以最終\\, #end 之前的部分是程序體.

如果$jazz是 false, 輸出結果為

\

注意一些執行將被中斷如果元素沒有屬性被轉義.

\\\#if( $jazz )
    Vyacheslave Ganelin
\\#end

這里 #if 被轉義, 但是這里保留一個 #end 標簽; 多余的標簽將導致解析錯誤.

</div>

VTL: Formatting Issues(格式化問題)

雖然VTL的用戶使用指南中經常顯示換行符和空格,VTL顯示如下

#set( $imperial = ["Munetaka","Koreyasu","Hisakira","Morikune"] )
#foreach( $shogun in $imperial )
    $shogun
#end

上面實例和下面實例是等效的, Geir Magnusson Jr. 寫給用戶的郵件來說明這點完全無關:

Send me #set($foo=["$10 and ","a pie"])#foreach($a in $foo)$a#end please.

Velocity可以去掉多余的空格. 前面的指令可以寫成:

Send me
#set( $foo = ["$10 and ","a pie"] )
#foreach( $a in $foo )
$a
#end
please.

or as

Send me
#set($foo       = ["$10 and ","a pie"])
                 #foreach           ($a in $foo )$a
         #end please.

在這些實例中輸出結果將是一樣的.

</div>

Other Features and Miscellany(其他的特性和雜記)

Math(算術操作)

Velocity中內置了一個算術函數,這些函數你可以在VTL模板中進行調用 .下面的實例分別展示加減乘數的使用:

#set( $foo = $bar + 3 )
#set( $foo = $bar - 4 )
#set( $foo = $bar * 6 )
#set( $foo = $bar / 2 )

當兩個整數相除時,結果是整數, 小數部分被丟棄. 模板中也可以使用求模運算符 (%).

#set( $foo = $bar % 5 )

</div>

Range Operator(范圍操作符)

范圍操作符能夠結合著 #set 和 #foreach 語句使用. 用它能夠產生一個證書數組,它的語法結果如下:

[n..m]

產生一個n到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]

輸出結果為:

First example:
1 2 3 4 5

Second example:
2 1 0 -1 -2

Third example:
0 1

Fourth example:
[1..3]

注意范圍操作符僅僅產生數組當結合 #set 和 #foreach 指令, 正如在第四個例子中展示的.

網頁設計者關系一個制作標準大小的表格, 有些情況下沒有足夠的數據填充表格, 將發現范圍操作符特別有用.

</div>

Advanced Issues: Escaping and !(高級問題:轉義和!)

當一個引用前面加上! 字符和! 字符前面加上一個 \ 轉義字符, 這種引用需要一種特殊的處理方式. 注意正規的轉義符和特殊的\之后緊跟 !實例的不同:

#set( $foo = "bar" )
$\!foo
$\!{foo}
$\\!foo
$\\\!foo

輸出結果為:

$!foo
$!{foo}
$\!foo
$\\!foo

對比這個正規 \ 優先$的轉義:

\$foo
\$!foo
\$!{foo}
\\$!{foo}

輸出結果為:

$foo
$!foo
$!{foo}
\bar

</div>

Velocimacro Miscellany(雜記)

這一章節是關于Velocimacros一些小疑問.本章節以后還會經常改變 , 所以它很值得你關注.

Note : 貫穿整個章節, ‘Velocimacro’ 將被簡寫成 ‘VM’.

Can I use a directive or another VM as an argument to a VM?Example : #center( #bold("hello") )

No. 一個指令不是一個可用的指令參數, 出于實用的目的, 一個VM是一個指令.

然而…, 這里有很多事情你需要做. 一個容易的解決方案是利用編譯器 ‘doublequote’ (“) 輸出顯示它的內容. 你可以想下面方式來做

#set($stuff = "#bold('hello')" )
#center( $stuff )

You can save a step…

#center( "#bold( 'hello' )" )

在這個實例中參數是在VM中計算的,而不是在調用時 . 簡而言之, the argument to the 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()的內部, 所以 $bar 的值是在 #outer() 內部進行賦值的.

這是一種有意的保護功能 – 參數通過名字傳遞到VMs, 所以你能夠傳遞VMs像狀態引用,例如

#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 )

Can I register Velocimacros via #parse() ?Yes! This became possible in Velocity 1.6.

如果你使用之前的版本, 你的Velocimacros必須第一次使用之前就已經被定義 .它的意思是有的當你使用  #macro()之前都已經被定義了.

這是很重要的如果你試圖 #parse() 一個包含#macro() 指令模板. 因為 #parse() 在運行時才被調用,解析時 解析器決定是否在你的模板中 VM-looking 元素是一個 VM, #parse()-ing 設置 VM 聲明并不向期望那樣工作. 為了避開這一點, 可以使用 velocimacro.library來使Velocity啟動時重新加載VMs.

What is Velocimacro Autoreloading?這個屬性用在開發模式下,  而不是生成環境 :

velocimacro.library.autoreload

默認是false. 當設置為true時

<type>.resource.loader.cache = false

( <type> 是你使用資源的名字, 例如 ‘file’) 然后Velocity將自動加載已經修改的Velocimacro依賴包文件當你配置該選項時, 所以你不比清空你的服務器(或者引用的)或者通過其他方式來是Velocimacros重載.

這里是一個簡單的配置文件設置.

file.resource.loader.path = templates
    file.resource.loader.cache = false
    velocimacro.library.autoreload = true

在生產環境不能使用這種配置.

</div>

String Concatenation(字符串的拼接)

開發者經常會問一個很普通的問題,就是怎么去拼接兩個字符串?是不是類似于Java里面的’+’?. 

為了實現在VTL中兩個字符串的拼接VTL, 你僅僅需要把它們放在一起. 你需要把他們放在一起當你需要的時候, 請看下面實例.

在一個有規則的 ‘schmoo’ 模板 (當你添加一個有規則的內容時) :

#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.

它們的輸出結果是一樣的. 作為最后一個實例, 當你想在你的引用中添加一個 ‘static’字符串時 , 你需要使用正式的引用 :

#set( $size = "Big" )
      #set( $name = "Ben" )

      #set($clock = "${size}Tall$name" )

      The clock is $clock.

現在輸出的是 ‘The clock is BigTallBen’。正式引用解析能夠把 ‘$size’ 和’$sizeTall’ 通過 ‘{}’ 進行區分開.

</div>

</div>

反饋

假如你在這篇文檔中遇見任何錯誤或者對Velocity用戶指南有關的建議和意見, 請發送郵件到 Velocity開發者列表 。謝謝!(校對注:如果你對譯文有什么建議也歡迎聯系并發編程網ifeve.com)

原創文章,轉載請注明: 轉載自并發編程網 – ifeve.com

</div>

 本文由用戶 owes 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!