Tiny模板语言(VelocityPlus)初步入门
2019獨角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
1 關(guān)于用戶手冊
本文主要介紹如何在模板中使用Tiny模板語言,通過查閱本手冊,可以對Tiny模板語言 TTL(Tiny Template Language)的用法有一個較全面的認(rèn)識,并學(xué)會如何有效地使用Tiny模板語言。同時,本文提供了較多的例子幫您來學(xué)習(xí)并掌握它。
2 Tiny模板語言概述
Tiny 模板語言是一個參考Velocity語法的模板語言,它對Velocity模板語言中一些功能不太完全及使用過程中比較不方便的地方進行全面的擴展和升級,同時為了更好的適應(yīng)Web界面層的開發(fā),還提供了強大的布局功能。本文中的例子都使用Tiny 模板語言來開發(fā)。
| <HTML> <BODY> Hello ${customer.Name}! <table> #for( mud : mudsOnSpecial )#if ( customer.hasPurchased(mud) )<tr><td>${flogger.getPromo( mud )}</td></tr>#end #end </table> </BODY> </HTML> |
感謝您選擇Tiny模板引擎!
3 Tiny模板語言能為您做什么?
假設(shè)您是一家專門出售Mud的在線商店的頁面設(shè)計人員,讓我們暫且稱它為“在線MUD商店”。您的業(yè)務(wù)非常繁忙,客戶下了各種類型和數(shù)量的Mud訂單。他們都是通過用戶名和密碼登陸到您的網(wǎng)站,登陸后就允許他們查看訂單并購買更多的Mud。現(xiàn)在,一種非常流行的Mud正在打折銷售。另外有一些客戶規(guī)律性地購買另外一種也在打折但不是很流行的Bright Red Mud,由于購買的人并不多,所以它被安置在頁面的邊緣。另外所有用戶的操作信息都是被跟蹤并存放于數(shù)據(jù)庫中的,所以某天有一個問題可能會冒出來:如何給每個用戶定制一個自己的頁面,讓他們?yōu)g覽自己的感興趣的物品。為什么不使用模板語言來使用戶更好的瀏覽他們感興趣的商品呢?而Tiny模板語言就是一個非常不錯的選擇。
Tiny Template使得定制化Web頁面非常容易。作為一個Web Site的設(shè)計人員,您希望每個用戶登陸時都擁有自己的頁面。
您咨詢了一些公司內(nèi)的軟件工程師,您發(fā)現(xiàn)他們每個人都同意客戶應(yīng)該擁有具有個性化的信息。那讓我們把軟件工程師應(yīng)該作的事情放在一邊,看一看您應(yīng)該作些什么吧。
您可以在頁面內(nèi)嵌套如下的TTL聲明:
| <HTML> <BODY> Hello ${customer.Name}! <table> #foreach( mud : mudsOnSpecial )#if ( customer.hasPurchased(mud) )<tr><td>${flogger.getPromo( mud )}</td></tr>#end #end </table> </BODY> </HTML> |
使用Tiny模板引擎實現(xiàn)WEB界面就是這么簡單!本文后續(xù)會有更全面的TTL語法介紹,掌握這些,您將會全面體會到Tiny模板引擎的威力。
4 Tiny模板語言簡介
Tiny模板語言的目標(biāo)是提供一個簡潔、易學(xué)的方法將動態(tài)內(nèi)容展現(xiàn)到Web頁面上,使得Web頁面設(shè)計者可以在沒有任何編程語言經(jīng)驗就可以在非常短的時間內(nèi)(一天?)學(xué)會使用它,增強您的網(wǎng)站展現(xiàn)力。
TTL使用引用這種方式將動態(tài)內(nèi)容(一般指Java代碼中生成的數(shù)據(jù)對象)顯示到您的Web Site上。Tiny模板語言的變量只是引用中的一種,變量是用來描述要展現(xiàn)到視圖模板中的Java數(shù)據(jù)對象。當(dāng)然,Java代碼也可以從模板TTL中獲取數(shù)據(jù),以下是一個寫在HTML中的TTL變量:
| #set( a = "Tiny" ) |
TTL語句:所有的TTL 語句都是以#開頭,且包含一個指令(這里是set),當(dāng)用戶訪問您的頁面時, Tiny模板引擎將搜索頁面中的所有“#”符號,如果確定這是一個TTL語句時就按規(guī)則處理動態(tài)內(nèi)容, 符號“#”僅僅只是表明這可能是一個TTL聲明。
符號“#”所跟的set我們用“指令”這一名詞來稱呼它(隨后介紹更多的指令),set指令使用一個表達(dá)式(expression) (包含在一對括號里)將一個值value(這里是字符串“Tiny”)賦給變量a,(變量名在左邊,值在右邊,用“=”組合起來)。
在以上的例子中,變量是a,無需額外特殊符號標(biāo)記變量,所賦值的字符串要用引號括起。而字符串的拼接可以使用運算符“+”操作,或者系統(tǒng)函數(shù)format進行格式化拼裝。
請理解Tiny模板語言基本規(guī)則:
${expression}輸出表達(dá)式的計算結(jié)果,而expression(表達(dá)式)中變量無需額外符號標(biāo)記變量。而指令則以#開頭來表示,有點“做些什么動作”的意思。
在上面的例子中,#set用來指定值給一個變量名a, 而變量名a的值就是"Tiny"。
5 Hello Tiny!
在您的HTML文檔的任何地方,都可以引用一個變量名來輸出值, 如下例,先給變量foo 賦值為Tiny,然后將它輸出到頁面中。
| <html> <body> #set( foo = "Tiny" ) Hello ${foo}! </body> <html> |
在這個頁面上,您看到的將是 "Hello?Tiny!"。
為了讓編輯器中的TTL指令更易讀,我們強烈建議您每行只有一條TTL指令,當(dāng)然這不是必須的。 關(guān)于set 指令的更多功能我們隨后再討論。
6 注釋
注釋可以讓您在模板中包含對TTL或其它問題的說明描述以便與閱讀和理解。但它并不會在最終輸出的WEB頁面中看到。如下示例是TTL中的一行注釋。
| ## This is a single line comment. ## 這里是行注釋內(nèi)容 |
單行注釋是以“##”開頭的一行文字。如要寫下多行注釋,就要像下面那樣,將它們放入“#*”和“*#”間或“#--”和“--#”間:
| #*Thus begins a multi-line comment. Online visitors won'tsee this text because the Tiny Templating Engine willignore it. *# #--這里是塊注釋內(nèi)容 --# #* 這里是塊注釋內(nèi)容 *# |
雖然引擎只是提供了兩種簡單的注釋方式,但卻能滿足您在頁面上添加必要的說明文字。
之所以支持兩種塊注釋方式,是為了在兼容性及方便性方面提供更大的便捷。#* *#方式是為了與Velocity兼容,這樣熟悉Velocity的人員更容易上手。#-- --#是為了便于把Html中的注釋改成Tiny模板注釋。
7 引用(References)
TTL中有三種引用references:變量引用(variables),屬性引用(properties)和方法引用(methods)。作為使用TTL的頁面開發(fā)者, 您必須和您的Java工程師在特定的引用名稱上達(dá)成一致,這樣模板和Java代碼才可按照你們的預(yù)期去結(jié)合以輸出正確的內(nèi)容。
所有的引用在模板中的輸出都表現(xiàn)為一個字符串。假設(shè)一個引用變量 foo ,它是一個int型變量, Tiny模板引擎在處理時將調(diào)用它的.toString()去解析這個對象(int),從而獲得代表它的字符串。
7.1 變量(variables)
| [_a-zA-Z][_a-zA-Z$0-9]* |
上面的正則表達(dá)式表示,在Tiny框架引擎中,變量必須是以下劃線或大小寫字母開頭的,后續(xù)可以跟下劃線或大小寫字母和數(shù)字的字符串,才可以作為變量名。實際上宏的名字,也是遵守同樣的規(guī)則。
簡單地說,變量不需要任何額外的符號開頭,一個合法的TTL變量名是以字母開頭,后面可以是以下任意字符:
- 字母(a .. z, A .. Z)
- 數(shù)字(0 .. 9)
- 下劃線 ("_")
以下是正確的TTL變量名:
| foo mudSlinger mud_slinger |
如果想在TTL中引用一個變量如 foo,可以通過set命令設(shè)置自己的值,也可以從Java代碼中獲取。例如, Java變量foo的值為”bar”, 如果想在模板中輸出這個值,那么模板中引用${foo}就可以在Web頁面中輸出所需值。另一種方式是在模板中使用如下TTL也可以達(dá)到這個目地。
| #set(foo = "bar" ) ${foo} |
只要符合上面的規(guī)范的字符串都可以作為Tiny框架引擎中的變量,即使是Java的關(guān)鍵字也可以。
| 需要注意的是,由于在進行循環(huán)時,Tiny模板引擎會在循環(huán)變量名后附加“For”作為狀態(tài)變量,因此,需要注意避免沖突,以影響使用。 |
7.2 屬性(properties)
TTL的第二種引用是屬性引用,屬性引用不需要任何額外特殊符號開頭,只需簡單地按照“變量名字.變量屬性”的形式即可。如下例:
| customer.address purchase.total |
“customer.address”我們設(shè)想可能在兩種意思。首先它可能查找一個類型為Map的customer的引用,并以“address”為key的一個數(shù)據(jù)對象。另外它可能表示的是Java對象customer中的getAddress()這個方法的返回值(當(dāng)然也可寫成 customer.getAddress())。當(dāng)用戶請求Web頁面,Tiny模板引擎將根據(jù)具體的customer類型進行處理。如果想在頁面直接輸出這個屬性,那么應(yīng)該加一個取值符號${},例如${customer.address}。
| 注意:在Tiny語言模板使用屬性的引用時,引擎首先會通過Java Bean中的getter/setter實現(xiàn)的,如果沒有找到相應(yīng)的方法,引擎才會再去尋找該對象的屬性字段,并且這個屬性訪問權(quán)限只有為public時才能解析引用。而Java對象的其他受保護的數(shù)據(jù)域是不能直接引用的,Tiny模板引擎遵守Java數(shù)據(jù)安全規(guī)則。 |
如${foo.name}會解析到 對象foo的 getName()的實例方法或public name這個實例變量,但不會解析到Foos類的 private name這個實例變量。
7.3 方法(methods)
在Java 代碼中定義方法是最平常的事。方法引用和其它引用一樣也是一個TTL聲明,看如下的例子可能可以更快地理解:
| customer.getAddress() purchase.getTotal() page.setTitle( "My Home Page" ) person.setAttributes(["Strange", "Weird", "Excited"]) |
上述兩個例子中customer.getAddress()和purchase.getTotal()可以等同與屬性引用情況: customer.address和 purchase.total。如果您已經(jīng)領(lǐng)悟到了這點,您的確是很聰明的!后面兩個引用也會直接對應(yīng)Java對象的對應(yīng)方法,不同的是傳入了參數(shù)。
8 表達(dá)式(Expression)
8.1 取值表達(dá)式
上文介紹了變量、屬性和方法調(diào)用等引用的定義。那么要將這些引用的結(jié)果輸出打印都需要經(jīng)過取值表達(dá)式。在Tiny引擎模板中取值表達(dá)式分為有兩種:
(1)${expression}:輸出表達(dá)式的計算結(jié)果
(2)$!{expression}:輸出表達(dá)式的計算結(jié)果,并轉(zhuǎn)義其中的 HTML 標(biāo)簽。
其中expression必須是一個合法的Tiny Template表達(dá)式,如果您繼續(xù)閱讀本文后續(xù)的介紹將會了解表達(dá)式規(guī)范。Tiny模板引擎取值表達(dá)式{}不可以省略,${expression}和$expression不是等價的。如果表達(dá)式執(zhí)行結(jié)果為null或void,則不會輸出任何內(nèi)容。注意:取值表達(dá)式作為指令的參數(shù)時,不可以采用${expression}形式需要去掉{},同時在字符串參數(shù)中,也不支持${expression}。也許您現(xiàn)在還不能理解這點,不過繼續(xù)閱讀下文您會慢慢領(lǐng)悟的。
8.2 Map常量
| {expression:expression,...} |
在模板中為了數(shù)據(jù)存儲、傳遞的方便,Tiny模板語言提供了Map常量的表達(dá)方式。Map常量經(jīng)常直接作為指令或自定義宏的參數(shù),下面的例子希望能幫助您快速理解如何定義Map常量。
| {} ##表示空Map {"aa":"aaValue","bb":"bbValue"}##純字符串Map {"aa":1,"bb":"bbValue"} ##數(shù)字及字符串混合Map |
上面的例子是告訴您如何定義Map常量,事實上,在模板中定一個Map變量也類似上面的形式,只不過您還需要使用#set指令,并制定一個具體的參數(shù)名。下面的例子希望能幫助您快速理解如何調(diào)用Map常量。
| #set(map={"aa":1,"key":"bbValue"}) ${map.key} ${map["key"]} ${map.get("key")} |
| {aa:1}和{"aa":1}的含義是不同的,這一點必須要注意。 {aa:1}表示key值是aa變量的值,${"aa":1}表示key值是"aa"的字符串。 因此,如果寫為{aa:1}的形式時,如果沒有aa變量存在,則會報空指針錯誤。 |
| 如果不能確認(rèn),前面的變量是否為空,可以加一個安全調(diào)用方式: ${map?.key} ${map?.get("key")} |
8.3 數(shù)組常量
| [expression,...] |
在模板中定義數(shù)組常量也十分簡單,看了下面的例子相信您一定可以掌握。
| [] ##表示空數(shù)組 [1..5]##等價于[1,2,3,4,5] [5..1]##等價于[5,4,3,2,1] [(1+4)..1]##等價于[5,4,3,2,1] [1,2,3,4,5]##純數(shù)字?jǐn)?shù)組 [1,"aa",2,"cc",3]##數(shù)字及字符串混合數(shù)組 [1,aa,2,"cc",3]##數(shù)字,變量,字符串混合數(shù)組 |
而調(diào)用數(shù)組常量的方式有兩種,一種是直接通過下標(biāo)索引的方式,另一種是調(diào)用get(index)方式。
| ${list[1]} ${list.get(1)} |
| 如果不能確認(rèn),前面的變量是否為空,可以加一個安全調(diào)用方式:${list?.[index]}或${list?.get(1)} |
8.4 其他表達(dá)式
| 類型 | 表達(dá)式 | 說明 |
| 邏輯運算 | ! && || | |
| 自增/自減 | ++ -- | 不論放在變量前面與后面,沒有區(qū)別 |
| 算術(shù)計算 | + - * / % | |
| 空值常量 | null | |
| 移位運算 | >>? >>>? <<? | |
| 比較運算 | == !=? ?> >=? ?<? ?<= | ==的執(zhí)行邏輯請查看13.3 關(guān)系和邏輯運算。 |
| 方法調(diào)用 | functionName([...]) | 調(diào)用框架中的內(nèi)嵌或擴展方法。 |
| 數(shù)組讀取 | array[i] | |
| 數(shù)字常量 | 123 123L 99.99F 99.99d 99.99e99? -99.99E-10d 0xFF00 0xFF00L 0.001 0.001D 1.10D | ?前綴0x不可以寫成0X,后綴lfde可以用相應(yīng)LFDE替換 |
| 成員方法調(diào)用 | object.methodName([...]) | 可以通過框架為某種類型增加新的方法或覆蓋原有方法。 |
| 成員屬性訪問 | object.fieldName | |
| 布爾值常量 | true false | |
| 字符串常量 | "abc\r\n" 'abc\u00A0\r\n' | 不論是單引號框起來的字符串還是雙引號框起來的字符串,都是一樣的,唯一的區(qū)別有,當(dāng)字符串中包含雙引號或單引號的時候可以少用轉(zhuǎn)義符。 |
| 位運算 | ~ ^ & | | |
| 三元表達(dá)式 | exp?a:b exp?:b | a?:b等價于a?a:b,當(dāng)表達(dá)式比較復(fù)雜的時候,這種簡寫形式會比較漂亮,也更容易閱讀 |
Tiny模板引擎對于布爾表達(dá)式進行多種強力支持,不僅僅只有布爾值才可以參與運算,它的運行規(guī)則如下:
- 如果是null,則返回false
- 如果是布爾值,則返回布爾值
- 如果是字符串且為空串“”,則返回false
- 如果是集合,且集合中沒有元素,則返回false
- 如果是數(shù)組,且數(shù)組長度為0,則返回false
- 如果是Iterator類型,則如果沒有后續(xù)元素,則返回false
- 如果是Enumerator類型,則如果沒有后續(xù)元素,則返回false
- 如果是Map類型且其里面沒有KV對,則返回false
- 否則返回true
| 在訪問屬性或成員變量的時候,普通的方式是用“.”運算符,也可以使用"?.”運算符,表示如果前置變量非空,都繼續(xù)執(zhí)行取屬性值或調(diào)用成員函數(shù),避免空指針異常的發(fā)生。 |
| #if(0)zero#end會顯示zero,在Tiny模板語言中,只要有值就會返回true。 |
9 索引表示法
用類似foo[0]的方式可以獲取一個對象的指定索引的值。這種形式類似調(diào)用get(Object)方法,實際上是提供了一種簡略,比如foo.get(0)。因此以下幾種寫法都是調(diào)用get方法:
| 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數(shù)組適用相同的語法,因為Tiny模板引擎將數(shù)組包裝成一個對象,它可以通過get(Integer)獲得指定索引對象的元素。例如:
| foo.bar[1].junk foo.callMethod()[1] foo["apple"][4] |
10 渲染
無論是變量、屬性還是方法等這些引用的最終結(jié)果值的渲染輸出本質(zhì)都會轉(zhuǎn)換成String對象。例如要取值輸出一個Integer對象${foo},那么Tiny 模板引擎就會調(diào)用它的.toString()方法,從而將對象解析轉(zhuǎn)換成一個字符串。
11 與Java無縫對接
至此,您對Tiny模板語言已經(jīng)有了一定程度的了解,相信您已經(jīng)迫不及待的想使用它來開發(fā)應(yīng)用了。但您不要忘記,Tiny模板語言與Java是無縫對接的,Tiny模板引擎設(shè)計者花費了一定的精力做到了與Java很好的兼容,并且從Java語法中也汲取了一些優(yōu)點,使得模板設(shè)計者更容易使用TTL。比如對于變量foo:${foo.getBar()}等同于${foo.bar}。
現(xiàn)在您大概了解到了Tiny模板語言引用的不同方式但得到的是相同的結(jié)果,事實上Tiny模板語言融合了Java和Java Bean的相關(guān)簡潔語法和規(guī)范來解析Java代碼中的對象和這些對象的方法及其屬性,使得Java對象的大部分功能都可以展示到視圖中,同時還有較好的處理性能。
12 模板布局
布局在Tiny模板引擎中是一個非常重要的概念,通過Tiny模板引擎,可以快速進行頁面構(gòu)建與渲染,并且減少程序員工作量。Tiny模板引擎設(shè)計者認(rèn)為越到底層的程序員,所要完成的工作越少。如果您將Tiny模板語言與同類的模板引擎的布局實現(xiàn)相比會發(fā)現(xiàn),Tiny模板引擎中的布局具有一定的強制性,這也同時減少了程序員的開發(fā)工作量,程序員不再需要關(guān)心布局文件的引入,只要放入有布局文件的目錄,就會應(yīng)用布局;您把它拿出來,它也就沒有了。
用于設(shè)置Tiny模板語言的布局的文件稱為布局文件。布局布局文件的方法結(jié)構(gòu)與普通模板文件完全相同,只是它的擴展名與模板文件名不同,它的文件名以“.layout”結(jié)尾,用以區(qū)別。布局文件與模板文件完全相同,只是在布局文件中需要放置一個#pageContent標(biāo)簽,用以標(biāo)示插入點。
為了更好的理解Tiny模板引擎中的布局,直接用示例說明,下面是目錄結(jié)構(gòu):
| template|+- tiny|+- layout|+- div|? +- aa.page|? +- default.layout+- default.layout |
/template/tiny/layout/div目錄中aa.page的內(nèi)容如下:
| Hello,World |
/template/tiny/layout/div目錄中default.layout的內(nèi)容如下:
| <b>#pageContent </b> |
/template/tiny/layout目錄中的default.layout的內(nèi)容如下:
| <div>#pageContent </div> |
下面是執(zhí)行結(jié)果:
| <div><b>Hello,World</b> </div> |
也就是說,雖然aa.page文件里只有Hello,World,但是由于在與它同名路徑中有一個布局文件,因此用布局文件對其進行了渲染,從而變成下面的內(nèi)容:
| <b> Hello,World </b> |
但是引擎發(fā)現(xiàn)它上層目錄中另外還有一個布局文件/template/tiny/layout/default.layout,于是引擎就被渲染出上文看到的最終結(jié)果。
在Tiny模板語言中使用布局十分方便,布局文件不需要在模板文件進行顯式聲明。布局文件的命名規(guī)范為:模板基本文件名+“.”+布局文件擴展名,比如:模板文件名為:aa.page,則模板基本文件名為aa,其布局文件擴展名為layout,這個時候它的布局文件名就是:aa.layout。
Tiny模板引擎中有一個特殊的布局文件名,它就是default+"."+布局文件擴展名,比如:布局文件擴展名為layout,這個時候它的布局文件名就是:default.layout。
為了說明模板布局的進階用法,請看下面的舉例,假如有下面的目錄:
| template|+- tiny|+- layout+- div|? +- aa.page|? +- aa.layout|? +- bb.page|? + default.layout+- default.layout |
/template/tiny/layout/div目錄中aa.page的內(nèi)容如下:
| Hello,World |
/template/tiny/layout/div目錄中bb.page的內(nèi)容如下:
| Hello,悠然 |
/template/tiny/layout/div目錄中default.layout的內(nèi)容如下:
| <b>#pageContent </b> |
/template/tiny/layout/div目錄中aa.layout的內(nèi)容如下:
| <h3>#pageContent </h3> |
/template/tiny/layout目錄中的default.layout的內(nèi)容如下:
| <div>#pageContent </div> |
aa.page執(zhí)行結(jié)果如下:
| <div><h3>Hello,World</h3> </div> |
bb.page執(zhí)行結(jié)果如下:
| <div><b>Hello,悠然</b> </div> |
聰明的您一定明白了,布局文件的渲染過程是這樣的,優(yōu)先渲染與模板文件同名的布局文件,只有不存在與模板文件同名的布局文件的時候,才會渲染default.layout布局文件。詳細(xì)的渲染過程分析如下:
aa.page先去找同級aa.layout,如果找到了,渲染同級aa.layout。再往上一級遞歸渲染到上一級的default.layout。
bb.page先去找同級bb.layout,如果找不到,去找同級default.layout。如果找到,渲染同級default.layout。再往上一級遞歸,渲染到上一級的default.layout。
| Tiny模板引擎的默認(rèn)擴展名為layout、component、page,分別代表而已文件、宏文件、頁面文件。在實際應(yīng)用當(dāng)中,也可以根據(jù)自己的喜好設(shè)置為其它的名字。 |
13 指令集
在模板中您可以使用“引用”生成動態(tài)內(nèi)容,而指令簡單地說就是設(shè)計者在模板中操作Java對象,方便頁面設(shè)計者有效地控制輸出內(nèi)容的格式。
指令總是以#開頭后面緊跟具體的指令符。
13.1 #set指令
| #set(name1=expression,name2=expression,[...])用于向當(dāng)前上下文賦值 #!set(name1=expression,name2=expression,[...])用于向當(dāng)前模板的上下文賦值。 |
#set指令通常是用來給一個引用賦值。賦值對象不僅可以是變量引用,還可以是屬性引用。如下示:
| #set( primate = "monkey" ) |
| 注意:Tiny模板語言的#set指令賦值的內(nèi)容可以直接是變量名,但是不需采用${變量名}的形式賦值。如#set( customer.Behavior = $primate )就是一種錯誤的寫法。 |
“左操作數(shù)被賦值“是引用操作的一個規(guī)則。=號右側(cè)可能是以下類型之一:
- Variable reference變量引用?
- String literal字符串?
- Property reference 屬性引用
- Method reference 命令引用
- Number literal 數(shù)字
- ArrayList 數(shù)組
- Map 映射
請看下面例子,可以幫助聰明的您理解上述類型設(shè)置的理解:
| #set( monkey = bill ) ## variable reference #set( blame = whitehouse.Leak ) ## property reference #set( number = 123 ) ##number literal #set( friend = "monica" ) ## string literal #set( say = ["Not", friend, "fault"] ) ## ArrayList #set( map = {"banana" : "good", "kg" : 1}) ## Map |
| 注意:在ArrayList類型引用的例子中,其原素定義在數(shù)組 [..]中, 因此,您可以使 ${Say.get(0)}訪問第一個元素。 類似的,引用Map 的例子中, 原素定義在 { } 中,其鍵和值間以“:”隔成一對,使用 ${map.get("bannana") }在上例中將返回 'good', 如果寫成${map.banana}也會有同樣效果。 |
下面的例子是一般的計算表達(dá)式結(jié)果通過#set指令賦值:
| #set( value = foo + 1 ) #set( value = bar - 1 ) #set( value = foo * bar ) #set( value = foo / bar ) |
如果您在模板中對一個變量進行多次賦值 ,可以對其值進行替換,比如下例中,最終name變量中賦的值為字符串“def”。
| #set(name="abc",name="def") |
| 在TIny模板語言中,不論是定義的變量還是循環(huán)變量,在宏模板執(zhí)行過程中將全程有效,直到被修改。? |
在Tiny語言中,引入了變量作用域近者優(yōu)先的概念,當(dāng)前區(qū)塊有,則取當(dāng)前區(qū)塊,如果當(dāng)前區(qū)塊沒有,則取離得最近的變量。
比如:
| #for(i:[1,2,3,4,5])#for(i:[6,7,8,9])${i}#end${i} #end |
在上面的代碼中,兩個區(qū)塊的${i}不會任何影響。
在Tiny模板語言中已經(jīng)內(nèi)置上下文Context,如果調(diào)用宏,會產(chǎn)生一個上下文;如果進入循環(huán)語句,也會創(chuàng)建一個上下文。這些創(chuàng)建的上下文,在其生命周期是有限的,出了生命周期以后,設(shè)置在他上面的變量就不能被訪問了。如果在宏里或循環(huán)里,想把值設(shè)到自己的生命周期結(jié)束之后還可以被繼續(xù)使用,就要設(shè)置到模板的上下文上。
| 設(shè)置到當(dāng)前上下文用#set,設(shè)置到模板的上下文上,則用#!set,如果當(dāng)前位置就在模板中,使用#set和#!set沒有任何區(qū)別。? |
| 注意: #set 不需要使用 #end 來聲明結(jié)尾。 |
13.2 條件判斷
#if...#else...#elseif..#end?指令用來根據(jù)條件在頁面中輸出內(nèi)容,如下簡單的例子:
| #if( foo )Tiny! #end |
根據(jù)變量foo計算后是否為true決定輸出,這時會有三類情況:
(1)foo是null值,那么模板引擎處理結(jié)果為false。
(2)foo的是值是一個非null的boolean(true/false)型變量,那么計算結(jié)果直接取其值。
(3)它是一個非null的實例,若是String、Collection、Map、Array等類型,則當(dāng)其長度或大小大于0返回true否則返回false,若是Iterator則當(dāng)?shù)饔邢乱粋€元素返回true否則返回false;其他非null實例都返回true。
在 #if 和 #end 的內(nèi)容是否會輸出,由foo是否為true決定。這里,如果foo為true,輸出將是:Tiny!如果foo 為null或false,將不會有任何輸出。
#elseif 或 #else 可以 #if 和組合使用。如果第一個表達(dá)式為true,將會不計算以后的流程,如下例假設(shè)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 |
輸出將會是
| ?Go South. |
其中#if指令及#end指令必須包含,#elseif及#else指令可以省略,#elseif可以多次出現(xiàn),而#else最多只能出現(xiàn)一次。多個條件之間可以用&&、||等進行連接。有時候#else或#end會和后面的字符內(nèi)容連起來,從而導(dǎo)致模板引擎無法正確識別,這時就需要用#{else}或#{end}方式,避免干擾。
13.3 關(guān)系和邏輯運算
==相等運算
Tiny模板語言使用==來做比較,如下例.:
| #set (foo = "deoxyribonucleic acid") #set (bar = "ribonucleic acid")#if (foo == bar)In this case it's clear they aren't equivalent. So... #elseThey are not equivalent and this will be the output. #end |
| 浮點數(shù)比較,不推薦采用==方式進行比較,因為這樣會由于精度原因出現(xiàn)誤差,而導(dǎo)致看似相同的結(jié)果在執(zhí)行equals的時候返回false。 |
| 注意:== 計算與Java中的 == 計算有些不同,不能用來測試對象是否相等(指向同一塊內(nèi)存)。在相等運算時,Tiny模板引擎首先會判斷操作對象是否為null,若兩個操作數(shù)都為null,則判為相等,若兩操作數(shù)中僅有一個為null則判為不相等;若兩個操作數(shù)都是非null但類型相同,則調(diào)用其equals()方法。如果是不同的對象,會調(diào)用它們的toString()方法再調(diào)用兩個String的equals()結(jié)果來比較。 |
AND運算
| ## logical AND #if( foo && bar )<strong> This AND that</strong> #end |
僅當(dāng)foo 和bar都為true時,#if()才會輸出中間內(nèi)容.
OR 運算
| ## logical OR #if( foo || bar )<strong>This OR That</strong> #end |
foo或bar只要有一個為true就可以輸出。
NOT運算
NOT運算則只有一個操作參數(shù)或表達(dá)式 :
| ##logical NOT #if( !foo )<strong>NOT that</strong> #end |
13.4 循環(huán)語句
13.4.1 for循環(huán)
| #for|foreach(var:expression) ... #else ... #end |
| #for(number:[1,2,3,4,5])value:${number} #end #foreach(book:user.books)書名:${book.title},標(biāo)題:${book.author.name} #elseNo books found. #end |
其中expression必須是一個合法的Tiny Template表達(dá)式,具體參考表達(dá)式小節(jié)。
#end指令在使用的時候如果有歧義可以用#{end}代替。循環(huán)變量及循環(huán)狀態(tài)變量只在循環(huán)體內(nèi)可以使用,循環(huán)體外則不可用。
| <ul> #for ( product : allProducts )<li>${product.name}</li> #end </ul> |
在上述例子中,allProducts或是一個List、 Map或是?Array類型的容器集合,#for每一次循環(huán)都會將容器集合中的一個對象賦給暫存變量product(稱為循環(huán)變量),allProducts指定給變量 product 是一個引用到其中一個Java對象的引用。如果product確實是一個Java代碼中的Product類,它可以通過product.name訪問(或者Product.getName())。
我們假設(shè)?allProducts 是一個HashMap,您會發(fā)現(xiàn)要取出其中的東西是多么的簡單:
| <ul> #for ( key : allProducts.keySet())<li>Key: ${key} -> Value: ${allProducts.get(key)}</li> #end </ul> |
| Tiny模板引擎對于表達(dá)式進行了多種強力支持,不僅僅只有集合類型才可以參與運算,它的執(zhí)行規(guī)則如下:
|
循環(huán)狀態(tài)變量
每個#for語句,會在循環(huán)體內(nèi)產(chǎn)生兩個變量,一個是變量本身,一個是變量名+“For”,比如:
| #for(num:[1,2,3,4,5]) ... #end |
例如上面的例子中,在循環(huán)體內(nèi)可以有兩個變量可以訪問一個是“num”,一個是"numFor"。其中numFor是其狀態(tài)變量,用于查看for循環(huán)中的一些內(nèi)部狀態(tài),下面對numFor屬性進行詳細(xì)說明:
- numFor.index 可用于內(nèi)部循環(huán)計數(shù),從 1 開始計數(shù)。
- numFor.size 獲取循環(huán)總數(shù)。如果對 Iterator 進行循環(huán),或者對非 Collection 的 Iterable 進行循環(huán),則返回 -1。
- numFor.first 是否為第一個元素。
- ?numFor.last 是否為最后一個元素。
- numFor.odd 是否為第奇數(shù)個元素。
- ?numFor.even 是否為第偶數(shù)個元素。
循環(huán)中斷:#break
循環(huán)中斷語句只能用在循環(huán)體內(nèi),用于表示跳出當(dāng)前循環(huán)體。
| #break(expression) #break |
其中expression必須是一個合法的TinyTemplate表達(dá)式,具體參考表達(dá)式小節(jié)。
| #for(num:[1,2,3])#break(num==2) #end |
上面的例子表示當(dāng)num的值為2的時候,跳出循環(huán)體。
它等價于:
| #for(num:[1,2,3])#if(num==2)#break#end #end |
可以看出第一種寫法更方便。
| #break只能跳出一層循環(huán),不能跳出多層循環(huán)。#break只能放在循環(huán)體中,放在循環(huán)體外,會導(dǎo)致運行異常。 |
循環(huán)繼續(xù):# continue
循環(huán)繼續(xù)語句,只能用在循環(huán)體內(nèi),表示不再執(zhí)行下面的內(nèi)容,繼續(xù)下一次循環(huán)。
| #continue(expression) #continue |
其中expression必須是一個合法的Tiny Template表達(dá)式,具體參考表達(dá)式小節(jié)。
| #for(num:[1,2,3])#continue(num==2) #end |
表示當(dāng)num的值為2的時候,執(zhí)行下一次循環(huán)。
它等價于:
| #for(num:[1,2,3])#if(num==2)#continue#end #end |
可以看出上面的寫法更方便。
| #continue只能繼續(xù)當(dāng)前循環(huán),不能繼續(xù)外層循環(huán)。#continue只能放在循環(huán)體中,放在循環(huán)體外,會導(dǎo)致運行異常。 |
13.4.2 while循環(huán)
| #while(expression) ... #end |
| while循環(huán)指令是模板引擎2.0.10新增加的指令,更早的版本是不支持的。 |
下面是具體使用例子。
| #set(i=0) #while(i<10)#set(i=i+1)${i} #end |
Tiny模板引擎中的循環(huán)語句,expression可以支持任意的表達(dá)式。
13.5 模板嵌套語句#include
| #include(expression) #include(expression,{key:value,key:value}) |
#include內(nèi)的這個表達(dá)式應(yīng)該是一個字符串,用于指定要嵌套的子模板的路徑。它后可以跟參數(shù),也可以不跟參數(shù),如果跟參數(shù)的話,只能跟一個map類型的值。
示例
| #include("/a/b/aa.page") ##表示絕對路徑 #include("../a/b/aa.page") ##表示相對路徑#include(format("file%s-%s.page",1,2)) ##表示采用格式化函數(shù)執(zhí)行結(jié)果作為路徑,這個例子中為:與當(dāng)前訪問路徑相同路徑中的"file1-2.page"文件 #include("/a/b/aa.page",{aa:user,bb:book})##表示帶參數(shù)訪問,會帶過去兩個參數(shù)aa和bb。 |
子模板可以訪問所有祖先模板中的變量。出于封裝性方面的考慮,在Tiny模板語言中子模板不能修改父模板中變量的值,從而避免不可預(yù)知的問題。
13.6 宏定義語句#macro
在Tiny模板引擎中,宏是一個非常強大靈活的東西,使用它可以避免在模板中編寫重復(fù)的代碼,也可方便一些具體業(yè)務(wù)的開發(fā)。
| #macro macroName([varName[=expression][,varName[=expression]]])#bodyContent #end |
宏的名字和變量的名字必須符合Tiny變量的定義規(guī)范,宏的參數(shù)的個數(shù)可以為0~N個。宏定義的參數(shù)可以設(shè)置默認(rèn)值,參數(shù)分隔可以采用英文逗號或者空格。#bodyContent表示中間可以包含任意的符合Tiny模板規(guī)范的內(nèi)容,#bodyContent也可以不存在,因此對應(yīng)了不同的調(diào)用方式。
在Tiny模板語言中宏的調(diào)用方式有兩種,一種是單行調(diào)用方式,格式如下:
| #macroName([expression|varName=expression[,expression|varName=expression]*]) |
另外一種是帶內(nèi)容調(diào)用方式,格式如下:
| #@macroName([expression|varName=expression[,expression|varName=expression]*]) ...... #end |
參數(shù)支持按順序賦值方式,也支持命名賦值(varName=值)方式。參數(shù)分隔可以采用英文逗號或者空格。
| #@macroName([expression|varName=expression[,expression|varName=expression]*]) ...... #end |
例如在模板中定義如下宏:
| #macro header(subTitle)<h1>Tiny框架:${subTitle}</h1> #end |
調(diào)用方式:
| #header("homepage") #header("about") |
運行結(jié)果:
| <h1>Tiny框架:homepage</h1> <h1>Tiny框架:about</h1> |
為了進一步說明宏定義,請看下面的進階示例
| #macro div() <div>#bodyContent </div> #end #macro p()<p>#bodyContent</p> #end |
調(diào)用方式:
| #@div()#@p()<em>一些信息</em><b>一些內(nèi)容</b>#end #end |
運行結(jié)果:
| <div><p><em>一些信息</em><b>一些內(nèi)容</b></p> </div> |
| 自定義宏macro的訪問有兩種方式:一種是包含內(nèi)容的,一種是不包含內(nèi)容的。 |
如果參數(shù)變量與外部變量的名稱完全相同,這個變量可以不在調(diào)用時傳遞,Tiny模板引擎會自動讀取外部變量對應(yīng)的值。通過命名傳值可以避免復(fù)雜的傳值指令及不必再費心考慮參數(shù)順序。
另外宏的定義支持嵌套定義,也就是說支持下面的形式:
| #macro aa()aa-Content#macro bb()bb-Content#end #end |
它等價于下面的方式:
| #macro aa()aa-Content #end #macro bb()bb-Content #end |
考慮到代碼的易讀性,建議還是采用第二種的定義方式。
在Velocity中定義宏的時候是不可以調(diào)用帶內(nèi)容的宏的,而在強大的Tiny模板引擎中,則可以無限定義,強力支持。
| #macro macroName()#@subMacroName1()#@subMacroName1()#bodyContent#end#end #end |
13.7 宏引入語句#import
如果項目中存在同名宏,那么就會涉及加載的選擇問題。#import指令可以確定引入宏的執(zhí)行順序,從而解決宏沖突的問題。
| #import(expression) #import("/a/b/filename") ##表示絕對路徑,其中filename表示宏名稱。 |
這個表達(dá)式的執(zhí)行結(jié)果應(yīng)該是一個字符串,其標(biāo)示了要引入的宏的路徑。
| #import("/aa/aa/aa.component") 表示引入/aa/aa/aa.component。 |
13.8?布局重寫語句#layout #@layout?
在使用Tiny模板語言開發(fā)的Web項目中如果定義布局文件(*.layout)和頁面文件(*.page)就會遇到如下需求:針對特定頁面展示不同的布局樣式,目前有兩種實現(xiàn)方式:
| |
| #layout(layoutName) ...... #end ? |
#layout指令用于布局文件(*.layout),定義布局文件的名稱,制定通用的布局格式。
| #@layout(layoutName) ...... #end |
#@layout 指令用于頁面文件(*.page),如果layoutName的布局存在,則模板引擎在渲染布局時使用用戶在#@layout 指令里定義的布局覆蓋原有布局。
layout指令就是為實現(xiàn)布局文件的特殊渲染而設(shè)計的,以下是簡單示例,方便大家理解:
首先,創(chuàng)建布局文件default.layout。
| this is default layout start #layout(weblayout) this is default#pageContent #end this is default layout end |
上述例子中,我們定義了名為weblayout的布局樣式。接下來就是定義頁面文件a.page。
| #@layout(weblayout)this is layout of weblayout.#pageContent #end this is a.page |
在模板中weblayout的布局樣式被用戶自定義的樣式給取代,模板渲染的結(jié)果如下:
| this is default layout startthis is layout of weblayout.this is a.pagethis is default layout end |
我們再嘗試修改a.page,重寫一個不存在的布局樣式weblayout2.
| #@layout(weblayout2)this is layout of weblayout2.#pageContent #end this is a.page |
渲染的效果如下:
| this is default layout startthis is defaultthis is a.pagethis is default layout end |
13.9 停止執(zhí)行#stop
?#stop 指令用來指示在模板的某處直接結(jié)束當(dāng)前處理,終止模板的渲染,引擎停止解析。
| #stop(expression) #stop |
當(dāng)模板中調(diào)用#stop時無條件直接終止模板渲染。Tiny模板引擎還支持帶條件執(zhí)行終止模板渲染,請看下面的例子:
| #stop(num==2) |
上述例子表示當(dāng)num==2時執(zhí)行#stop終止模板渲染,它等價于:
| #if(num==2)#stop#end |
?可以看出上面的寫法更方便。
13.10 返回指令#return
返回指令,停止某個宏的后續(xù)邏輯的渲染,類似Java方法中的return指令;如果用戶在page頁面使用該指令,會影響整個頁面的渲染。
| #macro log(level info)#if(level=='debug')<debug>${info}</debug>#else#return#end #end ##以上示例在宏中使用return指令,如果觸發(fā)return機制,模板引擎會停止對宏以后內(nèi)容的渲染#while(i<10)#set(i=i+1)#if(i>7)#return#end${i} #end |
| 在page頁面中使用return指令,可能會導(dǎo)致以后頁面停止渲染,用戶請慎用! |
return指令的作用與stop指令相同,部分場合可以相互替換,但是還是存在以下差異:
(1)return是指退出當(dāng)前執(zhí)行場景,如宏或模板。
(2)stop是直接終止模板引擎的繼續(xù)渲染,僅輸出已經(jīng)渲染內(nèi)容。
13.11 行結(jié)束指令
| #eol #{eol} |
表示顯式輸出一個“\r\t”。
在Tiny模板引擎中,默認(rèn)會把文本輸出內(nèi)容進行trim操作,因此,默認(rèn)是沒有回車換行符的。因此,如果想額外增加一個回車換行符,就需要增加#eol指令。但在HTML頁面中并不是<Br>。
14 系統(tǒng)內(nèi)置函數(shù)
系統(tǒng)內(nèi)嵌函數(shù)是指在模板引擎中默認(rèn)就會注冊的函數(shù),直接可以拿來使用的函數(shù)。
14.1 讀取文本資源函數(shù)read,readContent
讀取文本資源函數(shù)(read,readContent) ,用于讀取指定路徑的文本資源,并返回指定結(jié)果。如果讀取的是模板文件,得到的將是未經(jīng)渲染的文本內(nèi)容。
| read("src/test.txt") readContent("src/test.txt") |
函數(shù)調(diào)用后的返回值是加載文本資源的字符串。
14.2?解析模板parse?
?解析模板可以用內(nèi)置函數(shù)parse引入一個包含TTL的模板文件,Tiny模板引擎把解析這個文件的結(jié)果作為函數(shù)返回值。
| parse(expression) parse("/a/b/filename") ##表示絕對路徑,其中filename表示宏名稱。 |
?與 #include 指令不同,引入的模板經(jīng)過內(nèi)置函數(shù)parse處理后可以得到一個變量引用,方便模板中其他地方再引用。
14.3 格式化函數(shù)fmt,format,formatter
格式化函數(shù)(fmt,format,formatter),用于對數(shù)據(jù)進行格式化,并返回執(zhí)行結(jié)果。該類函數(shù)的底層實現(xiàn)是調(diào)用了java.util.Formatter實現(xiàn)的,因此具體如何填寫格式化串可以參考java.util.Formatter用法。
| #set(result=format("hello,%s%s",name,city)) ${format("hello,%s",name)} |
14.4 宏調(diào)用方法call,callMacro
宏調(diào)用方法(call,callMacro),用于執(zhí)行一個宏,并把執(zhí)行完成的結(jié)果作為字符串返回。call函數(shù)的返回值為宏的運行結(jié)果。call有類似macro語法,也是支持單行調(diào)用和多行帶內(nèi)容調(diào)用。
單行調(diào)用:
| #call("macroName") #call("macroName",1,2) #callMacro("macroName") #callMacro("macroName",1,2) |
?多行帶內(nèi)容調(diào)用,需要結(jié)束標(biāo)識。
| #@call("macroName")...... #end |
因此,以下三種方式是等價的:
| ${call("macroName")} #call("macroName") #macroName() |
14.5 實例判斷函數(shù)is,instanceOf,instance
| is(object,classType...) instanceOf(object,classType...) instance(object,classType...) |
類實例判斷函數(shù)會根據(jù)傳入對象判斷是否為指定類的實例,返回值為true或者false。
| ${instance("abc","java.lang.String","java.lang.Byte")} ${instanceOf(10,"java.lang.Integer")} |
14.6 求值函數(shù)eval,evaluate
| eval("模板內(nèi)容")evaluate(templateContentVarName) |
求值 函數(shù)(eval,evaluate),用于執(zhí)行一段宏代碼,執(zhí)行后的結(jié)果為字符串
| #set(result=eval("hello,${name}"))${eval("hello,${name}")} |
14.7 隨機數(shù)函數(shù)rand,random
隨機數(shù)函數(shù)用于生成指定類型的隨機數(shù)。目前支持int、long、float、double和uuid五種類型。注意該函數(shù)是在模板引擎2.0.16版本之后提供的,更早版本是不支持這個函數(shù)的
| rand("隨機數(shù)類型") rand() random("隨機數(shù)類型") random() |
返回值:隨機數(shù),如果不指定類型,默認(rèn)返回int類型;如果指定類型,返回指定類型的隨機數(shù)
| ${rand()} ${random()} ${rand("int")} ${random("long")} ${rand("float")} ${rand("double")} ${rand("uuid")} |
14.8 ?類型轉(zhuǎn)換函數(shù)
Tiny模板語言中有可能經(jīng)常會遇到String類型的引用轉(zhuǎn)成其他基本類型(Integer、Double、Float、Long、Bool)的引用,Tiny模板引擎為您提供了一系列函數(shù),請看下面的示例。
| ${toInt("8")+toInt("2")} ${toDouble("2")} ${toFloat("20.4")+toFloat("20.8")} ${toBool("true")?1:2} |
執(zhí)行結(jié)果如下:
| 10 2.0 41.199997 1 |
14.9 日期格式轉(zhuǎn)換formatDate
為了使Java的Date類型在模板語言能按照您的指定格式輸出,Tiny模板引擎內(nèi)置了formatDate/formatdate(date,formatPatten)。formatDate系統(tǒng)函數(shù)的第一個參數(shù)是Date類型,第二參數(shù)是格式化模式。另外Tiny模板引擎還提供一個獲取當(dāng)前系統(tǒng)時間Date對象的系統(tǒng)函數(shù)now()。
| ${formatDate(now(),"yyyy年MM月dd日 HH:mm:ss")} |
上面的例子模板語言解析得到當(dāng)前系統(tǒng)時間,并按照格式“?yyyy年MM月dd日 HH:mm:ss”輸出。
15 其它特性和細(xì)節(jié)
15.1 數(shù)學(xué)計算
Tiny模板語言自帶一些數(shù)學(xué)函數(shù),可以用#set指令在模板中使用。下面是四則運算的例子:
| #set( foo = bar + 3 ) #set( foo = bar - 4 ) #set( foo = bar * 6 ) #set( foo = bar / 2 ) |
兩個整數(shù)間的除法運算的結(jié)果仍是整數(shù),小數(shù)部分會被剔除。余數(shù)可以用取余運算符(%)得到,例如:
| #set( foo = bar % 5 ) |
15.2 范圍操作符
范圍操作符可以與#set和#foreach語句一起使用。用它來生成包含整數(shù)的數(shù)組非常方便:
| [n..m] |
其中n和m必須是整數(shù)。m可以大于n也可以小于n。如果m小于n,整數(shù)序列是遞減的。
例子一:
| #for( foo : [1..5] )${foo} #end |
例子二:
| #for(bar : [2..-2] )${bar} #end |
例子三:
| #set( arr = [0..1] ) #for( i : arr )${i} #end |
例子四:
| ?[1..3] |
例子一結(jié)果:
| ?1 2 3 4 5 |
例子二結(jié)果:
| ?2 1 0 -1 -2 |
例子三結(jié)果:
| ?0 1 |
例子四結(jié)果:
| ?[1..3] |
15.3 連接字符串
很簡單,看例子就是 :
| #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. |
除此之外,您還可以通過系統(tǒng)函數(shù)fmt輸出拼裝字符串。
| #set( size = "Big" )#set( name = "Ben" )${fmt("The clock is %s %s",size,name)} |
上面模板的輸出將是
| ?The clock is Big Ben |
15.4 文本內(nèi)容轉(zhuǎn)義輸出
如果有些內(nèi)容本來是文本內(nèi)容,但是由于與模板引擎的指令或表達(dá)式產(chǎn)生沖突,此時可以采用轉(zhuǎn)義方式進行處理。
比如:如果一個變量email己定義了(比如它的值是 foo),而這里您不是要讀取變量email的值,想直接輸出${email}這樣一個字符串,就需要使用轉(zhuǎn)義字符”\”。
| ## The following line defines $email in this template: #set(email = "foo" ) ${email} \${email} \\${email} \\\${email} \#macro abc() |
上面的模板在Web頁面上的輸出將是:
| foo ${email} \foo \${email} #macro abc() |
另外,還可以使用#[[...]]#不解析文本塊的所有內(nèi)容。例如:
| This ia test info.<a href="#">link</a> #[[ ${abc}#macro aa()info #end ]]# |
它的運行結(jié)果為:
| This ia test info.<a href="#">link</a>${abc}#macro aa()info #end |
非模板引擎支持的類似的指令,比如:#aabbff,不會被識別成指令,而會原樣輸出,可以不進行轉(zhuǎn)義。"\" 后面跟的字符不是 "#" 和"$",也不需要進行轉(zhuǎn)義,直接輸出。
轉(zhuǎn)載于:https://my.oschina.net/tinyframework/blog/502249
總結(jié)
以上是生活随笔為你收集整理的Tiny模板语言(VelocityPlus)初步入门的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安装程序检测到无法验证文件的发行者_文件
- 下一篇: 为Mac安装homebrew