簡(jiǎn)介
FreeMarker的模板文件并不比HTML頁(yè)面復(fù)雜多少,FreeMarker模板文件主要由如下4個(gè)部分組成:
1)文本:直接輸出的部分
2)注釋:<#-- ... -->格式部分,不會(huì)輸出
3)插值:即${...}或#{...}格式的部分,將使用數(shù)據(jù)模型中的部分替代輸出
4)FTL指令:FreeMarker指定,和HTML標(biāo)記類(lèi)似,名字前加#予以區(qū)分,不會(huì)
下面是一個(gè)給出一個(gè)簡(jiǎn)單的FreeMarker模板的例子,簡(jiǎn)單介紹以上所說(shuō)的4個(gè)部分
<html><br>
<head><br>
<title>Welcome!</title><br>
</head><br>
<body><br>
<#-- 注釋部分 --><br>
<#-- 下面使用插值 -->
<h1>Welcome ${user} !</h1><br>
<p>We have these animals:<br>
<u1><br>
<#-- 使用FTL指令 -->
<#list animals as being><br>
<li>${being.name} for ${being.price} Euros<br>
<#list><br>
<u1><br>
</body><br>
</html>
1.FTL指令規(guī)則
在FreeMarker中,使用FTL標(biāo)簽來(lái)使用指令,FreeMarker有3種FTL標(biāo)簽,這和HTML標(biāo)簽是完全類(lèi)似的.
1,開(kāi)始標(biāo)簽:<#directivename parameter>
2,結(jié)束標(biāo)簽:</#directivename>
3,空標(biāo)簽:<#directivename parameter/>
實(shí)際上,使用標(biāo)簽時(shí)前面的符號(hào)#也可能變成@,如果該指令是一個(gè)用戶(hù)指令而不是系統(tǒng)內(nèi)建指令時(shí),應(yīng)將#符號(hào)改成@符號(hào).
使用FTL標(biāo)簽時(shí), 應(yīng)該有正確的嵌套,而不是交叉使用,這和XML標(biāo)簽的用法完全一樣.如果全用不存在的指令,FreeMarker不會(huì)使用模板輸出,而是產(chǎn)生一個(gè)錯(cuò)誤消息.FreeMarker會(huì)忽略FTL標(biāo)簽中的空白字符.值得注意的是< , /> 和指令之間不允許有空白字符.
2 插值規(guī)則
FreeMarker的插值有如下兩種類(lèi)型:1,通用插值${expr};2,數(shù)字格式化插值:#{expr}或#{expr;format}
2.1 通用插值
對(duì)于通用插值,又可以分為以下4種情況:
1,插值結(jié)果為字符串值:直接輸出表達(dá)式結(jié)果
2,插值結(jié)果為數(shù)字值:根據(jù)默認(rèn)格式(由#setting指令設(shè)置)將表達(dá)式結(jié)果轉(zhuǎn)換成文本輸出.可以使用內(nèi)建的字符串函數(shù)格式化單個(gè)插值,如下面的例子:
<#settion number_format="currency"/>
<#assign answer=42/>
${answer}
${answer?string} <#-- the same as ${answer} -->
${answer?string.number}
${answer?string.currency}
${answer?string.percent}
${answer}
輸出結(jié)果是:
$42.00
$42.00
42
$42.00
4,200%
3,插值結(jié)果為日期值:根據(jù)默認(rèn)格式(由#setting指令設(shè)置)將表達(dá)式結(jié)果轉(zhuǎn)換成文本輸出.可以使用內(nèi)建的字符串函數(shù)格式化單個(gè)插值,如下面的例子:
${lastUpdated?string("yyyy-MM-dd HH:mm:ss zzzz")}
${lastUpdated?string("EEE, MMM d, ''yy")}
${lastUpdated?string("EEEE, MMMM dd, yyyy, hh:mm:ss a '('zzz')'")}
輸出結(jié)果是:
2008-04-08 08:08:08 Pacific Daylight Time
Tue, Apr 8, '03
Tuesday, April 08, 2003, 08:08:08 PM (PDT)
4,插值結(jié)果為布爾值:根據(jù)默認(rèn)格式(由#setting指令設(shè)置)將表達(dá)式結(jié)果轉(zhuǎn)換成文本輸出.可以使用內(nèi)建的字符串函數(shù)格式化單個(gè)插值,如下面的例子:
<#assign foo=true/>
${foo?string("yes", "no")}
輸出結(jié)果是:
yes
2.2 數(shù)字格式化插值
數(shù)字格式化插值可采用#{expr;format}形式來(lái)格式化數(shù)字,其中format可以是:
mX:小數(shù)部分最小X位
MX:小數(shù)部分最大X位
如下面的例子:
<#assign x=2.582/>
<#assign y=4/>
#{x; M2} <#-- 輸出2.58 -->
#{y; M2} <#-- 輸出4 -->
#{x; m2} <#-- 輸出2.6 -->
#{y; m2} <#-- 輸出4.0 -->
#{x; m1M2} <#-- 輸出2.58 -->
#{x; m1M2} <#-- 輸出4.0 -->
3 表達(dá)式
表達(dá)式是FreeMarker模板的核心功能,表達(dá)式放置在插值語(yǔ)法${}之中時(shí),表明需要輸出表達(dá)式的值;表達(dá)式語(yǔ)法也可與FreeMarker 標(biāo)簽結(jié)合,用于控制輸出.實(shí)際上FreeMarker的表達(dá)式功能非常強(qiáng)大,它不僅支持直接指定值,輸出變量值,也支持字符串格式化輸出和集合訪問(wèn)等功能.
3.1 直接指定值
使用直接指定值語(yǔ)法讓FreeMarker直接輸出插值中的值,而不是輸出變量值.直接指定值可以是字符串,數(shù)值,布爾值,集合和MAP對(duì)象.
1)字符串
直接指定字符串值使用單引號(hào)或雙引號(hào)限定,如果字符串值中包含特殊字符需要轉(zhuǎn)義,看下面的例子:
${"我的文件保存在C:\\盤(pán)"}
${'我名字是\"annlee\"'}
輸出結(jié)果是:
我的文件保存在C:\盤(pán)
我名字是"annlee"
FreeMarker支持如下轉(zhuǎn)義字符:
\";雙引號(hào)(u0022)
\';單引號(hào)(u0027)
\\;反斜杠(u005C)
\n;換行(u000A)
\r;回車(chē)(u000D)
\t;Tab(u0009)
\b;退格鍵(u0008)
\f;Form feed(u000C)
\l;<
\g;>
\a;&
\{;{
\xCode;
直接通過(guò)4位的16進(jìn)制數(shù)來(lái)指定Unicode碼,輸出該unicode碼對(duì)應(yīng)的字符.
如果某段文本中包含大量的特殊符號(hào),FreeMarker提供了另一種特殊格式:可以在指定字符串內(nèi)容的引號(hào)前增加r標(biāo)記,在r標(biāo)記后的文件將會(huì)直接輸出.看如下代碼:
${r"${foo}"}
${r"C:\foo\bar"}
輸出結(jié)果是:
${foo}
C:\foo\bar
2)數(shù)值
表達(dá)式中的數(shù)值直接輸出,不需要引號(hào).小數(shù)點(diǎn)使用"."分隔,不能使用分組","符號(hào).FreeMarker目前還不支持科學(xué)計(jì)數(shù)法,所以"1E3"是錯(cuò)誤的.在FreeMarker表達(dá)式中使用數(shù)值需要注意以下幾點(diǎn):
1,數(shù)值不能省略小數(shù)點(diǎn)前面的0,所以".5"是錯(cuò)誤的寫(xiě)法
2,數(shù)值8 , +8 , 8.00都是相同的
3)布爾值
直接使用true和false,不使用引號(hào).
4)集合
集合以方括號(hào)包括,各集合元素之間以英文逗號(hào)","分隔,看如下的例子:
<#list ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天"] as x>
${x}
</#list>
輸出結(jié)果是:
星期一
星期二
星期三
星期四
星期五
星期六
星期天
除此之外,集合元素也可以是表達(dá)式,例子如下:
[2 + 2, [1, 2, 3, 4], "whatnot"]
還可以使用數(shù)字范圍定義數(shù)字集合,如2..5等同于[2, 3, 4, 5],但是更有效率.注意,使用數(shù)字范圍來(lái)定義集合時(shí)無(wú)需使用方括號(hào),數(shù)字范圍也支持反遞增的數(shù)字范圍,如5..2
5)Map對(duì)象
Map對(duì)象使用花括號(hào)包括,Map中的key-value對(duì)之間以英文冒號(hào)":"分隔,多組key-value對(duì)之間以英文逗號(hào)","分隔.下面是一個(gè)例子:
{"語(yǔ)文":78, "數(shù)學(xué)":80}
Map對(duì)象的key和value都是表達(dá)式,但是key必須是字符串
3.2 輸出變量值
FreeMarker的表達(dá)式輸出變量時(shí),這些變量可以是頂層變量,也可以是Map對(duì)象中的變量,還可以是集合中的變量,并可以使用點(diǎn)(.)語(yǔ)法來(lái)訪問(wèn)Java對(duì)象的屬性.下面分別討論這些情況
1)頂層變量
所謂頂層變量就是直接放在數(shù)據(jù)模型中的值,例如有如下數(shù)據(jù)模型:
Map root = new HashMap(); //創(chuàng)建數(shù)據(jù)模型
root.put("name","annlee"); //name是一個(gè)頂層變量
對(duì)于頂層變量,直接使用${variableName}
來(lái)輸出變量值,變量名只能是字母,數(shù)字,下劃線,$,@
和#
的組合,且不能以數(shù)字開(kāi)頭號(hào).為了輸出上面的name的值,可以使用如下語(yǔ)法:
${name}
2)輸出集合元素
如果需要輸出集合元素,則可以根據(jù)集合元素的索引來(lái)輸出集合元素,集合元素的索引以方括號(hào)指定.假設(shè)有索引:
["星期一","星期二","星期三","星期四","星期五","星期六","星期天"].該索引名為week,如果需要輸出星期三,則可以使用如下語(yǔ)法:
${week[2]} //輸出第三個(gè)集合元素
此外,FreeMarker還支持返回集合的子集合,如果需要返回集合的子集合,則可以使用如下語(yǔ)法:
week[3..5] //返回week集合的子集合,子集合中的元素是week集合中的第4-6個(gè)元素
3)輸出Map元素
這里的Map對(duì)象可以是直接HashMap的實(shí)例,甚至包括JavaBean實(shí)例,對(duì)于JavaBean實(shí)例而言,我們一樣可以把其當(dāng)成屬性為key,屬性值為value的Map實(shí)例.為了輸出Map元素的值,可以使用點(diǎn)語(yǔ)法或方括號(hào)語(yǔ)法.假如有下面的數(shù)據(jù)模型:
Map root = new HashMap();
Book book = new Book();
Author author = new Author();
author.setName("annlee");
author.setAddress("gz");
book.setName("struts2");
book.setAuthor(author);
root.put("info","struts");
root.put("book", book);
為了訪問(wèn)數(shù)據(jù)模型中名為struts2的書(shū)的作者的名字,可以使用如下語(yǔ)法:
book.author.name //全部使用點(diǎn)語(yǔ)法
book["author"].name
book.author["name"] //混合使用點(diǎn)語(yǔ)法和方括號(hào)語(yǔ)法
book["author"]["name"] //全部使用方括號(hào)語(yǔ)法
使用點(diǎn)語(yǔ)法時(shí),變量名字有頂層變量一樣的限制,但方括號(hào)語(yǔ)法沒(méi)有該限制,因?yàn)槊挚梢允侨我獗磉_(dá)式的結(jié)果.
3.3 字符串操作
FreeMarker的表達(dá)式對(duì)字符串操作非常靈活,可以將字符串常量和變量連接起來(lái),也可以返回字符串的子串等.
字符串連接有兩種語(yǔ)法:
1)使用${..}或#{..}在字符串常量部分插入表達(dá)式的值,從而完成字符串連接.
2)直接使用連接運(yùn)算符+來(lái)連接字符串
例如有如下數(shù)據(jù)模型:
Map root = new HashMap(); root.put("user","annlee");
下面將user變量和常量連接起來(lái):
${"hello, ${user}!"}
//使用第一種語(yǔ)法來(lái)連接
${"hello, " + user + "!"}
//使用+號(hào)來(lái)連接
上面的輸出字符串都是hello,annlee!,可以看出這兩種語(yǔ)法的效果完全一樣.
值得注意的是,${..}只能用于文本部分,不能用于表達(dá)式,下面的代碼是錯(cuò)誤的:
<#if ${isBig}>Wow!</#if>
<#if "${isBig}">Wow!</#if>
應(yīng)該寫(xiě)成:<#if isBig>Wow!</#if>
截取子串可以根據(jù)字符串的索引來(lái)進(jìn)行,截取子串時(shí)如果只指定了一個(gè)索引值,則用于取得字符串中指定索引所對(duì)應(yīng)的字符;如果指定兩個(gè)索引值,則返回兩個(gè)索引中間的字符串子串.假如有如下數(shù)據(jù)模型:
Map root = new HashMap(); root.put("book","struts2,freemarker");
可以通過(guò)如下語(yǔ)法來(lái)截取子串:
${book[0]}${book[4]} //結(jié)果是su
${book[1..4]} //結(jié)果是tru
3.4 集合連接運(yùn)算符
這里所說(shuō)的集合運(yùn)算符是將兩個(gè)集合連接成一個(gè)新的集合,連接集合的運(yùn)算符是+,看如下的例子:
<#list ["星期一","星期二","星期三"] + ["星期四","星期五","星期六","星期天"] as x>
${x}
</#list>
輸出結(jié)果是:星期一 星期二 星期三 星期四 星期五 星期六 星期天
3.5 Map連接運(yùn)算符
Map對(duì)象的連接運(yùn)算符也是將兩個(gè)Map對(duì)象連接成一個(gè)新的Map對(duì)象,Map對(duì)象的連接運(yùn)算符是+,如果兩個(gè)Map對(duì)象具有相同的key,則右邊的值替代左邊的值.看如下的例子:
<#assign scores = {"語(yǔ)文":86,"數(shù)學(xué)":78} + {"數(shù)學(xué)":87,"Java":93}>
語(yǔ)文成績(jī)是${scores.語(yǔ)文}
數(shù)學(xué)成績(jī)是${scores.數(shù)學(xué)}
Java成績(jī)是${scores.Java}
輸出結(jié)果是:
語(yǔ)文成績(jī)是86
數(shù)學(xué)成績(jī)是87
Java成績(jī)是93
3.6 算術(shù)運(yùn)算符
FreeMarker表達(dá)式中完全支持算術(shù)運(yùn)算,FreeMarker支持的算術(shù)運(yùn)算符包括:+, - , * , / , % 看如下的代碼:
<#assign x=5>
${ x * x - 100 }
${ x /2 }
${ 12 %10 }
輸出結(jié)果是:
-75 2.5 2
在表達(dá)式中使用算術(shù)運(yùn)算符時(shí)要注意以下幾點(diǎn):
1,運(yùn)算符兩邊的運(yùn)算數(shù)字必須是數(shù)字
2,使用+運(yùn)算符時(shí),如果一邊是數(shù)字,一邊是字符串,就會(huì)自動(dòng)將數(shù)字轉(zhuǎn)換為字符串再連接,如:${3 + "5"},結(jié)果是:35
使用內(nèi)建的int函數(shù)可對(duì)數(shù)值取整,如:
<#assign x=5>
${ (x/2)?int }
${ 1.1?int }
${ 1.999?int }
${ -1.1?int }
${ -1.999?int }
結(jié)果是:2 1 1 -1 -1
3.7 比較運(yùn)算符
表達(dá)式中支持的比較運(yùn)算符有如下幾個(gè):
1,=或者==:判斷兩個(gè)值是否相等.
2,!=:判斷兩個(gè)值是否不等.
3,>或者gt:判斷左邊值是否大于右邊值
4,>=或者gte:判斷左邊值是否大于等于右邊值
5,<或者lt:判斷左邊值是否小于右邊值
6,<=或者lte:判斷左邊值是否小于等于右邊值
注意:=和!=可以用于字符串,數(shù)值和日期來(lái)比較是否相等,但=和!=兩邊必須是相同類(lèi)型的值,否則會(huì)產(chǎn)生錯(cuò)誤,而且FreeMarker是精確比較,"x","x ","X"是不等的.其它的運(yùn)行符可以作用于數(shù)字和日期,但不能作用于字符串,大部分的時(shí)候,使用gt等字母運(yùn)算符代替>會(huì)有更好的效果,因?yàn)?FreeMarker會(huì)把>解釋成FTL標(biāo)簽的結(jié)束字符,當(dāng)然,也可以使用括號(hào)來(lái)避免這種情況,如:<#if (x>y)>
3.8 邏輯運(yùn)算符
邏輯運(yùn)算符有如下幾個(gè):
邏輯與:&&
邏輯或:||
邏輯非:!
邏輯運(yùn)算符只能作用于布爾值,否則將產(chǎn)生錯(cuò)誤
3.9 內(nèi)建函數(shù)
FreeMarker還提供了一些內(nèi)建函數(shù)來(lái)轉(zhuǎn)換輸出,可以在任何變量后緊跟?,?后緊跟內(nèi)建函數(shù),就可以通過(guò)內(nèi)建函數(shù)來(lái)輪換輸出變量.下面是常用的內(nèi)建的字符串函數(shù):
html:對(duì)字符串進(jìn)行HTML編碼
cap_first:使字符串第一個(gè)字母大寫(xiě)
lower_case:將字符串轉(zhuǎn)換成小寫(xiě)
upper_case:將字符串轉(zhuǎn)換成大寫(xiě)
trim:去掉字符串前后的空白字符
下面是集合的常用內(nèi)建函數(shù)
size:獲取序列中元素的個(gè)數(shù)
下面是數(shù)字值的常用內(nèi)建函數(shù)
int:取得數(shù)字的整數(shù)部分,結(jié)果帶符號(hào)
例如:
<#assign test="Tom & Jerry">
${test?html}
${test?upper_case?html}
結(jié)果是:Tom & Jerry TOM & JERRY
3.10 空值處理運(yùn)算符
FreeMarker對(duì)空值的處理非常嚴(yán)格,FreeMarker的變量必須有值,沒(méi)有被賦值的變量就會(huì)拋出異常,因?yàn)镕reeMarker未賦值的變量強(qiáng)制出錯(cuò)可以杜絕很多潛在的錯(cuò)誤,如缺失潛在的變量命名,或者其他變量錯(cuò)誤.這里所說(shuō)的空值,實(shí)際上也包括那些并不存在的變量,對(duì)于一個(gè)Java的 null值而言,我們認(rèn)為這個(gè)變量是存在的,只是它的值為null,但對(duì)于FreeMarker模板而言,它無(wú)法理解null值,null值和不存在的變量完全相同.
為了處理缺失變量,FreeMarker提供了兩個(gè)運(yùn)算符:
!:指定缺失變量的默認(rèn)值
??:判斷某個(gè)變量是否存在
其中,!運(yùn)算符的用法有如下兩種:
variable!或variable!defaultValue,第一種用法不給缺失的變量指定默認(rèn)值,表明默認(rèn)值是空字符串,長(zhǎng)度為0的集合,或者長(zhǎng)度為0的Map對(duì)象.
使用!指定默認(rèn)值時(shí),并不要求默認(rèn)值的類(lèi)型和變量類(lèi)型相同.使用??運(yùn)算符非常簡(jiǎn)單,它總是返回一個(gè)布爾值,用法為:variable??,如果該變量存在,返回true,否則返回false
3.11 運(yùn)算符的優(yōu)先級(jí)
FreeMarker中的運(yùn)算符優(yōu)先級(jí)如下(由高到低排列):
1,一元運(yùn)算符:!
2,內(nèi)建函數(shù):?
3,乘除法:*, / , %
4,加減法:- , +
5,比較:> , < , >= , <= (lt , lte , gt , gte)
6,相等:== , = , !=
7,邏輯與:&&
8,邏輯或:||
9,數(shù)字范圍:..
實(shí)際上,我們?cè)陂_(kāi)發(fā)過(guò)程中應(yīng)該使用括號(hào)來(lái)嚴(yán)格區(qū)分,這樣的可讀性好,出錯(cuò)少
4 FreeMarker的常用指令
FreeMarker的FTL指令也是模板的重要組成部分,這些指令可實(shí)現(xiàn)對(duì)數(shù)據(jù)模型所包含數(shù)據(jù)的撫今迭代,分支控制.除此之外,還有一些重要的功能,也是通過(guò)FTL指令來(lái)實(shí)現(xiàn)的.
4.1 if指令
這是一個(gè)典型的分支控制指令,該指令的作用完全類(lèi)似于Java語(yǔ)言中的if,if指令的語(yǔ)法格式如下:
<#if condition>...
<#elseif condition>...
<#elseif condition>...
<#else> ...
</#if>
例子如下:
<#assign age=23>
<#if (age>60)>老年人
<#elseif (age>40)>中年人
<#elseif (age>20)>青年人
<#else> 少年人
</#if>
輸出結(jié)果是:青年人
上面的代碼中的邏輯表達(dá)式用括號(hào)括起來(lái)主要是因?yàn)槔锩嬗?gt;符號(hào),由于FreeMarker會(huì)將>符號(hào)當(dāng)成標(biāo)簽的結(jié)束字符,可能導(dǎo)致程序出錯(cuò),為了避免這種情況,我們應(yīng)該在凡是出現(xiàn)這些符號(hào)的地方都使用括號(hào).
4.2 switch , case , default , break指令
這些指令顯然是分支指令,作用類(lèi)似于Java的switch語(yǔ)句,switch指令的語(yǔ)法結(jié)構(gòu)如下:
<#switch value>
<#case refValue>...<#break>
<#case refValue>...<#break>
<#default>...
</#switch>
4.3 list, break指令
list指令是一個(gè)迭代輸出指令,用于迭代輸出數(shù)據(jù)模型中的集合,list指令的語(yǔ)法格式如下:
<#list sequence as item>
...
</#list>
上面的語(yǔ)法格式中,sequence就是一個(gè)集合對(duì)象,也可以是一個(gè)表達(dá)式,但該表達(dá)式將返回一個(gè)集合對(duì)象,而item是一個(gè)任意的名字,就是被迭代輸出的集合元素.此外,迭代集合對(duì)象時(shí),還包含兩個(gè)特殊的循環(huán)變量:
item_index:當(dāng)前變量的索引值
item_has_next:是否存在下一個(gè)對(duì)象
也可以使用<#break>指令跳出迭代
例子如下:
<#list ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天"] as x>
${x_index + 1}.${x}<#if x_has_next>,</if>
<#if x="星期四"><#break></#if>
</#list>
4.4 include指令
include指令的作用類(lèi)似于JSP的包含指令,用于包含指定頁(yè).include指令的語(yǔ)法格式如下:
<#include filename [options]>
在上面的語(yǔ)法格式中,兩個(gè)參數(shù)的解釋如下:
filename:該參數(shù)指定被包含的模板文件
options:該參數(shù)可以省略,指定包含時(shí)的選項(xiàng),包含encoding和parse兩個(gè)選項(xiàng),其中encoding指定包含頁(yè)面時(shí)所用的解碼集,而parse指定被包含文件是否作為FTL文件來(lái)解析,如果省略了parse選項(xiàng)值,則該選項(xiàng)默認(rèn)是true.
4.5 import指令
該指令用于導(dǎo)入FreeMarker模板中的所有變量,并將該變量放置在指定的Map對(duì)象中,import指令的語(yǔ)法格式如下:
<#import "/lib/common.ftl" as com>
上面的代碼將導(dǎo)入/lib/common.ftl模板文件中的所有變量,交將這些變量放置在一個(gè)名為com的Map對(duì)象中.
4.6 noparse指令
noparse指令指定FreeMarker不處理該指定里包含的內(nèi)容,該指令的語(yǔ)法格式如下:
<#noparse>...</#noparse>
看如下的例子:
<#noparse>
<#list books as book>
<tr><td>${book.name}<td>作者:${book.author}
</#list>
</#noparse>
輸出如下:
<#list books as book>
<tr><td>${book.name}<td>作者:${book.author}
</#list>
4.7 escape , noescape指令
escape指令導(dǎo)致body區(qū)的插值都會(huì)被自動(dòng)加上escape表達(dá)式,但不會(huì)影響字符串內(nèi)的插值,只會(huì)影響到body內(nèi)出現(xiàn)的插值,使用escape指令的語(yǔ)法格式如下:
<#escape identifier as expression>...
<#noescape>...</#noescape>
</#escape>
看如下的代碼:
<#escape x as x?html>
First name:${firstName}
Last name:${lastName}
Maiden name:${maidenName}
</#escape>
上面的代碼等同于:
First name:${firstName?html}
Last name:${lastName?html}
Maiden name:${maidenName?html}
escape指令在解析模板時(shí)起作用而不是在運(yùn)行時(shí)起作用,除此之外,escape指令也嵌套使用,子escape繼承父escape的規(guī)則,如下例子:
<#escape x as x?html>
Customer Name:${customerName}
Items to ship;
<#escape x as itemCodeToNameMap[x]>
${itemCode1}
${itemCode2}
${itemCode3}
${itemCode4}
</#escape>
</#escape>
上面的代碼類(lèi)似于:
Customer Name:${customerName?html}
Items to ship;
${itemCodeToNameMap[itemCode1]?html}
${itemCodeToNameMap[itemCode2]?html}
${itemCodeToNameMap[itemCode3]?html}
${itemCodeToNameMap[itemCode4]?html}
對(duì)于放在escape指令中所有的插值而言,這此插值將被自動(dòng)加上escape表達(dá)式,如果需要指定escape指令中某些插值無(wú)需添加escape表達(dá)式,則應(yīng)該使用noescape指令,放在noescape指令中的插值將不會(huì)添加escape表達(dá)式.
4.8 assign指令
assign指令在前面已經(jīng)使用了多次,它用于為該模板頁(yè)面創(chuàng)建或替換一個(gè)頂層變量,assign指令的用法有多種,包含創(chuàng)建或替換一個(gè)頂層變量, 或者創(chuàng)建或替換多個(gè)變量等,它的最簡(jiǎn)單的語(yǔ)法如下:<#assign name=value [in namespacehash]>
,這個(gè)用法用于指定一個(gè)名為name的變量,該變量的值為value,此外,FreeMarker允許在使用 assign指令里增加in子句,in子句用于將創(chuàng)建的name變量放入namespacehash命名空間中.
assign指令還有如下用法:<#assign name1=value1 name2=value2 ... nameN=valueN [in namespacehash]>
,這個(gè)語(yǔ)法可以同時(shí)創(chuàng)建或替換多個(gè)頂層變量,此外,還有一種復(fù)雜的用法,如果需要?jiǎng)?chuàng)建或替換的變量值是一個(gè)復(fù)雜的表達(dá)式,則可以使用如下語(yǔ)法格式:<#assign name [in namespacehash]>capture this</#assign>,在這個(gè)語(yǔ)法中,是指將assign指令的內(nèi)容賦值給name變量.如下例子:
<#assign x>
<#list ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天"] as n>
${n}
</#list>
</#assign>
${x}
上面的代碼將產(chǎn)生如下輸出:星期一 星期二 星期三 星期四 星期五 星期六 星期天
雖然assign指定了這種復(fù)雜變量值的用法,但是我們也不要濫用這種用法,如下例子:<#assign x>Hello ${user}!</#assign>,以上代碼改為如下寫(xiě)法更合適:<#assign x="Hello ${user}!">
4.9 setting指令
該指令用于設(shè)置FreeMarker的運(yùn)行環(huán)境,該指令的語(yǔ)法格式如下:<#setting name=value>,在這個(gè)格式中,name的取值范圍包含如下幾個(gè):
locale:該選項(xiàng)指定該模板所用的國(guó)家/語(yǔ)言選項(xiàng)
number_format:指定格式化輸出數(shù)字的格式
boolean_format:指定兩個(gè)布爾值的語(yǔ)法格式,默認(rèn)值是true,false
date_format,time_format,datetime_format:指定格式化輸出日期的格式
time_zone:設(shè)置格式化輸出日期時(shí)所使用的時(shí)區(qū)
4.10 macro , nested , return指令
macro可以用于實(shí)現(xiàn)自定義指令,通過(guò)使用自定義指令,可以將一段模板片段定義成一個(gè)用戶(hù)指令,使用macro指令的語(yǔ)法格式如下:
<#macro name param1 param2 ... paramN>
...
<#nested loopvar1, loopvar2, ..., loopvarN>
...
<#return>
...
</#macro>
在上面的格式片段中,包含了如下幾個(gè)部分:
name:name屬性指定的是該自定義指令的名字,使用自定義指令時(shí)可以傳入多個(gè)參數(shù)
paramX:該屬性就是指定使用自定義指令時(shí)報(bào)參數(shù),使用該自定義指令時(shí),必須為這些參數(shù)傳入值
nested指令:nested標(biāo)簽輸出使用自定義指令時(shí)的中間部分
nested指令中的循環(huán)變量:這此循環(huán)變量將由macro定義部分指定,傳給使用標(biāo)簽的模板
return指令:該指令可用于隨時(shí)結(jié)束該自定義指令.
看如下的例子:
<#macro book> //定義一個(gè)自定義指令
j2ee
</#macro>
<@book /> //使用剛才定義的指令
上面的代碼輸出結(jié)果為:j2ee
在上面的代碼中,可能很難看出自定義標(biāo)簽的用處,因?yàn)槲覀兌x的book指令所包含的內(nèi)容非常簡(jiǎn)單,實(shí)際上,自定義標(biāo)簽可包含非常多的內(nèi)容,從而可以實(shí)現(xiàn)更好的代碼復(fù)用.此外,還可以在定義自定義指令時(shí),為自定義指令指定參數(shù),看如下代碼:
<#macro book booklist> //定義一個(gè)自定義指令booklist是參數(shù)
<#list booklist as book>
${book}
</#list>
</#macro>
<@book booklist=["spring","j2ee"] /> //使用剛剛定義的指令
上面的代碼為book指令傳入了一個(gè)參數(shù)值,上面的代碼的輸出結(jié)果為:spring j2ee
不僅如此,還可以在自定義指令時(shí)使用nested指令來(lái)輸出自定義指令的中間部分,看如下例子:
<#macro page title>
<html>
<head>
<title>FreeMarker示例頁(yè)面 - ${title?html}</title>
</head>
<body>
<h1>${title?html}</h1>
<#nested> //用于引入用戶(hù)自定義指令的標(biāo)簽體
</body>
</html>
</#macro>
上面的代碼將一個(gè)HTML頁(yè)面模板定義成一個(gè)page指令,則可以在其他頁(yè)面中如此page指令:
<#import "/common.ftl" as com> //假設(shè)上面的模板頁(yè)面名為common.ftl,導(dǎo)入頁(yè)面
<@com.page title="book list">
<u1>
<li>spring</li>
<li>j2ee</li>
</ul>
</@com.page>
從上面的例子可以看出,使用macro和nested指令可以非常容易地實(shí)現(xiàn)頁(yè)面裝飾效果,此外,還可以在使用nested指令時(shí),指定一個(gè)或多個(gè)循環(huán)變量,看如下代碼:
<#macro book>
<#nested 1> //使用book指令時(shí)指定了一個(gè)循環(huán)變量值
<#nested 2>
</#macro>
<@book ;x> ${x} .圖書(shū)</@book>
當(dāng)使用nested指令傳入變量值時(shí),在使用該自定義指令時(shí),就需要使用一個(gè)占位符(如book指令后的;x).上面的代碼輸出文本如下:
1 .圖書(shū) 2 .圖書(shū)
在nested指令中使用循環(huán)變量時(shí),可以使用多個(gè)循環(huán)變量,看如下代碼:
<#macro repeat count>
<#list 1..count as x> //使用nested指令時(shí)指定了三個(gè)循環(huán)變量
<#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. 2 Last;
return指令用于結(jié)束macro指令,一旦在macro指令中執(zhí)行了return指令,則FreeMarker不會(huì)繼續(xù)處理macro指令里的內(nèi)容,看如下代碼:
<#macro book>
spring
<#return>
j2ee
</#macro>
<@book />
上面的代碼輸出:spring,而j2ee位于return指令之后,不會(huì)輸出.
if, else, elseif
switch, case, default, break
list, break
include
Import
compress
escape, noescape
assign
global
setting
macro, nested, return
t, lt, rt
3一些常用方法或注意事項(xiàng)
表達(dá)式轉(zhuǎn)換類(lèi)
數(shù)字循環(huán)
對(duì)浮點(diǎn)取整數(shù)
給變量默認(rèn)值
判斷對(duì)象是不是null
常用格式化日期
添加全局共享變量數(shù)據(jù)模型
直接調(diào)用java對(duì)象的方法
字符串處理(內(nèi)置方法)
在模板里對(duì)sequences和hashes初始化
注釋標(biāo)志
sequences內(nèi)置方法
hashes內(nèi)置方法
4 freemarker在web開(kāi)發(fā)中注意事項(xiàng)
web中常用的幾個(gè)對(duì)象
view中值的搜索順序
在模板里ftl里使用標(biāo)簽
如何初始化共享變量
與webwork整合配置
5高級(jí)方法
自定義方法
自定義 Transforms
1概念
最常用的3個(gè)概念
sequence 序列,對(duì)應(yīng)java里的list端铛、數(shù)組等非鍵值對(duì)的集合
hash 鍵值對(duì)的集合
namespace 對(duì)一個(gè)ftl文件的引用,利用這個(gè)名字可以訪問(wèn)到該ftl文件的資源
2指令
if, else, elseif
語(yǔ)法
<#if condition>
...
<#elseif condition2>
...
<#elseif condition3>
...
...
<#else>
...
</#if>
用例
<#if x = 1>
x is 1
</#if>
<#if x = 1>
x is 1
<#else>
x is not 1
</#if>
switch, case, default, break
語(yǔ)法
<#switch value>
<#case refValue1>
...
<#break>
<#case refValue2>
...
<#break>
...
<#case refValueN>
...
<#break>
<#default>
...
</#switch>
用例
字符串
<
#switch being.size>
<#case "small">
This will be processed if it is small
<#break>
<#case "medium">
This will be processed if it is medium
<#break>
<#case "large">
This will be processed if it is large
<#break>
<#default>
This will be processed if it is neither
</#switch>
數(shù)字
<#switch x>
<#case x = 1>
1
<#case x = 2>
2
<#default>
d
</#switch>
如果x=1 輸出 1 2, x=2輸出 2, x=3 輸出d
list, break
語(yǔ)法
<#list sequence as item>
...
<#if item = "spring"><#break></#if>
...
</#list>
關(guān)鍵字
item_index:是list當(dāng)前值的下標(biāo)
item_has_next:判斷l(xiāng)ist是否還有值
用例
<#assign seq = ["winter", "spring", "summer", "autumn"]>
<#list seq as x>
${x_index + 1}. ${x}<#if x_has_next>,</#if>
</#list>
輸出
1. winter,
2. spring,
3. summer,
4. autumn
include
語(yǔ)法
<#include filename>
or<#include filename options>
options包含兩個(gè)屬性
encoding=”GBK” 編碼格式
parse=true 是否作為ftl語(yǔ)法解析,默認(rèn)是true,false就是以文本方式引入.注意在ftl文件里布爾值都是直接賦值的如parse=true,而不是parse=”true”
用例
/common/copyright.ftl包含內(nèi)容
Copyright 2001-2002 ${me}
All rights reserved.
模板文件
<#assign me = "Juila Smith">
<h1>Some test</h1>
<p>Yeah.
<hr>
<#include "/common/copyright.ftl" encoding=”GBK”>
輸出結(jié)果
<h1>Some test</h1>
<p>Yeah.
<hr>
Copyright 2001-2002 Juila Smith
All rights reserved.
Import
語(yǔ)法
<#import path as hash>
類(lèi)似于java里的import,它導(dǎo)入文件,然后就可以在當(dāng)前文件里使用被導(dǎo)入文件里的宏組件
用例
假設(shè)mylib.ftl里定義了宏copyright那么我們?cè)谄渌0屙?yè)面里可以這樣使用
<#import "/libs/mylib.ftl" as my>
<@my.copyright date="1999-2002"/>
"my"在freemarker里被稱(chēng)作namespace
compress<#compress>
...
</#compress>
用來(lái)壓縮空白空間和空白的行
<#assign x = " moo \n\n ">
(<#compress>
1 2 3 4 5
${moo}
test only
I said, test only
</#compress>)
輸出
(1 2 3 4 5
moo
test only
I said, test only)
escape, noescape
語(yǔ)法
<#escape identifier as expression>
...
<#noescape>...</#noescape>
...
</#escape>
用例
主要使用在相似的字符串變量輸出,比如某一個(gè)模塊的所有字符串輸出都必須是html安全的否彩,這個(gè)時(shí)候就可以使用該表達(dá)式
<#escape x as x?html>
First name: ${firstName}
<#noescape>Last name: ${lastName}</#noescape>
Maiden name: ${maidenName}
</#escape>
相同表達(dá)式
First name: ${firstName?html}
Last name: ${lastName }
Maiden name: ${maidenName?html}
assign
語(yǔ)法
<#assign name=value>
or
<#assign name1=value1 name2=value2 ... nameN=valueN>
or
<#assign same as above... in namespacehash>
or
<#assign name>
capture this
</#assign>
or
<#assign name in namespacehash>
capture this
</#assign>
用例
生成變量,并且給變量賦值
給seasons賦予序列值
<#assign seasons = ["winter", "spring", "summer", "autumn"]>
給變量test加1
<#assign test = test + 1>
給my namespage 賦予一個(gè)變量bgColor,下面可以通過(guò)my.bgColor來(lái)訪問(wèn)這個(gè)變量
<#import "/mylib.ftl" as my>
<#assign bgColor="red" in my>
將一段輸出的文本作為變量保存在x里
下面的陰影部分輸出的文本將被賦值給x
<#assign x>
<#list 1..3 as n>
${n} <@myMacro />
</#list>
</#assign>
Number of words: ${x?word_list?size}
${x}
<#assign x>Hello ${user}!</#assign> error
<#assign x=” Hello ${user}!”> true
同時(shí)也支持中文賦值,如:
<#assign 語(yǔ)法>
java
</#assign>
${語(yǔ)法}
打印輸出:
java
global
語(yǔ)法
<#global name=value>
or
<#global name1=value1 name2=value2 ... nameN=valueN>
or
<#global name>
capture this
</#global>
全局賦值語(yǔ)法,利用這個(gè)語(yǔ)法給變量賦值腕巡,那么這個(gè)變量在所有的namespace中是可見(jiàn)的,如果這個(gè)變量被當(dāng)前的assign語(yǔ)法覆蓋如<#global x=2> <#assign x=1>
在當(dāng)前頁(yè)面里x=2將被隱藏,或者通過(guò)${.global.x}來(lái)訪問(wèn)
setting
語(yǔ)法
<#setting name=value>
用來(lái)設(shè)置整個(gè)系統(tǒng)的一個(gè)環(huán)境
locale
number_format
boolean_format
date_format, time_format, datetime_format
time_zone
classic_compatible
用例
假如當(dāng)前是匈牙利的設(shè)置血筑,然后修改成美國(guó)
${1.2}
<#setting locale="en_US">
${1.2}
輸出
1,2
1.2
因?yàn)樾傺览遣捎谩?”作為十進(jìn)制的分隔符绘沉,美國(guó)是用“.”
macro, nested, return
語(yǔ)法
<#macro name param1 param2 ... paramN>
...
<#nested loopvar1, loopvar2, ..., loopvarN>
...
<#return>
...
</#macro>
用例
<#macro test foo bar="Bar" baaz=-1>
Test text, and the params: ${foo}, ${bar}, ${baaz}
</#macro>
<@test foo="a" bar="b" baaz=5*5-2/>
<@test foo="a" bar="b"/>
<@test foo="a" baaz=5*5-2/>
<@test foo="a"/>
輸出
Test text, and the params: a, b, 23
Test text, and the params: a, b, -1
Test text, and the params: a, Bar, 23
Test text, and the params: a, Bar, -1
定義循環(huán)輸出的宏
<#macro list title items>
<p>${title?cap_first}:
<ul>
<#list items as x>
<li>${x?cap_first}
</#list>
</ul>
</#macro>
<@list items=["mouse", "elephant", "python"] title="Animals"/>
輸出結(jié)果
<p>Animals:
<ul>
<li>Mouse
<li>Elephant
<li>Python
</ul>
包含body的宏
<#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. 2 Last!
t, lt, rt
語(yǔ)法
<#t> 去掉左右空白和回車(chē)換行
<#lt>去掉左邊空白和回車(chē)換行
<#rt>去掉右邊空白和回車(chē)換行
<#nt>取消上面的效果
3一些常用方法或注意事項(xiàng)
表達(dá)式轉(zhuǎn)換類(lèi)
${expression}計(jì)算expression并輸出
#{ expression }數(shù)字計(jì)算#{ expression ;format}安格式輸出數(shù)字format為M和m
M表示小數(shù)點(diǎn)后最多的位數(shù),m表示小數(shù)點(diǎn)后最少的位數(shù)如#{121.2322;m2M2}輸出121.23
數(shù)字循環(huán)
1..5 表示從1到5,原型number..number
對(duì)浮點(diǎn)取整數(shù)
${123.23?int} 輸出123
給變量默認(rèn)值
${var?default(“hello world
”)?html}如果var is null那么將會(huì)被hello world
替代
判斷對(duì)象是不是null
<#if mouse?exists>
Mouse found
<#else>
也可以直接${mouse?if_exists})輸出布爾形
常用格式化日期
openingTime必須是Date型,詳細(xì)查看freemarker文檔 Reference->build-in referece->build-in for date
${openingTime?date}
${openingTime?date_time}
${openingTime?time}
添加全局共享變量數(shù)據(jù)模型
在代碼里的實(shí)現(xiàn)
cfg = Configuration.getDefaultConfiguration();
cfg.setSharedVariable("global", "you good");
頁(yè)面實(shí)現(xiàn)可以通過(guò)global指令,具體查看指令里的global部分
直接調(diào)用java對(duì)象的方法
${object.methed(args)}
字符串處理(內(nèi)置方法)
html安全輸出
“abc<table>sdfsf”?html
返回安全的html輸出,替換掉html代碼
xml安全輸出
var?xml
substring的用法
<#assign user=”hello jeen”>
${user[0]}${user[4]}
${user[1..4]}
輸出 :
ho
ello
類(lèi)似String.split的用法
“abc;def;ghi”?split(“;”)返回sequence
將字符串按空格轉(zhuǎn)化成sequence,然后取sequence的長(zhǎng)度
var?word_list 效果同 var?split(“ ”)
var?word_list?size
取得字符串長(zhǎng)度
var?length
大寫(xiě)輸出字符
var?upper_case
小寫(xiě)輸出字符
var?lower_case
首字符大寫(xiě)
var?cap_first
首字符小寫(xiě)
var?uncap_first
去掉字符串前后空格
var?trim
每個(gè)單詞的首字符大寫(xiě)
var?capitalize
類(lèi)似String.indexof:
“babcdabcd”?index_of(“abc”) 返回1
“babcdabcd”?index_of(“abc”,2) 返回5
類(lèi)似String.lastIndexOf
last_index_of和String.lastIndexOf類(lèi)似,同上
下面兩個(gè)可能在代碼生成的時(shí)候使用(在引號(hào)前加”\”)
j_string: 在字符串引號(hào)前加”\”
<#assign beanName = 'The "foo" bean.'>
String BEAN_NAME = "${beanName?j_string}";
打印輸出:
String BEAN_NAME = "The \"foo\" bean.";
js_string:
<#assign user = "Big Joe's \"right hand\".">
<script>
alert("Welcome ${user}!");
</script>
打印輸出
alert("Welcome Big Joe\'s \"right hand\"!");
替換字符串 replace
${s?replace(‘ba’, ‘XY’ )}
${s?replace(‘ba’, ‘XY’ , ‘規(guī)則參數(shù)’)}將s里的所有的ba替換成xy 規(guī)則參數(shù)包含: i r m s c f 具體含義如下:
· i: 大小寫(xiě)不區(qū)分.
· f: 只替換第一個(gè)出現(xiàn)被替換字符串的字符串
· r: XY是正則表達(dá)式
· m: Multi-line mode for regular expressions. In multi-line mode the expressions ^ and $ match just after or just before, respectively, a line terminator or the end of the string. By default these expressions only match at the beginning and the end of the entire string.
· s: Enables dotall mode for regular expressions (same as Perl singe-line mode). In dotall mode, the expression . matches any character, including a line terminator. By default this expression does not match line terminators.
· c: Permits whitespace and comments in regular expressions.
在模板里對(duì)sequences和hashes初始化
sequences
1. [“you”,”me”,”he”]
2. 1..100
3. [ {“Akey”:”Avalue”},{“Akey1”:”Avalue1”},
{“Bkey”:”Bvalue”},{“Bkey1”:”Bvalue1”},
]
hashes {“you”:”a”,”me”:”b”,”he”:”c”}
注釋標(biāo)志
<#--
這里是注釋
-->
舊版本的freemarker采用的是<#comment> 注釋 </#comment>方法
sequences內(nèi)置方法
sequence?first
返回sequence的第一個(gè)值;前提條件sequence不能是null
sequence?last
返回sequence最后一個(gè)值
sequence?reverse
反轉(zhuǎn)sequence的值
sequence?size
返回sequence的大小
sequence?sort
對(duì)sequence按里面的對(duì)象toString()的結(jié)果進(jìn)行排序
sequence?sort_by(value)
對(duì)sequence 按里面的對(duì)象的屬性value進(jìn)行排序
如: sequence里面放入的是10 個(gè)user對(duì)象豺总,user對(duì)象里面包含name,age等屬性
sequence?sort_by(name) 表示所有的user按user.name進(jìn)行排序
hashes內(nèi)置方法
hash?keys
返回hash里的所有keys, 返回結(jié)果類(lèi)型sequence
hash?values
返回hash里的所有value, 返回結(jié)果類(lèi)型sequence
4 freemarker在web開(kāi)發(fā)中注意事項(xiàng)
freemarker與webwork整合
web中常用的幾個(gè)對(duì)象
Freemarker的ftl文件中直接使用內(nèi)部對(duì)象:
${Request ["a"]}
${RequestParameters["a"]}
${Session ["a"]}
${Application ["a"]}
${JspTaglibs ["a"]}
5 整合springboot
引入依賴(lài)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
文件配置
########################################################
###FREEMARKER (FreeMarkerAutoConfiguration)
########################################################
spring.freemarker.allow-request-override=false
spring.freemarker.cache=true
spring.freemarker.check-template-location=true
spring.freemarker.charset=UTF-8
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=false
spring.freemarker.expose-session-attributes=false
spring.freemarker.expose-spring-macro-helpers=false
#spring.freemarker.prefix=
#spring.freemarker.request-context-attribute=
#spring.freemarker.settings.*=
#spring.freemarker.suffix=.ftl
#spring.freemarker.template-loader-path=classpath:/templates/ #comma-separated list
#spring.freemarker.view-names= # whitelist of view names that can be resolved
創(chuàng)建controller
@Controller
@RequestMapping("/user")
public class HelloContreller {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@GetMapping()
public String hello(Model model) {
model.addAttribute("name", "cxhc");
return "index";
}
}
創(chuàng)建view
<!DOCTYPE html>
<html>
<head lang="en">
<title>Spring Boot Demo - FreeMarker</title>
</head>
<body>
大家好我是${name}
</body>
</html>
啟動(dòng)工程
輸入url
http://localhost:8080/user/index
文章地址:http://www.haha174.top/article/details/259667
推薦一篇文章:http://mp.weixin.qq.com/s/SLaIcVp2EOwz5996oJZrHw
項(xiàng)目源碼:https://github.com/haha174/boot.git
歡迎關(guān)注车伞,更多福利