《Velocity 模板使用指南》中文版

    html

1.本文目地和使用對象java

2.什麼是Velocity?git

3.Velocity能爲你作什麼?程序員

1.一個Mud Store Exampleweb

4.Velocity Template Language (VTL): 介紹express

5.輸出第一個VTL頁面!apache

6.Comments(註釋)編程

7.References(引用)api

1.Variables(變量)數組

2.Properties(屬性)

3.Methods(命令)

4.屬性引用中的屬性查找規則

8.Formal Reference Notation(正規引用格式注意事項)

9.Quiet Reference Notation(靜態引用輸出)

10.Getting literal( 語義問題)

1.Currency(貨幣標誌)

2.Escaping Valid VTL References(封裝有效的引用)

11.Case Substitution(可選的格式)

12.Directives(指令符號)

1.#set指令

2.Literals (語義解析)

3.Conditionals(條件判斷)

4.Loops(循環)

3.Include(引入)

6.Parse(解析模板)

7.Stop

8.Velocimacros(宏調用)

13.注掉 VTL Directives

14.VTL: 通常使用的格式

15.Other Features and Miscellany(其它特性和細節)

1.數學計算

2.Range Operator

3.Advanced Issues: Escaping and !

4.Velocimacro Miscellany(關於宏的一些問題)

5.String Concatenation(連結字符串)

16.Feedback

 

1.本文目地和使用對象

本文主要介紹如何在模板中使用Velocity功能強大的模板語言VTL(Velocity Template Language)用法有一個全面的認識,並掌握如何在模板中有效使用。同時,本文提供較多的例子幫您來學習它.

感謝您選擇Velocity幫助您實現純正的MVC系統構架。

2.什麼是Velocity?

Velocity 是一個基於java的模板引擎(template engine). 它可讓視圖的設計者在web頁面中引用java代碼中定義的數據對象和命令。從而使Web designers和java開發者依照MVC思想(Model-View-Controller )開發系統,這意味着Web designers只須將精力注用於良好表現力的視圖外觀設計,而Java程序員則只要關心着如何寫出高效簡潔的java對象以實現業務邏輯 -----Velocity會將他們組裝到一塊兒. 相比傳統的jsp、PHP等腳本語言,Velocity完全的將避免了在視圖設計中出現的java代碼, 從而保證了web site的長期可維護性.

一 定要理解,Velocity是一個template engine的意思,它還能夠從模板中生成SQL語句或其它腳本提供給web pages. 它也能夠獨立使用---作爲一個工具類(utility class)用來生成源代碼、報表、郵件模板等---在有須要重複的視圖狀況下,你應想到使用Velocity.Apache站點提供的另一個框架Turbine 能夠和Velocity有效結合以實現true MVC model.

3.Velocity能爲你作什麼?

1.一個Mud Store Example

假 設你是一個page designer 在爲一個在線商店設計頁面. 咱們稱這個項目爲 "The Online Mud Store".業務發展還不錯,客戶會訂購不一樣類型的MuD,每一個客戶都會用本身的賬號密碼login,查看選擇他們訂購的MuD,查看訂單,但還有些忠 誠用戶會購賣不太流行的MuD----這些不須要出如今頁面中顯眼的地方。固然,The Online MuD Store必須把每一個客戶資料及訂購信息記錄到DB中,如今的問題是,如何讓某個客戶login後就看到他感興趣的信息?

使用Velocity!咱們爲每一個客戶定製一個頁面!這聽起來工做量巨大,讓咱們試試:.

使用Velocity的 VTL 以下來設計 web page:

<HTML>

<BODY>

##指定用戶名字

歡迎你: $customer.Name!

<table>

###輸出用戶喜愛的MuD

#foreach( $mud in $mudsOnSpecial )

   #if ( $customer.hasPurchased($mud) )

      <tr>

        <td>

          $flogger.getPromo( $mud )

        </td>

      </tr>

   #end

#end

</table>

使用VTL設計頁面就是這麼簡單!文檔《VTL參考中文版》中有更全面的VTL語言介紹,掌握這些,你將會全面體會到Velocity的威力.

4.Velocity Template Language (VTL): 介紹

