2019獨角獸企業重金招聘Python工程師標準>>>
1 關于用戶手冊
本文主要介紹如何在模板中使用Tiny模板語言,通過查閱本手冊,可以對Tiny模板語言 TTL(Tiny Template Language)的用法有一個較全面的認識,并學會如何有效地使用Tiny模板語言。同時,本文提供了較多的例子幫您來學習并掌握它。
2 Tiny模板語言概述
Tiny 模板語言是一個參考Velocity語法的模板語言,它對Velocity模板語言中一些功能不太完全及使用過程中比較不方便的地方進行全面的擴展和升級,同時為了更好的適應Web界面層的開發,還提供了強大的布局功能。本文中的例子都使用Tiny 模板語言來開發。
|
感謝您選擇Tiny模板引擎!
3 Tiny模板語言能為您做什么?
假設您是一家專門出售Mud的在線商店的頁面設計人員,讓我們暫且稱它為“在線MUD商店”。您的業務非常繁忙,客戶下了各種類型和數量的Mud訂單。他們都是通過用戶名和密碼登陸到您的網站,登陸后就允許他們查看訂單并購買更多的Mud。現在,一種非常流行的Mud正在打折銷售。另外有一些客戶規律性地購買另外一種也在打折但不是很流行的Bright Red Mud,由于購買的人并不多,所以它被安置在頁面的邊緣。另外所有用戶的操作信息都是被跟蹤并存放于數據庫中的,所以某天有一個問題可能會冒出來:如何給每個用戶定制一個自己的頁面,讓他們瀏覽自己的感興趣的物品。為什么不使用模板語言來使用戶更好的瀏覽他們感興趣的商品呢?而Tiny模板語言就是一個非常不錯的選擇。
Tiny Template使得定制化Web頁面非常容易。作為一個Web Site的設計人員,您希望每個用戶登陸時都擁有自己的頁面。
您咨詢了一些公司內的軟件工程師,您發現他們每個人都同意客戶應該擁有具有個性化的信息。那讓我們把軟件工程師應該作的事情放在一邊,看一看您應該作些什么吧。
您可以在頁面內嵌套如下的TTL聲明:
|
使用Tiny模板引擎實現WEB界面就是這么簡單!本文后續會有更全面的TTL語法介紹,掌握這些,您將會全面體會到Tiny模板引擎的威力。
4 Tiny模板語言簡介
Tiny模板語言的目標是提供一個簡潔、易學的方法將動態內容展現到Web頁面上,使得Web頁面設計者可以在沒有任何編程語言經驗就可以在非常短的時間內(一天?)學會使用它,增強您的網站展現力。
TTL使用引用這種方式將動態內容(一般指Java代碼中生成的數據對象)顯示到您的Web Site上。Tiny模板語言的變量只是引用中的一種,變量是用來描述要展現到視圖模板中的Java數據對象。當然,Java代碼也可以從模板TTL中獲取數據,以下是一個寫在HTML中的TTL變量:
|
TTL語句:所有的TTL 語句都是以#開頭,且包含一個指令(這里是set),當用戶訪問您的頁面時, Tiny模板引擎將搜索頁面中的所有“#”符號,如果確定這是一個TTL語句時就按規則處理動態內容, 符號“#”僅僅只是表明這可能是一個TTL聲明。
符號“#”所跟的set我們用“指令”這一名詞來稱呼它(隨后介紹更多的指令),set指令使用一個表達式(expression) (包含在一對括號里)將一個值value(這里是字符串“Tiny”)賦給變量a,(變量名在左邊,值在右邊,用“=”組合起來)。
在以上的例子中,變量是a,無需額外特殊符號標記變量,所賦值的字符串要用引號括起。而字符串的拼接可以使用運算符“+”操作,或者系統函數format進行格式化拼裝。
請理解Tiny模板語言基本規則:
${expression}輸出表達式的計算結果,而expression(表達式)中變量無需額外符號標記變量。而指令則以#開頭來表示,有點“做些什么動作”的意思。
在上面的例子中,#set用來指定值給一個變量名a, 而變量名a的值就是"Tiny"。
5 Hello Tiny!
在您的HTML文檔的任何地方,都可以引用一個變量名來輸出值, 如下例,先給變量foo 賦值為Tiny,然后將它輸出到頁面中。
|
在這個頁面上,您看到的將是 "Hello?Tiny!"。
為了讓編輯器中的TTL指令更易讀,我們強烈建議您每行只有一條TTL指令,當然這不是必須的。 關于set 指令的更多功能我們隨后再討論。
6 注釋
注釋可以讓您在模板中包含對TTL或其它問題的說明描述以便與閱讀和理解。但它并不會在最終輸出的WEB頁面中看到。如下示例是TTL中的一行注釋。
|
單行注釋是以“##”開頭的一行文字。如要寫下多行注釋,就要像下面那樣,將它們放入“#*”和“*#”間或“#--”和“--#”間:
|
雖然引擎只是提供了兩種簡單的注釋方式,但卻能滿足您在頁面上添加必要的說明文字。
之所以支持兩種塊注釋方式,是為了在兼容性及方便性方面提供更大的便捷。#* *#方式是為了與Velocity兼容,這樣熟悉Velocity的人員更容易上手。#-- --#是為了便于把Html中的注釋改成Tiny模板注釋。
7 引用(References)
TTL中有三種引用references:變量引用(variables),屬性引用(properties)和方法引用(methods)。作為使用TTL的頁面開發者, 您必須和您的Java工程師在特定的引用名稱上達成一致,這樣模板和Java代碼才可按照你們的預期去結合以輸出正確的內容。
所有的引用在模板中的輸出都表現為一個字符串。假設一個引用變量 foo ,它是一個int型變量, Tiny模板引擎在處理時將調用它的.toString()去解析這個對象(int),從而獲得代表它的字符串。
7.1 變量(variables)
|
上面的正則表達式表示,在Tiny框架引擎中,變量必須是以下劃線或大小寫字母開頭的,后續可以跟下劃線或大小寫字母和數字的字符串,才可以作為變量名。實際上宏的名字,也是遵守同樣的規則。
簡單地說,變量不需要任何額外的符號開頭,一個合法的TTL變量名是以字母開頭,后面可以是以下任意字符:
- 字母(a .. z, A .. Z)
- 數字(0 .. 9)
- 下劃線 ("_")
以下是正確的TTL變量名:
|
如果想在TTL中引用一個變量如 foo,可以通過set命令設置自己的值,也可以從Java代碼中獲取。例如, Java變量foo的值為”bar”, 如果想在模板中輸出這個值,那么模板中引用${foo}就可以在Web頁面中輸出所需值。另一種方式是在模板中使用如下TTL也可以達到這個目地。
|
只要符合上面的規范的字符串都可以作為Tiny框架引擎中的變量,即使是Java的關鍵字也可以。
需要注意的是,由于在進行循環時,Tiny模板引擎會在循環變量名后附加“For”作為狀態變量,因此,需要注意避免沖突,以影響使用。 |
7.2 屬性(properties)
TTL的第二種引用是屬性引用,屬性引用不需要任何額外特殊符號開頭,只需簡單地按照“變量名字.變量屬性”的形式即可。如下例:
|
“customer.address”我們設想可能在兩種意思。首先它可能查找一個類型為Map的customer的引用,并以“address”為key的一個數據對象。另外它可能表示的是Java對象customer中的getAddress()這個方法的返回值(當然也可寫成 customer.getAddress())。當用戶請求Web頁面,Tiny模板引擎將根據具體的customer類型進行處理。如果想在頁面直接輸出這個屬性,那么應該加一個取值符號${},例如${customer.address}。
注意:在Tiny語言模板使用屬性的引用時,引擎首先會通過Java Bean中的getter/setter實現的,如果沒有找到相應的方法,引擎才會再去尋找該對象的屬性字段,并且這個屬性訪問權限只有為public時才能解析引用。而Java對象的其他受保護的數據域是不能直接引用的,Tiny模板引擎遵守Java數據安全規則。 |
如${foo.name}會解析到 對象foo的 getName()的實例方法或public name這個實例變量,但不會解析到Foos類的 private name這個實例變量。
7.3 方法(methods)
在Java 代碼中定義方法是最平常的事。方法引用和其它引用一樣也是一個TTL聲明,看如下的例子可能可以更快地理解:
|
上述兩個例子中customer.getAddress()和purchase.getTotal()可以等同與屬性引用情況: customer.address和 purchase.total。如果您已經領悟到了這點,您的確是很聰明的!后面兩個引用也會直接對應Java對象的對應方法,不同的是傳入了參數。
8 表達式(Expression)
8.1 取值表達式
上文介紹了變量、屬性和方法調用等引用的定義。那么要將這些引用的結果輸出打印都需要經過取值表達式。在Tiny引擎模板中取值表達式分為有兩種:
(1)${expression}:輸出表達式的計算結果
(2)$!{expression}:輸出表達式的計算結果,并轉義其中的 HTML 標簽。
其中expression必須是一個合法的Tiny Template表達式,如果您繼續閱讀本文后續的介紹將會了解表達式規范。Tiny模板引擎取值表達式{}不可以省略,${expression}和$expression不是等價的。如果表達式執行結果為null或void,則不會輸出任何內容。注意:取值表達式作為指令的參數時,不可以采用${expression}形式需要去掉{},同時在字符串參數中,也不支持${expression}。也許您現在還不能理解這點,不過繼續閱讀下文您會慢慢領悟的。
8.2 Map常量
|
在模板中為了數據存儲、傳遞的方便,Tiny模板語言提供了Map常量的表達方式。Map常量經常直接作為指令或自定義宏的參數,下面的例子希望能幫助您快速理解如何定義Map常量。
|
上面的例子是告訴您如何定義Map常量,事實上,在模板中定一個Map變量也類似上面的形式,只不過您還需要使用#set指令,并制定一個具體的參數名。下面的例子希望能幫助您快速理解如何調用Map常量。
|
{aa:1}和{"aa":1}的含義是不同的,這一點必須要注意。 {aa:1}表示key值是aa變量的值,${"aa":1}表示key值是"aa"的字符串。 因此,如果寫為{aa:1}的形式時,如果沒有aa變量存在,則會報空指針錯誤。 |
如果不能確認,前面的變量是否為空,可以加一個安全調用方式: |
8.3 數組常量
|
在模板中定義數組常量也十分簡單,看了下面的例子相信您一定可以掌握。
|
而調用數組常量的方式有兩種,一種是直接通過下標索引的方式,另一種是調用get(index)方式。
|
如果不能確認,前面的變量是否為空,可以加一個安全調用方式:${list?.[index]}或${list?.get(1)} |
8.4 其他表達式
類型 | 表達式 | 說明 |
邏輯運算 | ! && || | |
自增/自減 | ++ -- | 不論放在變量前面與后面,沒有區別 |
算術計算 | + - * / % | |
空值常量 | null | |
移位運算 | >>? >>>? <<? | |
比較運算 | == !=? ?> >=? ?<? ?<= | ==的執行邏輯請查看13.3 關系和邏輯運算。 |
方法調用 | functionName([...]) | 調用框架中的內嵌或擴展方法。 |
數組讀取 | array[i] | |
數字常量 | 123 123L 99.99F 99.99d 99.99e99? -99.99E-10d 0xFF00 0xFF00L 0.001 0.001D 1.10D | ?前綴0x不可以寫成0X,后綴lfde可以用相應LFDE替換 |
成員方法調用 | object.methodName([...]) | 可以通過框架為某種類型增加新的方法或覆蓋原有方法。 |
成員屬性訪問 | object.fieldName | |
布爾值常量 | true false | |
字符串常量 | "abc\r\n" 'abc\u00A0\r\n' | 不論是單引號框起來的字符串還是雙引號框起來的字符串,都是一樣的,唯一的區別有,當字符串中包含雙引號或單引號的時候可以少用轉義符。 |
位運算 | ~ ^ & | | |
三元表達式 | exp?a:b exp?:b | a?:b等價于a?a:b,當表達式比較復雜的時候,這種簡寫形式會比較漂亮,也更容易閱讀 |
Tiny模板引擎對于布爾表達式進行多種強力支持,不僅僅只有布爾值才可以參與運算,它的運行規則如下:
- 如果是null,則返回false
- 如果是布爾值,則返回布爾值
- 如果是字符串且為空串“”,則返回false
- 如果是集合,且集合中沒有元素,則返回false
- 如果是數組,且數組長度為0,則返回false
- 如果是Iterator類型,則如果沒有后續元素,則返回false
- 如果是Enumerator類型,則如果沒有后續元素,則返回false
- 如果是Map類型且其里面沒有KV對,則返回false
- 否則返回true
在訪問屬性或成員變量的時候,普通的方式是用“.”運算符,也可以使用"?.”運算符,表示如果前置變量非空,都繼續執行取屬性值或調用成員函數,避免空指針異常的發生。 |
#if(0)zero#end會顯示zero,在Tiny模板語言中,只要有值就會返回true。 |
9 索引表示法
用類似foo[0]的方式可以獲取一個對象的指定索引的值。這種形式類似調用get(Object)方法,實際上是提供了一種簡略,比如foo.get(0)。因此以下幾種寫法都是調用get方法:
|
Java數組適用相同的語法,因為Tiny模板引擎將數組包裝成一個對象,它可以通過get(Integer)獲得指定索引對象的元素。例如:
|
10 渲染
無論是變量、屬性還是方法等這些引用的最終結果值的渲染輸出本質都會轉換成String對象。例如要取值輸出一個Integer對象${foo},那么Tiny 模板引擎就會調用它的.toString()方法,從而將對象解析轉換成一個字符串。
11 與Java無縫對接
至此,您對Tiny模板語言已經有了一定程度的了解,相信您已經迫不及待的想使用它來開發應用了。但您不要忘記,Tiny模板語言與Java是無縫對接的,Tiny模板引擎設計者花費了一定的精力做到了與Java很好的兼容,并且從Java語法中也汲取了一些優點,使得模板設計者更容易使用TTL。比如對于變量foo:${foo.getBar()}等同于${foo.bar}。
現在您大概了解到了Tiny模板語言引用的不同方式但得到的是相同的結果,事實上Tiny模板語言融合了Java和Java Bean的相關簡潔語法和規范來解析Java代碼中的對象和這些對象的方法及其屬性,使得Java對象的大部分功能都可以展示到視圖中,同時還有較好的處理性能。
12 模板布局
布局在Tiny模板引擎中是一個非常重要的概念,通過Tiny模板引擎,可以快速進行頁面構建與渲染,并且減少程序員工作量。Tiny模板引擎設計者認為越到底層的程序員,所要完成的工作越少。如果您將Tiny模板語言與同類的模板引擎的布局實現相比會發現,Tiny模板引擎中的布局具有一定的強制性,這也同時減少了程序員的開發工作量,程序員不再需要關心布局文件的引入,只要放入有布局文件的目錄,就會應用布局;您把它拿出來,它也就沒有了。
用于設置Tiny模板語言的布局的文件稱為布局文件。布局布局文件的方法結構與普通模板文件完全相同,只是它的擴展名與模板文件名不同,它的文件名以“.layout”結尾,用以區別。布局文件與模板文件完全相同,只是在布局文件中需要放置一個#pageContent標簽,用以標示插入點。
為了更好的理解Tiny模板引擎中的布局,直接用示例說明,下面是目錄結構:
|
/template/tiny/layout/div目錄中aa.page的內容如下:
|
/template/tiny/layout/div目錄中default.layout的內容如下:
|
/template/tiny/layout目錄中的default.layout的內容如下:
|
下面是執行結果:
|
也就是說,雖然aa.page文件里只有Hello,World,但是由于在與它同名路徑中有一個布局文件,因此用布局文件對其進行了渲染,從而變成下面的內容:
|
但是引擎發現它上層目錄中另外還有一個布局文件/template/tiny/layout/default.layout,于是引擎就被渲染出上文看到的最終結果。
在Tiny模板語言中使用布局十分方便,布局文件不需要在模板文件進行顯式聲明。布局文件的命名規范為:模板基本文件名+“.”+布局文件擴展名,比如:模板文件名為:aa.page,則模板基本文件名為aa,其布局文件擴展名為layout,這個時候它的布局文件名就是:aa.layout。
Tiny模板引擎中有一個特殊的布局文件名,它就是default+"."+布局文件擴展名,比如:布局文件擴展名為layout,這個時候它的布局文件名就是:default.layout。
為了說明模板布局的進階用法,請看下面的舉例,假如有下面的目錄:
|
/template/tiny/layout/div目錄中aa.page的內容如下:
|
/template/tiny/layout/div目錄中bb.page的內容如下:
|
/template/tiny/layout/div目錄中default.layout的內容如下:
|
/template/tiny/layout/div目錄中aa.layout的內容如下:
|
/template/tiny/layout目錄中的default.layout的內容如下:
|
aa.page執行結果如下:
|
bb.page執行結果如下:
|
聰明的您一定明白了,布局文件的渲染過程是這樣的,優先渲染與模板文件同名的布局文件,只有不存在與模板文件同名的布局文件的時候,才會渲染default.layout布局文件。詳細的渲染過程分析如下:
aa.page先去找同級aa.layout,如果找到了,渲染同級aa.layout。再往上一級遞歸渲染到上一級的default.layout。
bb.page先去找同級bb.layout,如果找不到,去找同級default.layout。如果找到,渲染同級default.layout。再往上一級遞歸,渲染到上一級的default.layout。
Tiny模板引擎的默認擴展名為layout、component、page,分別代表而已文件、宏文件、頁面文件。在實際應用當中,也可以根據自己的喜好設置為其它的名字。 |
13 指令集
在模板中您可以使用“引用”生成動態內容,而指令簡單地說就是設計者在模板中操作Java對象,方便頁面設計者有效地控制輸出內容的格式。
指令總是以#開頭后面緊跟具體的指令符。
13.1 #set指令
|
#set指令通常是用來給一個引用賦值。賦值對象不僅可以是變量引用,還可以是屬性引用。如下示:
|
注意:Tiny模板語言的#set指令賦值的內容可以直接是變量名,但是不需采用${變量名}的形式賦值。如#set( customer.Behavior = $primate )就是一種錯誤的寫法。 |
“左操作數被賦值“是引用操作的一個規則。=號右側可能是以下類型之一:
- Variable reference變量引用?
- String literal字符串?
- Property reference 屬性引用
- Method reference 命令引用
- Number literal 數字
- ArrayList 數組
- Map 映射
請看下面例子,可以幫助聰明的您理解上述類型設置的理解:
|
注意:在ArrayList類型引用的例子中,其原素定義在數組 [..]中, 因此,您可以使 ${Say.get(0)}訪問第一個元素。 類似的,引用Map 的例子中, 原素定義在 { } 中,其鍵和值間以“:”隔成一對,使用 ${map.get("bannana") }在上例中將返回 'good', 如果寫成${map.banana}也會有同樣效果。 |
下面的例子是一般的計算表達式結果通過#set指令賦值:
|
如果您在模板中對一個變量進行多次賦值 ,可以對其值進行替換,比如下例中,最終name變量中賦的值為字符串“def”。
|
在TIny模板語言中,不論是定義的變量還是循環變量,在宏模板執行過程中將全程有效,直到被修改。? |
在Tiny語言中,引入了變量作用域近者優先的概念,當前區塊有,則取當前區塊,如果當前區塊沒有,則取離得最近的變量。
比如:
|
在上面的代碼中,兩個區塊的${i}不會任何影響。
在Tiny模板語言中已經內置上下文Context,如果調用宏,會產生一個上下文;如果進入循環語句,也會創建一個上下文。這些創建的上下文,在其生命周期是有限的,出了生命周期以后,設置在他上面的變量就不能被訪問了。如果在宏里或循環里,想把值設到自己的生命周期結束之后還可以被繼續使用,就要設置到模板的上下文上。
設置到當前上下文用#set,設置到模板的上下文上,則用#!set,如果當前位置就在模板中,使用#set和#!set沒有任何區別。? |
注意: #set 不需要使用 #end 來聲明結尾。 |
13.2 條件判斷
#if...#else...#elseif..#end?指令用來根據條件在頁面中輸出內容,如下簡單的例子:
|
根據變量foo計算后是否為true決定輸出,這時會有三類情況:
(1)foo是null值,那么模板引擎處理結果為false。
(2)foo的是值是一個非null的boolean(true/false)型變量,那么計算結果直接取其值。
(3)它是一個非null的實例,若是String、Collection、Map、Array等類型,則當其長度或大小大于0返回true否則返回false,若是Iterator則當迭代器有下一個元素返回true否則返回false;其他非null實例都返回true。
在 #if 和 #end 的內容是否會輸出,由foo是否為true決定。這里,如果foo為true,輸出將是:Tiny!如果foo 為null或false,將不會有任何輸出。
#elseif 或 #else 可以 #if 和組合使用。如果第一個表達式為true,將會不計算以后的流程,如下例假設foo 是15 而bar為6。
|
輸出將會是
|
其中#if指令及#end指令必須包含,#elseif及#else指令可以省略,#elseif可以多次出現,而#else最多只能出現一次。多個條件之間可以用&&、||等進行連接。有時候#else或#end會和后面的字符內容連起來,從而導致模板引擎無法正確識別,這時就需要用#{else}或#{end}方式,避免干擾。
13.3 關系和邏輯運算
==相等運算
Tiny模板語言使用==來做比較,如下例.:
|
浮點數比較,不推薦采用==方式進行比較,因為這樣會由于精度原因出現誤差,而導致看似相同的結果在執行equals的時候返回false。 |
注意:== 計算與Java中的 == 計算有些不同,不能用來測試對象是否相等(指向同一塊內存)。在相等運算時,Tiny模板引擎首先會判斷操作對象是否為null,若兩個操作數都為null,則判為相等,若兩操作數中僅有一個為null則判為不相等;若兩個操作數都是非null但類型相同,則調用其equals()方法。如果是不同的對象,會調用它們的toString()方法再調用兩個String的equals()結果來比較。 |
AND運算
|
僅當foo 和bar都為true時,#if()才會輸出中間內容.
OR 運算
|
foo或bar只要有一個為true就可以輸出。
NOT運算
NOT運算則只有一個操作參數或表達式 :
|
13.4 循環語句
13.4.1 for循環
|
#for表示對expression進行循環處理,當expression不可以循環時,執行#else指令部分的內容。雖然foreach也表示循環,但是為了通用建議使用#for.
|
其中expression必須是一個合法的Tiny Template表達式,具體參考表達式小節。
#end指令在使用的時候如果有歧義可以用#{end}代替。循環變量及循環狀態變量只在循環體內可以使用,循環體外則不可用。
|
在上述例子中,allProducts或是一個List、 Map或是?Array類型的容器集合,#for每一次循環都會將容器集合中的一個對象賦給暫存變量product(稱為循環變量),allProducts指定給變量 product 是一個引用到其中一個Java對象的引用。如果product確實是一個Java代碼中的Product類,它可以通過product.name訪問(或者Product.getName())。
我們假設?allProducts 是一個HashMap,您會發現要取出其中的東西是多么的簡單:
|
Tiny模板引擎對于表達式進行了多種強力支持,不僅僅只有集合類型才可以參與運算,它的執行規則如下:
|
循環狀態變量
每個#for語句,會在循環體內產生兩個變量,一個是變量本身,一個是變量名+“For”,比如:
|
例如上面的例子中,在循環體內可以有兩個變量可以訪問一個是“num”,一個是"numFor"。其中numFor是其狀態變量,用于查看for循環中的一些內部狀態,下面對numFor屬性進行詳細說明:
- numFor.index 可用于內部循環計數,從 1 開始計數。
- numFor.size 獲取循環總數。如果對 Iterator 進行循環,或者對非 Collection 的 Iterable 進行循環,則返回 -1。
- numFor.first 是否為第一個元素。
- ?numFor.last 是否為最后一個元素。
- numFor.odd 是否為第奇數個元素。
- ?numFor.even 是否為第偶數個元素。
循環中斷:#break
循環中斷語句只能用在循環體內,用于表示跳出當前循環體。
|
其中expression必須是一個合法的TinyTemplate表達式,具體參考表達式小節。
|
上面的例子表示當num的值為2的時候,跳出循環體。
它等價于:
|
可以看出第一種寫法更方便。
#break只能跳出一層循環,不能跳出多層循環。#break只能放在循環體中,放在循環體外,會導致運行異常。 |
循環繼續:# continue
循環繼續語句,只能用在循環體內,表示不再執行下面的內容,繼續下一次循環。
|
其中expression必須是一個合法的Tiny Template表達式,具體參考表達式小節。
|
表示當num的值為2的時候,執行下一次循環。
它等價于:
|
可以看出上面的寫法更方便。
#continue只能繼續當前循環,不能繼續外層循環。#continue只能放在循環體中,放在循環體外,會導致運行異常。 |
13.4.2 while循環
|
此指令表示對判斷expression進行循環處理,當expression運算結果為false時結束循環。其中expression必須是一個合法的TinyTemplate表達式,具體參考表達式小節。
while循環指令是模板引擎2.0.10新增加的指令,更早的版本是不支持的。 |
下面是具體使用例子。
|
Tiny模板引擎中的循環語句,expression可以支持任意的表達式。
13.5 模板嵌套語句#include
|
#include內的這個表達式應該是一個字符串,用于指定要嵌套的子模板的路徑。它后可以跟參數,也可以不跟參數,如果跟參數的話,只能跟一個map類型的值。
示例
|
子模板可以訪問所有祖先模板中的變量。出于封裝性方面的考慮,在Tiny模板語言中子模板不能修改父模板中變量的值,從而避免不可預知的問題。
13.6 宏定義語句#macro
在Tiny模板引擎中,宏是一個非常強大靈活的東西,使用它可以避免在模板中編寫重復的代碼,也可方便一些具體業務的開發。
|
宏的名字和變量的名字必須符合Tiny變量的定義規范,宏的參數的個數可以為0~N個。宏定義的參數可以設置默認值,參數分隔可以采用英文逗號或者空格。#bodyContent表示中間可以包含任意的符合Tiny模板規范的內容,#bodyContent也可以不存在,因此對應了不同的調用方式。
在Tiny模板語言中宏的調用方式有兩種,一種是單行調用方式,格式如下:
|
另外一種是帶內容調用方式,格式如下:
|
參數支持按順序賦值方式,也支持命名賦值(varName=值)方式。參數分隔可以采用英文逗號或者空格。
|
例如在模板中定義如下宏:
|
調用方式:
|
運行結果:
|
為了進一步說明宏定義,請看下面的進階示例
|
調用方式:
|
運行結果:
|
自定義宏macro的訪問有兩種方式:一種是包含內容的,一種是不包含內容的。 |
如果參數變量與外部變量的名稱完全相同,這個變量可以不在調用時傳遞,Tiny模板引擎會自動讀取外部變量對應的值。通過命名傳值可以避免復雜的傳值指令及不必再費心考慮參數順序。
另外宏的定義支持嵌套定義,也就是說支持下面的形式:
|
它等價于下面的方式:
|
考慮到代碼的易讀性,建議還是采用第二種的定義方式。
在Velocity中定義宏的時候是不可以調用帶內容的宏的,而在強大的Tiny模板引擎中,則可以無限定義,強力支持。
|
13.7 宏引入語句#import
如果項目中存在同名宏,那么就會涉及加載的選擇問題。#import指令可以確定引入宏的執行順序,從而解決宏沖突的問題。
|
這個表達式的執行結果應該是一個字符串,其標示了要引入的宏的路徑。
|
13.8?布局重寫語句#layout #@layout?
在使用Tiny模板語言開發的Web項目中如果定義布局文件(*.layout)和頁面文件(*.page)就會遇到如下需求:針對特定頁面展示不同的布局樣式,目前有兩種實現方式:
|
|
#layout指令用于布局文件(*.layout),定義布局文件的名稱,制定通用的布局格式。
|
#@layout 指令用于頁面文件(*.page),如果layoutName的布局存在,則模板引擎在渲染布局時使用用戶在#@layout 指令里定義的布局覆蓋原有布局。
layout指令就是為實現布局文件的特殊渲染而設計的,以下是簡單示例,方便大家理解:
首先,創建布局文件default.layout。
|
上述例子中,我們定義了名為weblayout的布局樣式。接下來就是定義頁面文件a.page。
|
在模板中weblayout的布局樣式被用戶自定義的樣式給取代,模板渲染的結果如下:
|
我們再嘗試修改a.page,重寫一個不存在的布局樣式weblayout2.
|
渲染的效果如下:
|
13.9 停止執行#stop
?#stop 指令用來指示在模板的某處直接結束當前處理,終止模板的渲染,引擎停止解析。
|
當模板中調用#stop時無條件直接終止模板渲染。Tiny模板引擎還支持帶條件執行終止模板渲染,請看下面的例子:
|
上述例子表示當num==2時執行#stop終止模板渲染,它等價于:
|
?可以看出上面的寫法更方便。
13.10 返回指令#return
返回指令,停止某個宏的后續邏輯的渲染,類似Java方法中的return指令;如果用戶在page頁面使用該指令,會影響整個頁面的渲染。
|
在page頁面中使用return指令,可能會導致以后頁面停止渲染,用戶請慎用! |
return指令的作用與stop指令相同,部分場合可以相互替換,但是還是存在以下差異:
(1)return是指退出當前執行場景,如宏或模板。
(2)stop是直接終止模板引擎的繼續渲染,僅輸出已經渲染內容。
13.11 行結束指令
|
表示顯式輸出一個“\r\t”。
在Tiny模板引擎中,默認會把文本輸出內容進行trim操作,因此,默認是沒有回車換行符的。因此,如果想額外增加一個回車換行符,就需要增加#eol指令。但在HTML頁面中并不是<Br>。
14 系統內置函數
系統內嵌函數是指在模板引擎中默認就會注冊的函數,直接可以拿來使用的函數。
14.1 讀取文本資源函數read,readContent
讀取文本資源函數(read,readContent) ,用于讀取指定路徑的文本資源,并返回指定結果。如果讀取的是模板文件,得到的將是未經渲染的文本內容。
|
函數調用后的返回值是加載文本資源的字符串。
14.2?解析模板parse?
?解析模板可以用內置函數parse引入一個包含TTL的模板文件,Tiny模板引擎把解析這個文件的結果作為函數返回值。
|
?與 #include 指令不同,引入的模板經過內置函數parse處理后可以得到一個變量引用,方便模板中其他地方再引用。
14.3 格式化函數fmt,format,formatter
格式化函數(fmt,format,formatter),用于對數據進行格式化,并返回執行結果。該類函數的底層實現是調用了java.util.Formatter實現的,因此具體如何填寫格式化串可以參考java.util.Formatter用法。
|
14.4 宏調用方法call,callMacro
宏調用方法(call,callMacro),用于執行一個宏,并把執行完成的結果作為字符串返回。call函數的返回值為宏的運行結果。call有類似macro語法,也是支持單行調用和多行帶內容調用。
單行調用:
|
?多行帶內容調用,需要結束標識。
|
因此,以下三種方式是等價的:
|
14.5 實例判斷函數is,instanceOf,instance
|
類實例判斷函數會根據傳入對象判斷是否為指定類的實例,返回值為true或者false。
|
14.6 求值函數eval,evaluate
|
求值 函數(eval,evaluate),用于執行一段宏代碼,執行后的結果為字符串
|
14.7 隨機數函數rand,random
隨機數函數用于生成指定類型的隨機數。目前支持int、long、float、double和uuid五種類型。注意該函數是在模板引擎2.0.16版本之后提供的,更早版本是不支持這個函數的
|
返回值:隨機數,如果不指定類型,默認返回int類型;如果指定類型,返回指定類型的隨機數
|
14.8 ?類型轉換函數
Tiny模板語言中有可能經常會遇到String類型的引用轉成其他基本類型(Integer、Double、Float、Long、Bool)的引用,Tiny模板引擎為您提供了一系列函數,請看下面的示例。
|
執行結果如下:
|
14.9 日期格式轉換formatDate
為了使Java的Date類型在模板語言能按照您的指定格式輸出,Tiny模板引擎內置了formatDate/formatdate(date,formatPatten)。formatDate系統函數的第一個參數是Date類型,第二參數是格式化模式。另外Tiny模板引擎還提供一個獲取當前系統時間Date對象的系統函數now()。
|
上面的例子模板語言解析得到當前系統時間,并按照格式“?yyyy年MM月dd日 HH:mm:ss”輸出。
15 其它特性和細節
15.1 數學計算
Tiny模板語言自帶一些數學函數,可以用#set指令在模板中使用。下面是四則運算的例子:
|
兩個整數間的除法運算的結果仍是整數,小數部分會被剔除。余數可以用取余運算符(%)得到,例如:
|
15.2 范圍操作符
范圍操作符可以與#set和#foreach語句一起使用。用它來生成包含整數的數組非常方便:
|
其中n和m必須是整數。m可以大于n也可以小于n。如果m小于n,整數序列是遞減的。
例子一:
|
例子二:
|
例子三:
|
例子四:
|
例子一結果:
|
例子二結果:
|
例子三結果:
|
例子四結果:
|
15.3 連接字符串
很簡單,看例子就是 :
|
上面模板的輸出將是
|
或者:
|
它們都是同樣的輸出,最后一個例子如下:
|
輸出是:
|
除此之外,您還可以通過系統函數fmt輸出拼裝字符串。
|
上面模板的輸出將是
|
15.4 文本內容轉義輸出
如果有些內容本來是文本內容,但是由于與模板引擎的指令或表達式產生沖突,此時可以采用轉義方式進行處理。
比如:如果一個變量email己定義了(比如它的值是 foo),而這里您不是要讀取變量email的值,想直接輸出${email}這樣一個字符串,就需要使用轉義字符”\”。
|
上面的模板在Web頁面上的輸出將是:
|
另外,還可以使用#[[...]]#不解析文本塊的所有內容。例如:
|
它的運行結果為:
|
非模板引擎支持的類似的指令,比如:#aabbff,不會被識別成指令,而會原樣輸出,可以不進行轉義。"\" 后面跟的字符不是 "#" 和"$",也不需要進行轉義,直接輸出。