FreeMarker的指令的文件就稱為模板(Template)。
模板設計者不關心數據從那兒來,只知道使用已經建立的數據模型。
數據模型由程序員編程來創建,向模板提供變化的信息,這些信息來自于數據庫、文件,甚至于在程序中直接生成。
數據類型:
一、基本:
1、scalars:存儲單值
字符串:簡單文本由單或雙引號括起來。
數字:直接使用數值。
日期:通常從數據模型獲得
布爾值:true或false,通常在<#if …>標記中使用
2、hashes:充當其它對象的容器,每個都關聯一個唯一的查詢名字
具有一個唯一的查詢名字和他包含的每個變量相關聯。
3、sequences:充當其它對象的容器,按次序訪問
使用數字和他包含的每個變量相關聯。索引值從0開始。
4、集合變量:
除了無法訪問它的大小和不能使用索引來獲得它的子變量:集合可以看作只能由<#list...>指令使用的受限sequences。
5、方法:通過傳遞的參數進行計算,以新對象返回結果
方法變量通常是基于給出的參數計算值在數據模型中定義。
6、用戶自定義FTL指令:宏和變換器
7、節點
節點變量表示為樹型結構中的一個節點,通常在XML處理中使用。
模板:
使用FTL(freeMarker模板語言)編寫
組成部分
一、整體結構
1、注釋:<#--注釋內容-->,不會輸出。
2、文本:直接輸出。
3、interpolation:由 ${var} 或 #{var} 限定,由計算值代替輸出。
4、FTL標記
二、指令:
freemarker指令有兩種:
1、預定義指令:引用方式為<#指令名稱>
2、用戶定義指令:引用方式為<@指令名稱>,引用用戶定義指令時須將#換為@。
注意:如果使用不存在的指令,FreeMarker不會使用模板輸出,而是產生一個錯誤消息。
freemarker指令由FTL標記來引用,FTL標記和HTML標記類似,名字前加#來加以區分。如HTML標記的形式為<h1></h1>則FTL標記的形式是<#list></#list>(此處h1標記和list指令沒有任何功能上的對應關系,只是做為說明使用一下)。
有三種FTL標記:
1)、開始標記:<#指令名稱>
2)、結束標記:</#指令名稱>
3)、空標記:<#指令名稱/>
注意:
1) FTL會忽略標記之中的空格,但是,<#和指令 與 </#和指令 之間不能有空格。
2) FTL標記不能夠交叉,必須合理嵌套。每個開始標記對應一個結束標記,層層嵌套。 如:
<#list>
<li>
${數據}
<#if 變量>
<p>game over!</p>
</#if>
</li>
</#list>
注意事項:
1)、FTL對大小寫敏感。所以使用的標記及interpolation要注意大小寫。name與NAME就是不同的對象。<#list>是正確的標記,而<#List>則不是。
2)、interpolation只能在文本部分使用,不能位于FTL標記內。如<#if ${var}>是錯誤的,正確的方法是:<#if var>,而且此處var必須為布爾值。
3)、FTL標記不能位于另一個FTL標記內部,注釋例外。注釋可以位于標記及interpolation內部。
三、表達式
1、直接指定值:
1-1、字符串:
由雙引號或單引號括起來的字符串,其中的特殊字符(如' " \等)需要轉義。
1-2、raw字符串:
有一種特殊的字符串稱為raw字符串,被認為是純文本,其中的\和{等不具有特殊含義,該類字符串在引號前面加r,下面是一個例子:
${r"/${data}"year""}屏幕輸出結果為:/${data}"year"
轉義 含義
序列
\" 雙引號(u0022)
\' 單引號(u0027)
\\ 反斜杠(u005C)
\n 換行(u000A)
\r Return (u000D)
\t Tab (u0009)
\b Backspace (u0008)
\f Form feed (u000C)
\l <
\g >
\a &
\{ {
\xCode 4位16進制Unicode代碼
1-3、數字:直接輸入,不需要引號
1)、精度數字使用“.”分隔,不能使用分組符號
2)、目前版本不支持科學計數法,所以“1E3”是錯誤的
3)、不能省略小數點前面的0,所以“.5”是錯誤的
4)、數字8、+8、08和8.00都是相同的
1-4、布爾值:true和false,不使用引號
1-5、序列:由逗號分隔的子變量列表,由[]方括號限定。
1)、子變量列表可以是表達式
2)、可以使用數字范圍定義數字序列,<b>不需要方括號限定</b>,例如2..5等同于[2, 3, 4, 5],但是更有效率,可以定義反遞增范圍如:5..2。
1-6、散列(hash)
1)、由逗號分隔的鍵/值列表,由{}大括號限定,鍵和值之間用冒號分隔,如:{"key1":valu1,"key2":"character string"....}
2)、鍵和值都是表達式,但是鍵必須是字符串。
2、獲取變量:
2-1、頂層變量:${變量名}
變量名只能是字母、數字、下劃線、$、#、@ 的組合,且不能以數字開頭。
2-2、散列:有兩種方法
1)、點語法:變量名字和頂層變量的名字受同樣的限制
2)、方括號語法:變量名字無限制,可以是任意的表達式的結果
book.author.name
book.author.["name"]
book["author"].name
book["author"]["name"]
以上是等價的。
2-3、序列:使用散列的方括號語法獲取變量,方括號中的表達式結果必須為數字。注意:第一個項目的索引為0。可以使用
[startindex..endindex]語法獲取序列片段。
2-4、特殊變量:FreeMarker內定義變量,使用.variablename語法訪問。
3、字符串操作
3-1、interpolation:使用${}或#{}在文本部分插入表達式的值,例如:
${"hello${username}!"}
${"${username}${username}${username}"}
也可以使用+來獲得同樣的結果:
${"hello"+username+"!"}
${username+username+username}
注意:${}只能用于文本部分而不能出現于標記內。
<#if ${user.login}>或<#if "${user.login}">都是錯誤的;
<#if user.login>是正確的。
本例中user.login的值必須是布爾類型。
3-2、子串:
舉例說明:假如user的值為"Big Joe"
${user[0]}${user[4]}結果是:BJ
${user[1..4]}結果是:ig J
4、序列操作
4-1、連接操作:可以使用+來操作,例如:
["title","author"]+["month","day"]
5、散列操作
5-1、連接操作:可以使用+來操作,如果有相同的KEY,則右邊的值會替代左邊的值,例如:
{"title":散列,"author":"emma"}+{"month":5,"day":5}+{"month":6}結果month的值就是6。
6、算術運算
6-1、操作符:+、-、*、/、%
除+號以外的其他操作符兩邊的數據,必須都是數字類型。
如果+號操作符一邊有一個字符型數據,會自動將另一邊的數據轉換為字符型數據,運算結果為字符型數據。
6-2、比較操作符:
1)、=
2)、==
3)、!=
4)、<
5)、<=
6)、>
7)、>=
1-3的操作符,兩邊的數據類型必須相同,否則會產生錯誤
4-7的操作符,對于日期和數字可以使用,字符串不可以使用。
注意:
1)、FreeMarker是精確比較,所以"x" "x " "X"是不等的。
2)、因為<和>對FTL來說是開始和結束標記,所以,可以用兩種方法來避免這種情況:
一種是使用括號<#if (a<b)>
另一是使用替代輸出,對應如下:
< lt
<= lte
> gt
>= gte
6-3、邏輯操作符:只能用于布爾值,否則會出現錯誤。
&&(and)與運算
||(or)或運算
!(not)非運算
6-4、內建函數:使用方法類似于訪問散列的子變量,只是使用?代替.例如:${test?upper_case?html}
常用的內建函數列舉如下:
1)、字符串使用:
html:對字符串進行HTML編碼
cap_first:字符串第一個字母大寫
lower_first:字符串第一個字母小寫
upper_case:將字符串轉換成大寫
trim:去年字符前后的空白字符
2)、序列使用:
size:獲得序列中元素的數目
3)、數字使用:
int:取得數字的整數部分
7、操作符的優先順序:
后綴:[subbarName][subStringRange].(mathodParams)
一元:+expr、-expr、! (not)
內建:?
乘法:*、/、%
加法:+、-
關系:<、<=、>、>= (lt、lte、gt、gte)
相等:=、==、!=
邏輯與:&& (and)
邏輯或:|| (or)
數字范圍:..
四、interpolation
inperpolation只能用于文本,有兩種類型:通用interpolation及數字interpolation
1、通用interpolation
如${expr}
1-1、插入字符串值:直接輸出表達式結果。
1-2、插入數字值:根據缺省格式(由setting指令設置)將表達式結果轉換成文本輸出;可以使用內建函數string來格式化單個interpolation
如:
<#setting number_format="currency" />
<#assign answer=42 />
${answer} <#-- ¥42.00 -->
${answer?string} <#-- ¥42.00 -->
${answer?string.number} <#-- 42 -->
${answer?string.currency} <#-- ¥42.00 -->
${answer?string.percent} <#-- 42,00% -->
1-3、插入日期值:根據缺省格式(由setting指令設置)將表達式結果轉換成文本輸出;可以使用內建函數string來格式化單個interpolation
如:
${lastupdata?string("yyyy-MM-dd HH:mm:ss zzzz")} <#-- 2003-04-08 21:24:44 Pacific Daylight Time -->
${lastupdata?string("EEE,MMM d, ''yy")} <#-- tue,Apr 8, '03 -->
${lastupdata?string("EEEE,MMMM dd, yyyy,hh:mm:ss a '('zzz')'")} <#-- Tuesday,April 08, 2003, 09:24:44 PM (PDT)-->
1-4、插入布爾值:根據缺省格式(由setting指令設置)將表達式結果轉換成文本輸出;可以使用內建函數string來格式化單個interpolation
如:
<#assign foo=ture />
${foo?string("yes","no")} <#-- yes -->
2、數字interpolation:
有兩種形式:
1)、#{expr}
2)、#{expr;format}:format可以用來格式化數字,format可以是如下:
mX:小數部分最小X位
MX:小數部分最大X位
例如:
<#assign x=2.582 />
<#assign y=4 />
#{x;M2} <#-- 2.58 -->
#{y;M2} <#-- 4 -->
#{x;m1} <#-- 2.582 -->
#{y;m1} <#-- 4.0 -->
#{x;m1M2} <#-- 2.58 -->
#{y;m1M2} <#-- 4.0 -->
雜項
一、用戶定義指令
宏和變換器變量是兩種不同類型的用戶自定義指令,他們的區別是:
宏可以在模板中用macro指令來定義
變換器是在模板外由程序定義
1、宏:和某個變量關聯的模板片段,以便在模板中通過用戶自定義指令使用該變量
1-1、基本用法:
例如:
<#macro greet>
<font size="+2"> Hello JOE!</font>
</#macro>
使用時:
<@greet></@greet>
如果沒有體內容也可以用
<@greet />
1-2、變量:
1)、可以在宏定義之后定義參數,宏參數是局部變量,只在宏定義中有效。如:
<#macro greet person>
<font size="+2"> Hello ${person}!</font>
</#macro>
使用時:
<@greet person="emma"> and <@greet person="LEO">
輸出為:
<font size="+2"> Hello emma!</font>
<font size="+2"> Hello LEO!</font>
注意:宏的參數是FTL表達式,所以,person=emma和上面的例子中具有不同的意義,這意味著將變量emma的值傳給person,這個值可能是任意一種數據類型,甚至是一個復雜的表達式。
宏可以有多個參數,使用時參數的次序是無關的,但是只能使用宏中定義的參數,并且對所有參數賦值。如:
<#macro greet person color>
<font size="+2" color="${color}"> Hello ${person}!</font>
</#macro>
使用時:
<@greet color="black" person="emma" />正確
<@greet person="emma" />錯誤,color沒有賦值,此時,如果在定義宏時為color定義缺省值<#macro greet person color="black">這樣的話,這個使用方法就是正確的。
<@greet color="black" person="emma" bgcolor="yellow" />錯誤,宏greet定義中未指定bgcolor這個參數
2、嵌套內容:
2-1、自定義指令可以有嵌套內容,使用<#nested>指令,執行自定義指令開始和結束標記之間的模板片段。例如:
<#macro greet>
<p>
<#nested>
</p>
</#macro>
<@greet>hello Emma!</@greet>
輸出為
<p>hello Emma!</p>
2-2、<#nested>指令可以被多次調用,例如
<#macro greet>
<p>
<#nested>
<#nested>
<#nested>
<#nested>
</p>
</#macro>
<@greet>hello Emma!</@greet>
輸出為
<p>
hello Emma!
hello Emma!
hello Emma!
hello Emma!
</p>
2-3、嵌套的內容可以是有效的FTL,例如:
<#macro welcome>
<p>
<#nested>
</p>
</#macro>
<#macro greet person color="black">
<font size="+2" color="${color}"> Hello ${person}!</font>
</#macro>
<@welcome>
<@greet person="Emma" color="red" />
<@greet person="Andrew" />
<@greet person="Peter" />
</@welcome>
輸出為:
<p>
<font size="+2" color="red"> Hello Emma!</font>
<font size="+2" color="black"> Hello Andrew!</font>
<font size="+2" color="black"> Hello Peter!</font>
</p>
2-4、宏定義中的局部變量對嵌套內容是不可見的,例如:
<#macro repeat count>
<#local y="test" />
<#list 1..count as x>
${y}${count}/${x}:<#nested />
</#list>
</#macro>
<@repeat count=3>
${y?default("?")}
${x?default("?")}
${count?default("?")}
</@repeat>
輸出結果為
test 3/1:???
test 3/2:???
test 3/3:???
2-5、在宏定義中使用循環變量,通常用來重復嵌套內容,基本用法為:作為nested指令的參數,傳遞循環變量的實際值,而在調用自定義指令時,在標記的參數后面指定循環變量的名字。
例如:
<#macro repeat count>
<#list 1..count as x>
<#nested x,x/2,x==count />
</#list>
</#macro>
<@repeat count=4;c,halfc,last>
${c}. ${halfc}
<#if last>
last!
</#if>
</@repeat>
輸出結果是
1. 0.5
2. 1
3. 1.5
4. 2last!
注意:指定循環變量的數目和用戶定義指令開始標記指定的不同不會有問題
調用時,少指定循環變量,多指定的值會不見
調用時,多指定循環變量,多余的循環變量不會被創建
二、在模板中定義變量
1、在模板中定義的變量有三種類型
1-1、plain變量:可以在模板的任何地方訪問,包括使用include指令插入的模板,使用assign指令創建和替換。
1-2、局部變量:在宏定義體中有效,使用local指令創建和替換。
1-3、循環變量:只能存在于指令的嵌套內容,由指令(如list)自動創建。
注意:
1)、宏的參數是局部變量,不是循環變量。
2)、局部變量隱藏同名的plain變量
3)、循環變量隱藏同名的plain變量和局部變量。
例如:
<#assign x="plain">
1. ${x} <#-- plain -->
<@test />
6. ${x}
<#list ["loop"] as x>
7. ${x} <#-- loop -->
<#assign x="plain2">
8. ${x} <#-- loop -->
</#list>
9. ${x} <#-- plain2 -->
<#macro test>
2. ${x} <#-- plain -->
<#local x="local">
3. ${x} <#-- local -->
<#list ["loop"] as x>
4. ${x} <#-- loop -->
</#list>
5. ${x} <#-- local -->
</#macro>
4)、內部循環變量隱藏同名的外部循環變量
<#list ["loop1"] as x>
${x} <#-- loop1 -->
<#list ["loop2"] as x>
${x} <#-- loop2 -->
<#list ["loop3"] as x>
${x} <#-- loop3 -->
</#list>
${x} <#-- loop2 -->
</#list>
${x} <#-- loop1 -->
</#list>
5)、模板中的變量會隱藏數據模型中的同名變量,如果需訪問數據模型中的變量,使用特殊變量global。
例如:
假設數據模型中的user值為Emma
<#assign user="Man">
${user} <#-- Man -->
${.global.user} <#-- Emma -->