The Velocity Template Language (VTL)目標是提供一個簡潔,易學的方法將動態內容展示到web page上. a web page設計者能夠沒有任何編程經驗就能夠在一天內學會使用它加強你的站點的展現力!.

VTL使用引用(references )這種方式將dynamic content(動態內容,通常指java代碼生成的數據對象)加入到你的web site,Velocity中的變量(variable)只是refernce中的一種. Variables是用來描述從引入到視圖模板中的java數據對象。固然,java代碼也能夠從模板的VTL中獲取數據.如下是一個寫在HTML中的 VTL變量:

#set( $a = "Velocity" )

VTL聲明( statement),因此的VTL statement都是以#開頭,且包含一個指示符(這裏是set),當客戶訪問你的頁面時, the Velocity Templating Engine將搜索頁面中的全部 # 符號,若是肯定這是一個VTL聲明時就按必定規則處理動態內容, 符號#僅僅只是代表這多是一個VTL聲明.

符號# 所跟的set咱們用「指示符」這一名詞來稱呼它(隨後介紹更多的指示符), set 指示符使用一個表達式(expression) (包含在一對括號裏) –將一個值 value (這裏是Velocity)付給變量a,(變量名在左邊,值在右邊,用=組合起來).

在以上的例子中,變量是a ,而符號「$」代表它是一個變量,Velocity中全部變量以符號」$」開頭,所付的值要用雙引號括起, 這個值中還能夠再添加Velocity變量,如"Hello $name",輸出的將是name變量所付的值。

這是理解VTL基礎的規則:

 以$開頭的表示「引用」意思是取得一些東東.而」指示」(Directives)則以#開頭來表示,有點「作些什麼動做」的意思.

如上便, #set 用來指定值給一個變量名$a, 以「$」標示的變量名a的值就是"Velocity".

5.輸出第一個VTL頁面!

有你的HTML文檔的任何地方,均可以引用一個變量名來輸出值, 以下例, 先給變量名foo 賦值爲Velocity,而後將它輸出到頁面中.

<html>

<body>

 

#set( $foo = "Velocity" )

Hello $foo World!

</body>

<html>

在這個頁面上,你看到的將是 "Hello Velocity World!".

爲了讓查板中的VTL指令更易讀, 咱們強烈建議你每行一條VTL指令,固然這不是必須的. 關於 set directive的更多功能咱們隨後再討論.

6.Comments(註釋)

Comments可讓你在模板中包含對VTL或其它問題的說明描述以便與閱讀和理解.---但它並不會在最終輸出的web pages中看到.以下示例是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.

*#

 

不須要太複雜了,這兩種方式己足夠你給本身的頁面加上充分的說明。

7.References(引用)

VTL 中有三種references:變量引用(variables),屬性引用(properties)和命令引用(methods). 作爲一個使用VTL的設計者, 你和你的java軟件工程師必須就模板中引用的特定名了(就是$後的名字)達成一致的協議!這樣,模板和java代碼纔可按照大家的意圖去結合以輸出正確 的內容.

全部的引用在模板中都表現爲一個字符串. 假設一個引用變量 $foo 的值事實上是一個int, Velocity engine在處理時將調用它的.toString() 去解析這個字符串所表明的對象(int).

1.Variables(變量)

簡單的說變量以"$" 開後,後面跟一個VTL指示符( Identifier).一個合法的VTL指示符是以字母開頭,後面能夠是如下任意字符:

alphabetic (a .. z, A .. Z)

numeric (0 .. 9)

hyphen ("-")

underscore ("_")

如下是正確的VTL變量名:

$foo

$mudSlinger

$mud-slinger

$mud_slinger

$mudSlinger1

當VTL中的一個變量如 $foo, 這個變量能夠在模板中提取它本身的值經過set 指示符,或者從java代碼中.好比,若是需java中的變量foo的值爲bar,給模板中全部輸出$foo聲明的值都成爲bar.固然,在模板中使用以下VTL也能夠達到這個目地。

#set( $foo = "bar" )

2.Properties(屬性)

VTL的第二種引用,屬性引用,注意」屬性」具備相對固定的格式. 它也是以$開頭的合法VTL指示符,隨後是」變量名字.變量屬性」. 以下例:

$customer.Address

