工具集核心教程 | 第六篇: Freemarker模板引擎入門到進階

Freemarker的介紹

  Freemarker 是一款模板引擎,是一種基於模版生成靜態文件的通用 工具,它是爲程序員提供的一個開發包,或者說是一個類庫,它不是面向最終用戶的,而是爲程序員提供了一款能夠嵌入他們開發產品的應用程序。
  Freemarker 是使用純java編寫的,爲了提升頁面的訪問速度,須要把頁面靜態化, 那麼Freemarker就是被用來生成html頁面。
  到目前爲止,Freemarker使用愈來愈普遍,不光光只是它強大的生成技術,並且它可以與進行很好的集成。
 如今開始一層層揭開它的神祕面紗。。。php

特色

1.  輕量級模版引擎,不須要Servlet環境就能夠很輕鬆的嵌入到應用程序中
2.  能生成各類文本,如html,xml,java,等
3.  入門簡單,它是用java編寫的,不少語法和java類似

工做原理:(借用網上的圖片)
Freemarker工做原理html

目錄

1.FTL指令規則
2.插值規則
3.表達式
4.FreeMarker的經常使用指令
5.高級方法

前言

FreeMarker的模板文件並不比HTML頁面複雜多少,FreeMarker模板文件主要由以下4個部分組成:前端

1.文本:直接輸出的部分
2.註釋:<#-- ... -->格式部分,不會輸出
3.插值:即${...}或#{...}格式的部分,將使用數據模型中的部分替代輸出
4.FTL指令:FreeMarker指定,和HTML標記相似,名字前加#予以區分,不會輸出

下面是一個FreeMarker模板的例子,包含了以上所說的4個部分:java

<html>
    <head>
        <title>Welcome!</title>
    </head>
    <body>
        <#-- 註釋部分 -->
        <#-- 下面使用插值 -->
        <h1>Welcome ${user} !</h1>
        <p>We have these animals:</p>
        <u1>
            <#-- 使用FTL指令 -->
            <#list animals as being>
            <li>${being.name} for ${being.price} Euros</li>
            <#list>
        <u1>
    </body>
</html>

1. FTL指令規則

FreeMarker中,使用FTL標籤來使用指令,FreeMarker3FTL標籤,這和HTML標籤是徹底相似的.python

開始標籤:<#directivename parameter>
結束標籤:</#directivename>
空標籤:<#directivename parameter/>

實際上,使用標籤時前面的符號#也可能變成@,若是該指令是一個用戶指令而不是系統內建指令時,應將#符號改爲@符號.程序員

使用FTL標籤時,應該有正確的嵌套,而不是交叉使用,這和XML標籤的用法徹底同樣.若是全用不存在的指令,FreeMarker不會使用模板輸出,而是產生一個錯誤消息.FreeMarker會忽略FTL標籤中的空白字符.值得注意的是< , /> 和指令之間不容許有空白字符.面試

2. 插值規則

FreeMarker的插值有以下兩種類型:spring

通用插值${expr};
數字格式化插值:#{expr}或#{expr;format}

2.1 通用插值

對於通用插值,又能夠分爲如下4種狀況:express

