Velocity能爲咱們做什麼?
The Mud Store Example
假設你是一家專門出售Mud的在線商店的頁面設計人員,讓咱們暫且稱它爲「在線MUD商店」。大家的業務很旺,客戶下了各類類型和數量的mud訂單。他們 都是經過輸入用戶名和密碼後才登錄到你的網站,登錄後就容許他們查看訂單併購買更多的mud。如今,一種很是流行的mud正在打折銷售。另外有一些客戶規 律性的購買另一種也在打折可是不是很流行的Bright Red Mud,因爲購買的人並很少因此它被安置在頁面的邊緣。全部用戶的信息都是被跟蹤並存放於數據庫中的,因此某天有一個問題可能會冒出來:爲何不使用 velocity來使用戶更好的瀏覽他們感興趣的商品呢?
Velocity使得web頁面的客戶化工做很是容易。做爲一個web site的設計人員,你但願每一個用戶登錄時都擁有本身的頁面。
你會見了一些公司內的軟件工程師,你發現他們每一個人都贊成客戶應該擁有具備個性化的信息。那讓咱們把軟件工程師應該做的事情發在一邊,看一看你應該做些什 麼吧。
上面的實現結果是在頁面上打印「Hello Velocity World!」
爲了使包含VTL directives的statement更具備可讀性,咱們鼓勵你在新行開始每一個VTL statement,儘管你不是必須這麼做。Set directive將在後面詳細描述。
註釋
單行註釋:
## This is a single line comment.
多行註釋:
#*
Thus begins a multi-line comment. Online visitors won’t
see this text because the Velocity Templating Engine will
ignore it.
*#
文檔格式:
#**
This is a VTL comment block and
may be used to store such information
as the document author and versioning
information:
@version 5
@author
*#
References
在VTL中有三種類型的references:變量(variables)、屬性(properties)、方法(methods)。做爲一個使用VTL 的頁面設計者,你和你的工程師必須就references的名稱達成共識,以便你能夠在你的template中使用它們。
Everything coming to and from a reference被做爲一個String對象處理。若是有一個對象$foo是一個Integer對象,那麼Velocity將調用它的 toString()方法將這個對象轉型爲String類型。
變量
格式要求同java。
屬性
例子:
$customer.Address
$purchase.Total
$customer.Address有兩種含義。它能夠表示:查找hashtable對象customer中以Address爲關鍵字的值;也能夠表示調 用customer對象的getAddress()方法。當你的頁面被請求時,Velocity將肯定以上兩種方式選用那種,而後返回適當的值。
方法
一個方法就是被定義在java中的一段代碼,而且它有完成某些有用工做的能力,例如一個執行計算和判斷條件是否成立、知足等。方法是一個由$開始並跟隨 VTL標識符組成的References,通常還包括一個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()方法具備相同的效果。 若是可能的話使用屬性的方式是比較合理的。屬性和方法的不一樣點在於你可以給一個方法指定一個參數列表。
正式reference標記
reference的正是格式以下:
${mudSlinger} 變量
${customer.Address} 屬性
${purchase.getTotal()} 方法
非正是格式更見經常使用,可是有時仍是使用正是格式比較適合。例如:你但願經過一個變量$vice來動態的組織一個字符串。
Jack is a $vicemaniac.
原本變量是$vice如今卻變成了$vicemaniac,這樣Veloctiy就不知道您到底要什麼了。因此,應該使用正是格式書寫
Jack is a ${vice}maniac
如今Velocity知道變量是$vice而不是$vicemaniac。
Quiet reference notation
例如:
$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}
可是,注意VTL中不會將reference解釋爲對象的實例變量。例如:$foo.Name將被解釋爲Foo對象的getName()方法,而不是 Foo對象的Name實例變量。
Directives
Reference容許設計者使用動態的內容,而directive使得你能夠應用java代碼來控制你的顯示邏輯,從而達到你所指望的顯示效果。
#set
#set directive被用於設置一個reference的值。例如:
#set ( $primate = 「monkey」 )
#set ( $customer.Behavior = $primate )
賦值左側的(LHS)必須是一個變量或者屬性reference。右側(RHS)能夠是如下類型中一種:
l 變量reference
l String literal
l 屬性reference
l 方法reference
l number literal
l ArrayList
下面是應用各類類型的RHS的例子:
#set ( $monkey = $bill ) ##變量reference
#set ( $monkey.Friend = 「monica」 ) ##String literal
#set ( $monkey.Blame = $whitehouse.Leak )##屬性reference
#set ( $monkey.Plan = $spindoctor.weave($web) )##方法reference
#set ( $monkey.Number = 123 )##Number literal
#set ( $monkey.Say = [「Not」, $my, 「fault」] )##ArrayList
注意:最後一個例子的取值方法爲:$monkey.Say.get(0)
RHS也能夠是一個簡單的算術表達式:
#set ( $value = $foo + 1 )
#set ( $value = $bar -1 )
#set ( $value = $foo * $bar )
#set ( $value = $foo / $bar )
若是你的RHS是一個null,VTL的處理將比較特殊:它將指向一個已經存在的reference,這對初學者來說多是比較費解的。例如:
#set ( $resut = $query.criteria(「name」) )
The result of the first query is $result
#set ( $resut = $query.criteria(「address」) )
The result of the second query is $result
若是$query.criteria(「name」)返回一個「bill」,而$query.criteria(「address」)返回的是null, 則顯示的結果以下:
The result of the first query is bill
The result of the first query is bill
看看下面的例子:
#set( $criteria = ["name", "address"] )
#foreach( $criterion in $criteria )
#set( $result = $query.criteria($criterion) )
#if( $result )
Query was successful
#end
#end
在上面的例子中,程序將不能智能的根據$result的值決定查詢是否成功。在$result被#set後(added to the context),它不能被設置回null(removed from the context)。打印的結果將顯示兩次查詢結果都成功了,可是實際上有一個查詢是失敗的。
爲了解決以上問題咱們能夠經過預先定義的方式:
#set( $criteria = [「name」, 「address」] )
#foreach( $criterion in $criteria )
#set( $result = false )
#set( $result = $query.criteria( $criterion ) )
#if( $result )
Query was successful
#end
#end
String Literals
當你使用#set directive,String literal封閉在一對雙引號內。
#set ( $directoryRoot = 「www」 )
#set ( $templateName = 「index.vm」 )
#set ( $template = 「$directoryRoot/$tempateName」 )
$template
上面這段代碼的輸出結果爲:www/index.vm
可是,當string literal被封裝在單引號內時,它將不被解析:
#set ( $foo = 「bar」 )
$foo
#set ( $blargh = ‘$foo’ )
結果:
bar
$foo
上面這個特性能夠經過修改velocity.properties文件的stringliterals.interpolate = false的值來改變上面的特性是否有效。
條件語句
if/elseif/else
當一個web頁面被生成時使用Velocity的#if directrive,若是條件成立的話能夠在頁面內嵌入文字。例如:
#if ( $foo )
Velocity! #end
上例中的條件語句將在如下兩種條件下成立:
l $foo是一個boolean型的變量,且它的值爲true
l $foo變量的值不爲null
這裏須要注意一點:Velocity context僅僅可以包含對象,因此當咱們說「boolean」時實際上表明的時一個Boolean對象。即使某個方法返回的是一個boolean 值,Velocity也會利用內省機制將它轉換爲一個Boolean的相同值。
若是條件成立,那麼#if和#end之間的內容將被顯示。
#elseif和#else元素能夠同#if一同使用。例如:
#if( $foo < 10 )
Go North #elseif( $foo == 10 )
Go East #elseif( $foo == 6 )
Go South #else
Go West #end
注意這裏的Velocity的數字是做爲Integer來比較的――其餘類型的對象將使得條件爲false,可是與java不一樣它使用「==」來比較兩個 值,並且velocity要求等號兩邊的值類型相同。
關係、邏輯運算符
Velocity中使用等號操做符判斷兩個變量的關係。例如:
#set ( $foo = 「deoxyribonucleic acid」 )
#set ( $bar = 「ribonucleic acid」 )
#if ( $foo == $foo )
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邏輯運算符。下面是一些例子:
## logical AND
#if( $foo && $bar )
This AND that #end
## logical OR
#if ( $foo || $bar )
This OR That #end
##logical NOT
#if ( !$foo )
NOT that #end
循環
Foreach循環
例子:
Velocimacro arguments
Velocimacro可使用如下任何元素做爲參數:
l Reference:任何以$開頭的reference
l String literal:
l Number literal:
l IntegerRange:[1….3]或者[$foo….$bar]
l 對象數組:[「a」,」b」,」c」]
l boolean值:true、false
當將一個reference做爲參數傳遞給Velocimacro時,請注意reference做爲參數時是以名字的形式傳遞的。這就意味着參數的值在每 次Velocimacro內執行時纔會被產生。這個特性使得你能夠將一個方法調用做爲參數傳遞給Velocimacro,而每次Velocimacro執 行時都是經過這個方法調用產生不一樣的值來執行的。例如:
#macro ( callme $a )
$a $a $a
#end
#callme( $foo.bar() )
執行的結果是:reference $foo的bar()方法被執行了三次。
若是你不須要這樣的特性能夠經過如下方法:
#set ( $myval = $foo.bar() )
#callme ( $myval )
Velocimacro properties
Velocity.properties文件中的某幾行可以使Velocimacros的實現更加靈活。注意更多的內容能夠看Developer Guide。
Velocity.properties文件中的velocimacro.libraary:一個以逗號分隔的模板庫列表。默認狀況下,velocity 查找惟一的一個庫:VM_global_library.vm。你能夠經過配置這個屬性來指定本身的模板庫。
Velocity.properties文件中的velocimacro.permissions.allow.inline屬性:有兩個可選的值 true或者false,經過它能夠肯定Velocimacros是否能夠被定義在regular template內。默認值是ture――容許設計者在他們本身的模板中定義Velocimacros。
Velocity.properties文件中的
velocimacro.permissions.allow.inline.replace.global屬性有兩個可選值true和false,這個 屬性容許使用者肯定inline的Velocimacro定義是否能夠替代全局Velocimacro定義(好比在 velocimacro.library屬性中指定的文件內定義的Velocimacro)。默認狀況下,此值爲false。這樣就阻止本地 Velocimacro定義覆蓋全局定義。
Velocity.properties文件中的
velocimacro.permissions.allow.inline.local.scale屬性也是有true和false兩個可選值,默認是 false。它的做用是用於肯定你inline定義的Velocimacros是否僅僅在被定義的template內可見。換句話說,若是這個屬性設置爲 true,一個inline定義的Velocimacros只能在定義它的template內使用。你可使用此設置實現一個奇妙的VM敲門:a template can define a private implementation of the second VM that will be called by the first VM when invoked by that template. All other templates are unaffected。
Velocity.properties文件中的velocimacro.context.localscope屬性有true和false兩個可選值, 默認值爲false。當設置爲true時,任何在Velocimacro內經過#set()對context的修改被認爲是針對此velocimacro 的本地設置,而不會永久的影響內容。
Velocity.properties文件中的velocimacro.library.autoreload屬性控制Velocimacro庫的自動 加載。默認是false。當設置爲ture時,對於一個Velocimacro的調用將自動檢查原始庫是否發生了變化,若是變化將從新加載它。這個屬性使 得你能夠不用從新啓動servlet容器而達到從新加載的效果,就像你使用regular模板同樣。這個屬性可使用的前提就是resource loader緩存是off狀態(file.resource.loader.cache = false)。注意這個屬性其實是針對開發而非產品的。
Velocimacro Trivia
Velocimacro必須被定義在他們被使用以前。也就是說,你的#macro()聲明應該出如今使用Velocimacros以前。
特別要注意的是,若是你試圖#parse()一個包含#macro()的模板。由於#parse()發生在運行期,可是解析器在parsetiem決定一 個看似VM元素的元素是不是一個VM元素,這樣#parse()-ing一組VM聲明將不按照預期的樣子工做。爲了獲得預期的結果,只須要你簡單的使用 velocimacro.library使得Velocity在啓動時加載你的VMs。
Escaping VTL directives
VTL directives can be escaped with 「\」號,使用方式跟VTL的reference使用逃逸符的格式差很少。
## #include( 「a.txt」 ) renders as
(註釋行)
#include( 「a.txt」 )