$purchase.Total

第一個例子, $customer.Address.咱們設想可能在兩種意思.首先它可能在查找customer引用的一個hashtable中的以「Address」爲key關聯的一個數據對象.另外他可能表示的是java對象customer中的getAddress()這個命令取得的結果(固然也可寫成 $customer.getAddress()). 當客戶請求Web頁面中Velocity將根據具體的customer類型輸出.

3.Methods(命令)

在java 代碼中定義命令是最一般的事, 像執得一組方程式計算成本,讀取一個文件等. 命令引用和其它引用一個也是一個通常的VTL聲明,看以下的例子可能會更快的理解:

$customer.getAddress()

$purchase.getTotal()

$page.setTitle( "My Home Page" )

$person.setAttributes( ["Strange", "Weird", "Excited"] )

前兩個例子 -- $customer.getAddress() and $purchase.getTotal() – 能夠等同與屬性引用狀況: $customer.Address and $purchase.Total. 如你猜對了這點,呵,你還蠻聰明!同時,他們是等同與java對象coustomer的getAddress()命令調用。後面兩個引用呢,也會直接對應java對象的對應命令,不一樣的是傳入了命令參數。

4.屬性引用中的屬性查找規則

前己說起,屬性能夠引用到對象的命令. Velocity會使用合適的策略選擇引用到的命令. 它會根據協定的命令命令格式查找. 不管屬性引用的的名字是否大小寫,Velocity都有固定的查找規則.如在$customer.address引用時,查找順序是:

  1. getaddress()

  2. getAddress()

  3. get("address")

  4. isAddress()

對於VTL中大寫的屬性名Address引用,將是:

  1. getAddress()

  2. getaddress()

  3. get("Address")

  4. isAddress()

8.Formal Reference Notation(正規引用格式注意事項)

以上是簡潔格式引用的介紹,規則的格式像下面,如你看到的變量名須要放到{}中:

${mudSlinger}

${customer.Address}

${purchase.getTotal()}

大多數狀況下,簡潔格式引用足以知足使用,但有些狀況下,必須使用正規格式引用.

假設你構造的一個字符串中要包括有 $vice 變量的值. 你以爲如下兩種寫法會是一樣的結果嗎:

1.Jack is a $vicemaniac.

2.Jack is a ${vice}maniac.

這樣,Velocity就知你要的是 $vice, 而不是 $vicemaniac變量,正規引用格式通常用於在模板中直接調整字符串內容.

9.Quiet Reference Notation(靜態引用輸出)

Velocity遇到一個不能處理的引用時,通常他會直接輸出這個引用$email的寫法,頁面上會看到的是$email,以下例,咱們能夠在$後面加上一個!號,那麼就會輸出空白:.

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

 

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

正式的寫法是:.

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

10.Getting literal( 語義問題)

通常狀況下,velocity使用$,#字符來標誌它的聲明,但有時,HTML中由於某種其它意圖,也會寫出這樣的字符,咱們討論如何消除這種語義歧義問題.

1.Currency(貨幣標誌)

如美圓 $2.50!這樣的寫法出現到模板中, VTL處理時是不會出錯,會正確的輸出$2.50!這個你想要的結果。爲何呢?一個合法的VTL標示符是以一個字母開頭的,咱們前面己說過.

2.Escaping Valid VTL References(封裝有效的引用)

以下示,若是沒有#set( $email = "foo" )這一行且java代碼中Context對象中沒有放放email對象,將直接輸出$email.

#set( $email = "foo" )

$email

若是email己定義了 (好比它的值是 foo),而這裏你卻想輸出 $email. 這樣一個字符串,就須要使用轉義字符」\」.

## The following line defines $email in this template:

#set( $email = "foo" )

$email

\$email

\\$email

\\\$email

上面的模板在web頁面上的輸出將是:

foo

$email

\foo

\$email

但若是email並無定義,咱們這樣寫:.

$email

\$email

\\$email

\\\$email

輸出就原封不動了:

$email

\$email

\\$email

\\\$email

注意:當己定義變量和未定義變量一塊兒輸出時,會輸出字面意思,以下便,$moon是未定義的:

#set( $foo = "gibbous" )

$moon = $foo

