1. 程式人生 > >《Apache Velocity使用者指南》官方文件

《Apache Velocity使用者指南》官方文件

原文連結   譯文連線 譯者:小村長  校對:方騰飛

Quick Start

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

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

Velocity官方看看。

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

導讀

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的力量。

怎麼應用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>

其他使用者

假如你想快速安裝你的應用, 很簡單把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” 目錄中.

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”。

Hello Velocity World例項

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

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

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

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

註釋

註釋以一種不被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
*#

引用

在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}"/>

嚴格引用模式

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

模式替換

現在你已經熟悉了引用, 你可以在你的模板中使用它們。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).

指令

引用允許設計者在網頁上生成動態的內容, 指令很容易使用指令碼元素來建立和操縱輸出的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

條件語句

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>

迴圈

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

引入

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

#include( "one.txt" )

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

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

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

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

解析

#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!” 語句.

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)

Define指令

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

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

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

巨集呼叫

#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 ). 這個特徵主要用於開發模式, 而不是生產模式.

獲取字面量

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 標籤; 多餘的標籤將導致解析錯誤.

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.

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

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 )

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 指令, 正如在第四個例子中展示的.

網頁設計者關係一個製作標準大小的表格, 有些情況下沒有足夠的資料填充表格, 將發現範圍操作符特別有用.

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

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

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

輸出結果為:

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

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

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

輸出結果為:

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

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

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

String Concatenation(字串的拼接)

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

為了實現在VTL中兩個字串的拼接VTL,