1.插值結果爲字符串值:直接輸出表達式結果
2.插值結果爲數字值:根據默認格式(由#setting指令設置)將表達式結果轉換成文本輸出.可使用內建的字符串   函數格式化單個插值,以下面的例子:
<#settion number_format="currency"/>
<#assign answer=42/>
${answer}
${answer?string} <#-- the same as ${answer} -->
${answer?string.number}
${answer?string.currency}
${answer?string.percent}
${answer}

輸出結果是:小程序

$42.00
$42.00
42
$42.00
4,200%
3.插值結果爲日期值:根據默認格式(由#setting指令設置)將表達式結果轉換成文本輸出.可使用內建的字符串函數格式化單個插值,以下面的例子:
${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')'")}

輸出結果是:

2008-04-08 08:08:08 Pacific Daylight Time
Tue, Apr 8, '03
Tuesday, April 08, 2003, 08:08:08 PM (PDT)
4.插值結果爲布爾值:根據默認格式(由#setting指令設置)將表達式結果轉換成文本輸出.可使用內建的字符串函數格式化單個插值,以下面的例子:
<#assign foo=true/>
${foo?string("yes", "no")}

輸出結果是:

yes

2.2 數字格式化插值

數字格式化插值可採用#{expr;format}形式來格式化數字,其中format能夠是:

mX:小數部分最小X位
MX:小數部分最大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. 表達式

表達式是FreeMarker模板的核心功能,表達式放置在插值語法${}之中時,代表須要輸出表達式的值;表達式語法也可與FreeMarker標籤結合,用於控制輸出.實際上FreeMarker的表達式功能很是強大,它不只支持直接指定值,輸出變量值,也支持字符串格式化輸出和集合訪問等功能.

3.1 直接指定值

使用直接指定值語法讓FreeMarker直接輸出插值中的值,而不是輸出變量值.直接指定值能夠是字符串,數值,布爾值,集合和MAP對象.

字符串

直接指定字符串值使用單引號或雙引號限定,若是字符串值中包含特殊字符須要轉義,看下面的例子:

${"個人文件保存在C:\\盤"}
${'我名字是\"annlee\"'}

輸出結果是:

個人文件保存在C:\盤
我名字是"annlee"

FreeMarker支持以下轉義字符:

\"; 雙引號(u0022)
\'; 單引號(u0027)
\\; 反斜槓(u005C)
\n; 換行(u000A)
\r; 回車(u000D)
\t; Tab(u0009)
\b; 退格鍵(u0008)
\f; Form feed(u000C)
\l; <
\g; >
\a; &
\{; {
\xCode; 直接經過4位的16進制數來指定Unicode碼,輸出該unicode碼對應的字符.

若是某段文本中包含大量的特殊符號,FreeMarker提供了另外一種特殊格式:能夠在指定字符串內容的引號前增長r標記,在r標記後的文件將會直接輸出。看以下代碼:

${r"${foo}"}
${r"C:\foo\bar"}

輸出結果是:

${foo}
C:\foo\bar
數值

表達式中的數值直接輸出,不須要引號.小數點使用"."分隔,不能使用分組","符號.FreeMarker目前還不支持科學計數法,因此"1E3"是錯誤的.在FreeMarker表達式中使用數值須要注意如下幾點:

數值不能省略小數點前面的0,因此".5"是錯誤的寫法

數值8 , +8 , 8.00都是相同的

布爾值,直接使用true和false,不使用引號.

集合, 集合以方括號包括,各集合元素之間以英文逗號","分隔

以下爲集合元素遍歷的例子:

<#list ["星期一", "星期二", "星期三", "星期四", "星期五",     "星期六", "星期天"] as x>
    ${x}
</#list>

輸出結果是:

星期一
星期二
星期三
星期四
星期五
星期六
星期天

除此以外,集合元素也能夠是表達式,例子以下:

[2 + 2, [1, 2, 3, 4], "whatnot"]

還可使用數字範圍定義數字集合,如2..5等同於[2, 3, 4, 5], 可是更有效率。

    注意,使用數字範圍來定義集合時無需使用方括號,數字範圍也支持反遞增的數字範圍,如5..2

Map對象,Map對象使用花括號包括,Map中的key-value對之間以英文冒號":"分隔,多組key-value對之間以英文逗號","分隔。

下面是一個例子:

{"語文":78, "數學":80}

Map對象的key和value都是表達式,可是key必須是字符串。

3.2 輸出變量值

FreeMarker的表達式輸出變量時,這些變量能夠是頂層變量,也能夠是Map對象中的變量,還能夠是集合中的變量,並可使用點(.)語法來訪問Java對象的屬性。下面分別討論這些狀況:

1. 頂層變量

所謂頂層變量就是直接放在數據模型中的值,例若有以下數據模型:

Map root = new HashMap();   //建立數據模型
root.put("name","annlee");   //name是一個頂層變量

對於頂層變量,直接使用${variableName}來輸出變量值,變量名只能是字母,數字,下劃線,$,@#的組合,且不能以數字開頭號.爲了輸出上面的name的值,可使用以下語法:

${name}

2. 輸出集合元素

若是須要輸出集合元素,則能夠根據集合元素的索引來輸出集合元素,集合元素的索引以方括號指定。

假設有索引:["星期一","星期二","星期三","星期四","星期五","星期六","星期天"],該索引名爲week,若是須要輸出星期三,則可使用以下語法:

${week[2]} //輸出第三個集合元素

此外,FreeMarker還支持返回集合的子集合,若是須要返回集合的子集合,則可使用以下語法:

week[3..5] //返回week集合的子集合,子集合中的元素是week集合中的第4-6個元素

3. 輸出Map元素

這裏的Map對象能夠是直接HashMap的實例,甚至包括JavaBean實例,對於JavaBean實例而言,咱們同樣能夠把其當成屬性爲key,屬性值爲valueMap實例.爲了輸出Map元素的值,可使用點語法或方括號語法.假若有下面的數據模型:

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);

爲了訪問數據模型中名爲struts2的書的做者的名字,可使用以下語法:

book.author.name //所有使用點語法
book["author"].name
book.author["name"] //混合使用點語法和方括號語法
book["author"]["name"] //所有使用方括號語法

使用點語法時,變量名字有頂層變量同樣的限制,但方括號語法沒有該限制,由於名字能夠是任意表達式的結果.

3.3 字符串操做

FreeMarker的表達式對字符串操做很是靈活,能夠將字符串常量和變量鏈接起來,也能夠返回字符串的子串等。

字符串鏈接有兩種語法:

使用${..}或#{..}在字符串常量部分插入表達式的值,從而完成字符串鏈接.
直接使用鏈接運算符+來鏈接字符串

例若有以下數據模型:

Map root = new HashMap(); 
root.put("user","annlee");

下面將user變量和常量鏈接起來:

${"hello, ${user}!"}   //使用第一種語法來鏈接
${"hello, " + user + "!"} //使用+號來鏈接

上面的輸出字符串都是hello,annlee!,能夠看出這兩種語法的效果徹底同樣.
值得注意的是,${..}只能用於文本部分,不能用於表達式,下面的代碼是錯誤的:

<#if ${isBig}>Wow!</#if>
<#if "${isBig}">Wow!</#if>

應該寫成:

<#if isBig>Wow!</#if>

截取子串能夠根據字符串的索引來進行,截取子串時若是隻指定了一個索引值,則用於取得字符串中指定索引所對應的字符;若是指定兩個索引值,則返回兩個索引中間的字符串子串。假若有以下數據模型:

Map root = new HashMap(); 
root.put("book","struts2,freemarker");

能夠經過以下語法來截取子串:

${book[0]}${book[4]}   //結果是su
${book[1..4]}     //結果是tru

3.4 集合鏈接運算符

這裏所說的集合運算符是將兩個集合鏈接成一個新的集合,鏈接集合的運算符是+,看以下的例子:

<#list ["星期一","星期二","星期三"] + ["星期四","星期五","星期六","星期天"] as x>
    ${x}
</#list>

輸出結果是:

星期一 星期二 星期三 星期四 星期五 星期六 星期天

3.5 Map鏈接運算符

Map對象的鏈接運算符也是將兩個Map對象鏈接成一個新的Map對象,Map對象的鏈接運算符是+,若是兩個Map對象具備相同的key,則右邊的值替代左邊的值.看以下的例子:

<#assign scores = {"語文":86,"數學":78} + {"數學":87,"Java":93}>
語文成績是${scores.語文}
數學成績是${scores.數學}
Java成績是${scores.Java}

輸出結果是:

語文成績是86
數學成績是87
Java成績是93

3.6 算術運算符

FreeMarker表達式中徹底支持算術運算,FreeMarker支持的算術運算符包括:+, - , * , / , % 看以下的代碼:

<#assign x=5>
${ x * x - 100 }
${ x /2 }
${ 12 %10 }

輸出結果是:

-75   2.5   2

在表達式中使用算術運算符時要注意如下幾點:

運算符兩邊的運算數字必須是數字
使用+運算符時,若是一邊是數字,一邊是字符串,就會自動將數字轉換爲字符串再鏈接,如: ${3 + "5"},結果是:35

使用內建的int函數可對數值取整,如:

<#assign x=5>
${ (x/2)?int }
${ 1.1?int }
${ 1.999?int }
${ -1.1?int }
${ -1.999?int }

結果是:

2 1 1 -1 -1

3.7 比較運算符

表達式中支持的比較運算符有以下幾個:

=或者==:判斷兩個值是否相等.
!=:判斷兩個值是否不等.
>或者gt:判斷左邊值是否大於右邊值
>=或者gte:判斷左邊值是否大於等於右邊值
<或者lt:判斷左邊值是否小於右邊值
<=或者lte:判斷左邊值是否小於等於右邊值

注意:=和!=能夠用於字符串,數值和日期來比較是否相等,但=和!=兩邊必須是相同類型的值,不然會產生錯誤,並且FreeMarker是精確比較,"x","x ","X"是不等的.其它的運行符能夠做用於數字和日期,但不能做用於字符串,大部分的時候,使用gt等字母運算符代替>會有更好的效果,由於FreeMarker會把>解釋成FTL標籤的結束字符,固然,也可使用括號來避免這種狀況,如:<#if (x>y)>。

3.8 邏輯運算符

邏輯運算符有以下幾個:

邏輯與: &&
邏輯或: ||
邏輯非: !

邏輯運算符只能做用於布爾值,不然將產生錯誤。

3.9 內建函數

FreeMarker還提供了一些內建函數來轉換輸出,能夠在任何變量後緊跟「?」「?」後緊跟內建函數,就能夠經過內建函數來輪換輸出變量.下面是經常使用的內建的字符串函數:

html:對字符串進行HTML編碼
cap_first:使字符串第一個字母大寫
lower_case:將字符串轉換成小寫
upper_case:將字符串轉換成大寫
trim:去掉字符串先後的空白字符

下面是集合的經常使用內建函數

size:獲取序列中元素的個數

下面是數字值的經常使用內建函數

int:取得數字的整數部分,結果帶符號

例如:

<#assign test="Tom & Jerry">
${test?html}
${test?upper_case?html}

結果是:

Tom &amp; Jerry   TOM &amp; JERRY

3.10 空值處理運算符

FreeMarker對空值的處理很是嚴格,FreeMarker的變量必須有值,沒有被賦值的變量就會拋出異常,由於FreeMarker未賦值的變量強制出錯能夠杜絕不少潛在的錯誤,如缺失潛在的變量命名,或者其餘變量錯誤.這裏所說的空值,實際上也包括那些並不存在的變量,對於一個Javanull值而言,咱們認爲這個變量是存在的,只是它的值爲null,但對於FreeMarker模板而言,它沒法理解null值,null值和不存在的變量徹底相同.

爲了處理缺失變量,FreeMarker提供了兩個運算符:

! :指定缺失變量的默認值
??:判斷某個變量是否存在

其中,!運算符的用法有以下兩種:variable!variable!defaultValue,第一種用法不給缺失的變量指定默認值,代表默認值是空字符串,長度爲0的集合,或者長度爲0Map對象。使用!指定默認值時,並不要求默認值的類型和變量類型相同.使用??運算符很是簡單,它老是返回一個布爾值,用法爲:variable??,若是該變量存在,返回true,不然返回false

3.11 運算符的優先級

FreeMarker中的運算符優先級以下(由高到低排列):

一元運算符: !
內建函數: ?
乘除法: *, / , %
加減法: - , +
比較: > , < , >= , <= (lt , lte , gt , gte)
相等: == , = , !=
邏輯與: &&
邏輯或: ||
數字範圍: ..

實際上,咱們在開發過程當中應該使用括號來嚴格區分,這樣的可讀性好,出錯少。

4. FreeMarker的經常使用指令

FreeMarkerFTL指令也是模板的重要組成部分,這些指令可實現對數據模型所包含數據的撫今迭代,分支控制.除此以外,還有一些重要的功能,也是經過FTL指令來實現的.

4.1 if指令

這是一個典型的分支控制指令,該指令的做用徹底相似於Java語言中的if,if指令的語法格式以下:

<#if condition>...
<#elseif condition>...
<#elseif condition>...
<#else> ...
</#if>

例子以下:

<#assign age=23>
<#if (age>60)>
    老年人
<#elseif (age>40)>
    中年人
<#elseif (age>20)>
    青年人
<#else> 
    少年人
</#if>

輸出結果是:

青年人

上面的代碼中的邏輯表達式用括號括起來主要是由於裏面有>符號,因爲FreeMarker會將>符號當成標籤的結束字符,可能致使程序出錯,爲了不這種狀況,咱們應該在凡是出現這些符號的地方都使用括號。

4.2 switch , case , default , break指令

這些指令顯然是分支指令,做用相似於Javaswitch語句,switch指令的語法結構以下:

<#switch value>
    <#case refValue>...<#break>
    <#case refValue>...<#break>
    <#default>...
</#switch>

4.3 list, break指令

list指令是一個迭代輸出指令,用於迭代輸出數據模型中的集合,list指令的語法格式以下:

<#list sequence as item>
    ...
</#list>

上面的語法格式中,sequence就是一個集合對象,也能夠是一個表達式,但該表達式將返回一個集合對象,而item是一個任意的名字,就是被迭代輸出的集合元素.此外,迭代集合對象時,還包含兩個特殊的循環變量:

item_index:當前變量的索引值
item_has_next:是否存在下一個對象

除此以外,也可使用<#break>指令跳出迭代。

例子以下:

<#list ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天"] as x>
    ${x_index + 1}.${x}<#if x_has_next>,</if>
    <#if x="星期四"><#break></#if>
</#list>

4.4 include指令

include指令的做用相似於JSP的包含指令,用於包含指定頁.include指令的語法格式以下:

<#include filename [options]>

在上面的語法格式中,兩個參數的解釋以下:

filename:該參數指定被包含的模板文件
options:該參數能夠省略,指定包含時的選項,包含encoding和parse兩個選項,其中encoding指定包含頁面時所用的解碼集,而parse指定被包含文件是否做爲FTL文件來解析,若是省略了parse選項值,則該選項默認是true.

4.5 import指令

import指令用於導入FreeMarker模板中的全部變量,並將該變量放置在指定的Map對象中,import指令的語法格式以下:

<#import "/lib/common.ftl" as com>

上面的代碼將導入/lib/common.ftl模板文件中的全部變量,交將這些變量放置在一個名爲comMap對象中.

4.6 noparse指令

noparse指令指定FreeMarker不處理該指定裏包含的內容,該指令的語法格式以下:

<#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指令致使body區的插值都會被自動加上escape表達式,但不會影響字符串內的插值,只會影響到body內出現的插值,使用escape指令的語法格式以下:

<#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指令在解析模板時起做用而不是在運行時起做用,除此以外,escape指令也嵌套使用,子escape繼承父escape的規則,以下例子:

<#escape x as x?html>
    Customer Name:${customerName}
    Items to ship;
    <#escape x as itemCodeToNameMap[x]>
       ${itemCode1}
       ${itemCode2}
       ${itemCode3}
       ${itemCode4}
    </#escape>
</#escape>

上面的代碼相似於:

Customer Name:${customerName?html}
Items to ship;
${itemCodeToNameMap[itemCode1]?html}
${itemCodeToNameMap[itemCode2]?html}
${itemCodeToNameMap[itemCode3]?html}
${itemCodeToNameMap[itemCode4]?html}

對於放在escape指令中全部的插值而言,這此插值將被自動加上escape表達式,若是須要指定escape指令中某些插值無需添加escape表達式,則應該使用noescape指令,放在noescape指令中的插值將不會添加escape表達式。

4.8 assign指令

assign指令在前面已經使用了屢次,它用於爲該模板頁面建立或替換一個頂層變量,assign指令的用法有多種,包含建立或替換一個頂層變量,或者建立或替換多個變量等,它的最簡單的語法以下:

<#assign name=value [in namespacehash]>

這個用法用於指定一個名爲name的變量,該變量的值爲value,此外,FreeMarker容許在使用assign指令裏增長in子句,in子句用於將建立的name變量放入namespacehash命名空間中。

assign指令還有以下用法:

<#assign name1=value1 name2=value2 ... nameN=valueN [in namespacehash]>

這個語法能夠同時建立或替換多個頂層變量,此外,還有一種複雜的用法,若是須要建立或替換的變量值是一個複雜的表達式,則可使用以下語法格式:

<#assign name [in namespacehash]>capture this</#assign>

在這個語法中,是指將assign指令的內容賦值給name變量。以下例子:

<#assign x>
    <#list ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天"] as n>
        ${n}
    </#list>
</#assign>
${x}

上面的代碼將產生以下輸出:

星期一 星期二 星期三 星期四 星期五 星期六 星期天

雖然assign指定了這種複雜變量值的用法,可是咱們也不要濫用這種用法,以下例子:

<#assign x>Hello ${user}!</#assign>

以上代碼改成以下寫法更合適:

<#assign x="Hello ${user}!">

4.9 setting指令

該指令用於設置FreeMarker的運行環境,該指令的語法格式以下:<#setting name=value>,在這個格式中,name的取值範圍包含以下幾個:

locale:該選項指定該模板所用的國家/語言選項
number_format:指定格式化輸出數字的格式
boolean_format:指定兩個布爾值的語法格式,默認值是true,false
date_format,time_format,datetime_format:指定格式化輸出日期的格式
time_zone:設置格式化輸出日期時所使用的時區

4.10 macro , nested , return指令

macro能夠用於實現自定義指令,經過使用自定義指令,能夠將一段模板片斷定義成一個用戶指令,使用macro指令的語法格式以下:

<#macro name param1 param2 ... paramN>
    ...
    <#nested loopvar1, loopvar2, ..., loopvarN>
    ...
    <#return>
    ...
</#macro>

在上面的格式片斷中,包含了以下幾個部分:

name:name屬性指定的是該自定義指令的名字,使用自定義指令時能夠傳入多個參數
paramX:該屬性就是指定使用自定義指令時報參數,使用該自定義指令時,必須爲這些參數傳入值
nested指令:nested標籤輸出使用自定義指令時的中間部分
nested指令中的循環變量:這此循環變量將由macro定義部分指定,傳給使用標籤的模板
return指令:該指令可用於隨時結束該自定義指令.

看以下的例子:

<#macro book>   //定義一個自定義指令
j2ee
</#macro>
<@book />    //使用剛纔定義的指令

上面的代碼輸出結果爲:

j2ee

在上面的代碼中,可能很難看出自定義標籤的用處,由於咱們定義的book指令所包含的內容很是簡單,實際上,自定義標籤可包含很是多的內容,從而能夠實現更好的代碼複用.此外,還能夠在定義自定義指令時,爲自定義指令指定參數,看以下代碼:

<#macro book booklist>     //定義一個自定義指令booklist是參數
    <#list booklist as book>
       ${book}
    </#list>
</#macro>
<@book booklist=["spring","j2ee"] />   //使用剛剛定義的指令

上面的代碼爲book指令傳入了一個參數值,上面的代碼的輸出結果爲:

spring j2ee

不只如此,還能夠在自定義指令時使用nested指令來輸出自定義指令的中間部分,看以下例子:

<#macro page title>
<html>
<head>
   <title>FreeMarker示例頁面 - ${title?html}</title>
</head>
<body>
   <h1>${title?html}</h1>
   <#nested>      //用於引入用戶自定義指令的標籤體
</body>
</html>
</#macro>

上面的代碼將一個HTML頁面模板定義成一個page指令,則能夠在其餘頁面中如此page指令:

<#import "/common.ftl" as com>     //假設上面的模板頁面名爲common.ftl,導入頁面
<@com.page title="book list">
<u1>
<li>spring</li>
<li>j2ee</li>
</ul>
</@com.page >

從上面的例子能夠看出,使用macronested指令能夠很是容易地實現頁面裝飾效果,此外,還能夠在使用nested指令時,指定一個或多個循環變量,看以下代碼:

<#macro book>
<#nested 1>      //使用book指令時指定了一個循環變量值
<#nested 2>
</#macro>
<@book ;x> ${x} .圖書</@book >

當使用nested指令傳入變量值時,在使用該自定義指令時,就須要使用一個佔位符(如book指令後的;x).上面的代碼輸出文本以下:

1 .圖書    2 .圖書

nested指令中使用循環變量時,可使用多個循環變量,看以下代碼:

<#macro repeat count>
    <#list 1..count as x>     //使用nested指令時指定了三個循環變量
       <#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;

return指令用於結束macro指令,一旦在macro指令中執行了return指令,則FreeMarker不會繼續處理macro指令裏的內容,看以下代碼:

<#macro book>
spring
<#return>
j2ee
</#macro>
<@book />

上面的代碼輸出:

spring

j2ee位於return指令以後,不會輸出。

4.11 t, lt, rt 指令

語法:

<#t> 去掉左右空白和回車換行
<#lt> 去掉左邊空白和回車換行
<#rt> 去掉右邊空白和回車換行
<#nt> 取消上面的效果

4.12 指令總結

if, else, elseif
switch, case, default, break
list, break
include
Import
compress
escape, noescape
assign
global
setting
macro, nested, return
t, lt, rt, nt

5. 高級方法

5.1 自定義方法

自定義方法, 如:

${timer("yyyy-MM-dd H:mm:ss", x)}
${timer("yyyy-MM-dd ", x)}

在模板中除了能夠經過對象來調用方法外(${object.methed(args)})也能夠直接調用java實現的方法,java類必須實現接口TemplateMethodModel的方法exec(List args). 下面以把毫秒的時間轉換成按格式輸出的時間爲例子:

public class LongToDate implements TemplateMethodModel {
    
    public TemplateModel exec(List args) throws TemplateModelException {
        SimpleDateFormat mydate = new SimpleDateFormat((String) args.get(0)));
        return mydate.format(new Date(Long.parseLong((String)args.get(1)));
    }
}

LongToDate對象放入到數據模型中:

root.put("timer", new LongToDate());

ftl模板裏使用:

<#assign x = "123112455445">
${timer("yyyy-MM-dd H:mm:ss", x)}
${timer("yyyy-MM-dd ", x)}

輸出結果:

2001-10-12 5:21:12
2001-10-12

5.2 自定義 Transforms

實現自定義的<@transform>文本或表達式</@transform >的功能,容許對中間的最終文本進行解析轉換

例子:實現<@upcase>str</@upcase >str轉換成STR的功能.

代碼以下:

import java.io.*;
import java.util.*;
import freemarker.template.TemplateTransformModel;
public class UpperCaseTransform implements TemplateTransformModel {
    public Writer getWriter(Writer out, Map args) {
        return new UpperCaseWriter(out);
    }
    private class UpperCaseWriter extends Writer {
       
        private Writer out;
           
        UpperCaseWriter (Writer out) {
            this.out = out;
        }
        public void write(char[] cbuf, int off, int len)
                throws IOException {
            out.write(new String(cbuf, off, len).toUpperCase());
        }
        public void flush() throws IOException {
            out.flush();
        }
        public void close() {
        }
    }
}

而後將此對象put到數據模型中, 以下所示:

root.put("upcase", new UpperCaseTransform());

view(ftl)頁面中能夠以下方式使用:

<@upcase>
hello world
</@upcase >

打印輸出:

HELLO WORLD

寫在最後

歡迎關注喜歡、和點贊後續將推出更多的工具集教程,敬請期待。
歡迎關注個人微信公衆號獲取更多更全的學習資源,視頻資料,技術乾貨!
歡迎掃碼關注

公衆號回覆「學習」,拉你進程序員技術討論羣乾貨資源第一時間分享。

公衆號回覆「視頻」,領取800GJava視頻學習資源。
java學習全套
820G資源

公衆號回覆「全棧」,領取1T前端Java產品經理微信小程序Python等資源合集大放送。
全棧資料
java
python
機器學習
產品經理
接近1T資源

公衆號回覆「慕課」,領取1T慕課實戰學習資源。
慕課實戰大全
php
python
測試
後端
前端
前端
微信
1061G資源

公衆號回覆「實戰」,領取750G項目實戰學習資源。
先後端實戰項目
750實戰資源

公衆號回覆「面試」,領取8G面試實戰學習資源。
JAVA面試實戰視頻

傳智面試講解
8G面試資源

相關文章
相關標籤/搜索