輸出到web頁面中將是

 $moon = gibbou

11.Case Substitution(可選的格式)

至此,你對velocity的refenerce己比較熟悉了, 你能夠在你的模板中開始應用這些功能. 但你還能夠知道的是Velocity references從java語法中汲取了一些優勢以便模板設計者更容易使用VTL.好比:

$foo

 

$foo.getBar()

## 等同於

$foo.Bar

 

$data.setUser("jon")

##等同於

#set( $data.User = "jon" )

 

$data.getRequest().getServerName()

##等同於

$data.Request.ServerName

## is the same as

${data.Request.ServerName}

這裏示例了你可選的一些引用方式. VTL汲取了java語法和java bean的一些簡潔語法以解析java代碼中Context中的對象和這些對象的命令及屬性---這樣,一個java對象的全部功能均可以展現到視圖中了.

Velocity也借見了java Bean的規範(Bean specifications defined by Sun Microsystems), 是大小寫敏感的; 但Velocity會盡量的幫你修正錯誤. 當命令 getFoo() 經過指令 $bar.foo在模板中引用時,Velocity的搜索規則咱們在前面己講了,你還記得是什麼嗎?.

注意:模板中引用的必須是經過java Bean中的getter/setter 實現的,而直接的java對象的數據域是不能直接引用的,如$foo.Name 會解析到 class Foo's getName() 的實例方法,但不會解析到Foos類的 public Name 這個實例變量.

12.Directives(指令符號)

模板設計者使用「引用「生成動態內容, 指令(directives) – 簡單的說就是設計者在模板中操做java對象—讓視圖設計者全面控制輸出內容的格式.

指令老是以 #開頭後面緊跟具體的指令符. 就像引用同樣(指令的一種),能夠將指令理解爲」表示這裏是一個什麼東東).以下例生成一個出錯提示:

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

這個例子中應使用括號將else分開.

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

1.#set指令

#set 用來給一個引用賦值.值能夠被賦給變量引用或屬性引用, 但要將它們放入括號中,以下示:

#set( $primate = "monkey" )

#set( $customer.Behavior = $primate )

「左操做數被賦值「是引用操做的一個規則.=號右側多是如下類型之一:

  • 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類型引用的例子中,其原素定義在數組 [..]中, 所以,你可使表 $monkey.Say.get(0)訪問第一個元素.

相似的,引用Map 的例子中, 原素定義在 { } 中,其鍵和值間以:隔成一對,使用 $monkey.Map.get("bannana") 在上例中將返回 'good', ( $monkey.Map.banana也會有一樣效果).

下面是通常的計算表達式:

#set( $value = $foo + 1 )

#set( $value = $bar - 1 )

#set( $value = $foo * $bar )

#set( $value = $foo / $bar )

但注意:若是右邊的操做數是一個屬性或命令的引用而返回null,那麼賦值將不會成功,且在隨後的VTL中也不能再取出使用. 以下例:

#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, 上面的TVL輸出結果將是:

The result of the first query is bill

 

The result of the second query is bill

這對與初學者的理解有些麻煩,好比在 #foreach loops中, 你使用 #set 給一個屬性或命令賦值時,以下例示:

 

#set( $criteria = ["name", "address"] )

 

#foreach( $criterion in $criteria )

 

    #set( $result = $query.criteria($criterion) )

 

    #if( $result )

        Query was successful

    #end

 

#end

在上例中,就不能依賴if( $result )來決定查詢是否成功. $result 一但被 #set 爲null (context會一樣), 它將不能被賦 其它值 (不能從 context中取出).

一個解決辦法是,每次都將$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

注意: #set 不須要使用 #end 來聲明結尾.

2.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 such that stringliterals.interpolate=false.

另外, 指令 #literal 元素能夠用來輸出字面意思,以下示.

#literal()

#foreach ($woogie in $boogie)

 nothing will happen to $woogie

#end

#end

會輸出::

#foreach ($woogie in $boogie)

 nothing will happen to $woogie

#end

3.Conditionals(條件判斷)

1.If / ElseIf / Else

#if 指令用來根據條件在頁面中輸出內容, 以下簡單的例子:

#if( $foo )

   <strong>Velocity!</strong>

