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