#end

根據變量 $foo計算後是否爲true決定輸出, 這會有兩種狀況: (i) $foo 的是值是一個boolean (true/false)型並有一個true value, 或 (ii) 它是一個非null值. 要記者,Velocity context 中只能包含Objects, 所以當咱們講 'boolean'時, 它就是一個Boolean (the class).

#if#end 的內容是否會輸出,由$foo是否爲true決定. 這裏,若是 $foo is true, 輸出將是: "Velocity!". 若是$foo 爲null或false,將不會有任何輸出.

#elseif#else 能夠 #if 和組合使用. 若是第一個表達式爲true,將會不計算之後的流程,以下例假設t $foo 是15 and $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

輸出將會是

Go South.

2.Relational and Logical Operators(關係和邏輯運算)

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中的 == 計算有些不一樣:不能用來測試對象是否相等(指向同一塊內存). Velocity中是否相等僅直接的用來比較numbers, strings的值, or objects的toString()結果是否相等. 若是是不一樣的對象,會調用它們的toString()命令結果來比較.

Velocity也使用AND, OR and NOT 執行邏輯運算.詳細說明請參看《VTL參考中文版》,以下是一些簡單示例:

## logical AND

 

#if( $foo && $bar )

   <strong> This AND that</strong>

#end

 

僅當 $foo $bar 和都爲true時,#if()纔會輸出中間內容.

OR 運算例子

## logical OR

 

#if( $foo || $bar )

    <strong>This OR That</strong>

#end

$foo或$bar只要有一個爲true就能夠輸出。

NOT運算則只有一個操做參數或表達式 :

 

##logical NOT

 

#if( !$foo )

 <strong>NOT that</strong>

#end

 

考慮下,下面的例子有幾種輸出結果?.

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

4.Loops(循環)

Foreach Loop

#foreach 用來建立循環. For example:

<ul>

#foreach( $product in $allProducts )

    <li>$product</li>

#end

</ul>

#foreach 會生成包含$products中對象的一個列表. 每一次循環都會將列表中的一個對象賦與變量$product .

 $allProducts 或以是一個Vector, a Hashtable or an Array類型的容器. 指定給變量 $product 是一個引用到其中一個java對象的引用. For example, if $product 確實是一個java代碼中的Product class i,它能夠這樣的方法訪問$product.Name method (ie: $Product.getName()).

咱們假設 $allProducts 是一個Hashtable.看看取出其中的東東多麼簡單:

<ul>

#foreach( $key in $allProducts.keySet() )

    <li>Key: $key -> Value: $allProducts.get($key)</li>

#end

</ul>

經過引用變量$velocityCount能夠訪問到Velocity提供的計數器:

<table>

#foreach( $customer in $customerList )

    <tr><td>$velocityCount</td><td>$customer.Name</td></tr>

#end

</table>

$velocityCount默認的計數器引用,你能夠在配置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

固然,你還能夠設置其它參數,具體見《Velocity Java開發指南中文版》中講解.

# The maximum allowed number of loops.

directive.foreach.maxloops = -1

3.Include(引入)

#include 腳本元素讓模板設計者能夠在模板中引入一個本地文件, 這個被引入的文件將不會通過Velocity的解析. 安全起見,能夠引放的文件只是是配置參數TEMPLATE_ROOT所定義目錄下的,默認爲當前目錄下.

#include( "one.txt" )

若是須要引入多個文件,能夠像下面這樣.

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

固然,還可用一個變量名來代替文件名引入.

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

6.Parse(解析模板)

#parse 元素指示能夠引入一個包含TVL的本地文件,這個文件將被Veloict engine解析輸出。.

#parse( "me.vm" )

#include 指令不一樣, #parse 能夠從引入的模板中獲得變量引用.但#parse指令只能接受一個參數.

VTL templates 被#parse 的模板中還能夠再包含#parse聲明,默認的深度爲10,這是由配置參數directive.parse.max.depth在文件velocity.properties中決定的,你能夠修改它以適合項目要求

7.Stop

#stop 指令用來指示在模板的某處,engine中止解析,這通常用來調用。用法很簡單.

#stop

8.Velocimacros(宏調用)

#macro 指令讓模板設計者能夠將些重複、相關的的腳本版判定義爲一個功能塊.不管在什麼狀況下. 出於單一意圖設計的 Velocimacro都會最大程序的減小模板編寫中能夠的出錯,仍是看個例子來理解一下Velocimacros的概念.

#macro( d )

<tr><td></td></tr>

#end

這樣就定義了一個名爲d的宏,它能夠在其它的模板中像下面那樣直接引用:

#d()

Velocimacro能夠接收0到任意多的傳入參數.如上個例是0個參數,但當它被調用時,也必須傳入一樣多的參數. 這裏定義了一個有兩個參數的宏.

#macro( tablerows $color $somelist )

#foreach( $something in $somelist )

    <tr><td bgcolor=$color>$something</td></tr>

#end

#end

而後,咱們在頁面中來使用:

#set( $greatlakes = ["Superior","Michigan","Huron","Erie","Ontario"] )

#set( $color = "blue" )

<table>

    #tablerows( $color $greatlakes )

</table>

注意變量 $greatlakes 取代了宏中變量 $somelist的輸出,最終的輸出以下:

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

宏通常被定義在模板中,那麼站點上的其它模板中又如何調用呢?如能定義一個能夠更大範圍內共想的宏就太好了

若是將宏#tablerows($color $list) 定義到一個模板庫中(Velocimacros template library), 其它模板就均可以訪問它了.

Velocimacro Arguments(宏的參數)

Velocimacros能夠從TVL中接受如下參數 :

  • 引用類型 : 全部以'$'開頭的

  • 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

當傳一個引用參數給宏時, 引用是經過名字傳入的('pass by name').

     #macro( callme $a )

         $a $a $a

     #end

 

     #callme( $foo.bar() )

  

上例中命令 bar() 被調用了3 times.

最後要說的是,這個特性有些難以學習,但當你精心組織規劃你的宏庫時, 消除在VTL中重複功能的腳本時 –你能夠像使用一個對象或組件同樣使用宏, 好比一個宏對象生成多個表格的重複色彩.

若是你想利用這個特性,你只須要像下面那樣簡單的編碼傳一個值給它來調用 :

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

     #callme( $myval )

  

Velocimacro Properties(宏的屬性)

配置文件 velocity.properties 中有多行相關配置,具體請見《Velocity Java開發指南中文版》.

velocimacro.library –用來指定全局的宏庫,多個能夠,號分開.

velocimacro.permissions.allow.inline – 默認爲true,可讓宏定義在一個正規的模板文件中.

velocimacro.permissions.allow.inline.to.replace.global – 用來指定模板內定義的宏的功能是否要以替換全局庫,默認爲false.

velocimacro.permissions.allow.inline.local.scope –模板中定義的宏的使用範圍是否只是本模板可用.

velocimacro.context.localscope –若是爲true,宏經過#set賦值時.宏中將保持一個,且不會因爲context中的數據被修改而變化,一樣,宏中的修改也不會改變context中的。

velocimacro.library.autoreload – 是否自動從新載入,用於調試環境,默認false,如爲true,須要取掉chcheing:. file.resource.loader.cache = false ).

一些細節:

宏必須在模板中使用#macro()指令前定義.

儘可能不要直接在模板中使用#parse() 包含 #macro() 指令.由於 #parse() 動做在運行時執行,時會有一個在VM中查找元素的過程.

13.注掉 VTL Directives

嗯,你學下英語吧,一看就懂J

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

Extra care should be taken when escaping VTL directives that contain multiple script elements in a single directive (such as in an if-else-end statements). Here is a typical VTL if-statement:

#if( $jazz )

    Vyacheslav Ganelin

#end

If $jazz is true, the output is

Vyacheslav Ganelin

If $jazz is false, there is no output. Escaping script elements alters the output. Consider the following case:

\#if( $jazz )

    Vyacheslav Ganelin

\#end

Whether $jazz is true or false, the output will be

 #if($ jazz )

     Vyacheslav Ganelin

 #end

 

In fact, because all script elements are escaped, $jazz is never evaluated for its boolean value. Suppose backslashes precede script elements that are legitimately escaped:

\\#if( $jazz )

   Vyacheslav Ganelin

\\#end

In this case, if $jazz is true, the output is

\ Vyacheslav Ganelin

\

To understand this, note that the #if( arg ) when ended by a newline (return) will omit the newline from the output. Therefore, the body of the #if() block follows the first '\', rendered from the '\\' preceding the #if(). The last \ is on a different line than the text because there is a newline after 'Ganelin', so the final \\, preceding the #end is part of the body of the block.

If $jazz is false, the output is

\

Note that things start to break if script elements are not properly escaped.

\\\#if( $jazz )

    Vyacheslave Ganelin

\\#end

Here the #if is escaped, but there is an #end remaining; having too many endings will cause a parsing error.

14.VTL: 通常使用的格式

儘可能是這樣:

#set( $imperial = ["Munetaka","Koreyasu","Hisakira","Morikune"] )

#foreach( $shogun in $imperial )

    $shogun

#end

而不要這樣寫,雖然它能夠運行:

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

In each case the output will be the same.

15.Other Features and Miscellany(其它特性和細節)

1.數學計算

以下是四則運算的例子:

#set( $foo = $bar + 3 )

#set( $foo = $bar - 4 )

#set( $foo = $bar * 6 )

#set( $foo = $bar / 2 )

2.Range Operator

The range operator can be used in conjunction with #set and #foreach statements. Useful for its ability to produce an object array containing integers, the range operator has the following construction:

[n..m]

Both n and m must either be or produce integers. Whether m is greater than or less than n will not matter; in this case the range will simply count down. Examples showing the use of the range operator as provided below:

First example:

#foreach( $foo in [1..5] )

$foo

#end

 

Second example:

#foreach( $bar in [2..-2] )

$bar

#end

 

Third example:

#set( $arr = [0..1] )

#foreach( $i in $arr )

$i

#end

 

Fourth example:

[1..3]

Produces the following output:

First example:

1 2 3 4 5

 

Second example:

2 1 0 -1 -2

 

Third example:

0 1

 

Fourth example:

[1..3]

Note that the range operator only produces the array when used in conjunction with #set and #foreach directives, as demonstrated in the fourth example.

Web page designers concerned with making tables a standard size, but where some will not have enough data to fill the table, will find the range operator particularly useful.

3.Advanced Issues: Escaping and !

When a reference is silenced with the ! character and the ! character preceded by an \ escape character, the reference is handled in a special way. Note the differences between regular escaping, and the special case where \ precedes ! follows it:

#set( $foo = "bar" )

$\!foo

$\!{foo}

$\\!foo

$\\\!foo

This renders as:

$!foo

$!{foo}

$\!foo

$\\!foo

Contrast this with regular escaping, where \ precedes $:

\$foo

\$!foo

\$!{foo}

\\$!{foo}

This renders as:

$foo

$!foo

$!{foo}

\bar

4.Velocimacro Miscellany(關於宏的一些問題)

這是一些簡短的問題總結,也許你先要有這樣一個概念:. 'Velocimacro' 就像一個‘VM’。

能否用一個指示符作爲另一個指示符運算的參數?

如 : #center( #bold("hello") )

No. 指示符不是有效的參數但你能夠這樣實現你想要的:

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

#center( $stuff )

或者:

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

上面這個例子中,參數是在調用的宏中生成的.不是調用者傳入的. 看看下面的例子 :

 

#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()內部的!

能否經過 #parse()來註冊一個宏 ?

宏必須在模板使用前定義好.前面己有一個關於此問題的建議,#parse()是運行時執進的,JVM查找對象的順序不必定會全按咱們預計的執行。

什麼是宏的自動從新裝載?

這是由配置參數決定的, 爲方例開發者,在生產環境中則不須要 :

velocimacro.library.autoreload

默認的是false.當設爲true中,須要設定chcheing參數;

<type>.resource.loader.cache = false

(具體配置請見開發指南,以下是一個配置的例子)

    file.resource.loader.path = templates

    file.resource.loader.cache = false

    velocimacro.library.autoreload = true

   

注意:Don't keep this on in production.

5.String Concatenation(連結字符串)

很簡單,看例子就是 :

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

   

輸出將是

 'The clock is BigTallBen'.

相關文章
相關標籤/搜索