freeMarker模板語言參考:指令參考

指令參考

Alphabetical index(按字母順序搜索)

中文官方參考手冊

一.assign

寫法:

<#assign name1=value1 name2=value2 ... nameN=valueN>
或
<#assign same as above... in namespacehash>
或
<#assign name>
  capture this
</#assign>
或
<#assign name in namespacehash>
  capture this
</#assign>
  • name:變量的名字。 它不是表達式。而它可以寫作是字符串,如果變量名包含保留字符這是很有用的, 比如 <#assign “foo-bar” = 1>。 請注意這個字符串沒有展開插值(如"${foo}"); 如果需要賦值一個動態創建的名字,那麼不得不使用 這個技巧。
  • =:賦值操作符。 它也可以是一個簡寫的賦值操作符(從 FreeMarker 2.3.23 版本開始): ++,–, +=,-=, *=,/= 或 %=。比如 <#assign x++> 和 <#assign x = x + 1> 是一樣的,並且 <#assign x += 2> 和 <#assign x = x + 2> 是相同的。 請注意, ++ 通常意味着算術加法 (對於非數字將會失敗),不像 + 或 += 可以進行字符連接等重載操作。
  • value: 存儲的值。是表達式。
  • namespacehash:(通過 import) 爲命名空間創建的哈希表。是表達式

描述

使用該指令你可以創建一個新的變量, 或者替換一個已經存在的變量。注意僅僅頂級變量可以被創建/替換 (也就是說你不能創建/替換 some_hash.subvar, 除了 some_hash)。

應用

1.變量 seq 存儲一個序列

<#assign seq = ["foo", "bar", "baz"]>

2.變量 x 中存儲增長的數字

<#assign x++>
或者是
<#assign x=x+1>

3.可以使用一個 assign 標記來進行多次定義。比如這個會做上面兩個例子中相同的事情:

<#assign
  seq = ["foo", "bar", "baz"]
  x++
>

4.assign 指令在命名空間中創建變量(在assign之前引入import一個文件,然後在assign中調用import文件)
通常它在當前的命名空間 (也就是和標籤所在模板關聯的命名空間)中創建變量。
但如果你是用了 in namespacehash, 那麼你可以用另外一個 命名空間 來創建/替換變量。
比如,這裏你在命名空間中 /mylib.ftl 創建/替換了變量 bgColor:

<#import "/mylib.ftl" as my>
<#assign bgColor="red" in my>

5.assign 的極端使用是當它捕捉它的開始標記和結束標記中間生成的輸出時。
也就是說,在標記之間打印的東西將不會在頁面上顯示, 但是會存儲在變量中

<#macro myMacro>foo</#macro>
<#assign x>
  <#list 1..3 as n>
    ${n} <@myMacro />
  </#list>
</#assign>
Number of words: ${x?word_list?size}
${x}

在這裏插入圖片描述
請注意,你不應該使用它來往字符串中插入變量

錯誤寫法:
<#assign x>Hello ${user}!</#assign> <#-- BAD PRACTICE! -->
正確寫法:
<#assign x="Hello ${user}!">
 	  <#assign x>
      <#list ["星期一", "星期二", "星期三", "星期四", "星期五", 
      "星期六", "星期天"]as n>
      ${n}
      </#list>
      </#assign>
      ${x}

在這裏插入圖片描述


二.attempt, recover

1.寫法:

<#attempt>
  attempt block
<#recover>
  recover block
</#attempt>
  • attempt block:任意內容的模板塊。這是會被執行的, 但是如果期間發生了錯誤,那麼這塊內容的輸出將會回滾, 之後 recover block 就會被執行。
  • recover block: 任意內容的模板塊。 這個僅在 attempt block 執行期間發生錯誤時被執行。你可以在這裏打印錯誤信息或其他操作
  • recover 是強制的。 attempt/recover 可以嵌套在其他 attempt block 或 recover block中

描述

如果你想讓頁面成功輸出內容,儘管它在頁面特定位置發生錯誤也這樣, 那麼這些指令就是有用的。
如果一個錯誤在 attempt block 執行期間發生, 那麼模板執行就會中止,但是 recover block 會代替 attempt block 執行。
如果在 attempt block 執行期間沒有發生錯誤, 那麼 recover block 就會忽略
類似try-catch 拋出異常

Primary content
<#attempt>
  Optional content: ${thisMayFails}
<#recover>
  Ops! The optional content is not available.
</#attempt>
Primary content continued

如果 thisMayFails 變量不存在,將會輸出:
在這裏插入圖片描述
如果 thisMayFails 變量存在而且值爲 123,將會輸出:
在這裏插入圖片描述

三.compress

寫法:

<#compress>
  ...
</#compress>

描述

當你使用了對空白不敏感的格式(比如HTML或XML) 時壓縮指令對於移除多餘的 空白 是很有用的。
它捕捉在指令體(也就是在開始標籤和結束標籤中)中生成的內容, 然後縮小所有不間斷的空白序列到一個單獨的空白字符。
如果被替代的序列包含換行符或是一段空間,那麼被插入的字符也會是一個 換行符。 開頭和結尾的不間斷的空白序列將會完全被移除

  <#assign x = "    moo  \n\n   ">
    (<#compress>
    1 2  3   4    5
    ${moo}
    test only

    I said, test only

    </#compress>)

在這裏插入圖片描述

<#compress>...</#compress>:消除空白行。 

<@compress single_line=true>...</@compress>
將輸出壓縮爲一行。都需要包裹所需文檔
<#t> // 去掉左右空白和回車換行 

<#lt>// 去掉左邊空白和回車換行 

<#rt>// 去掉右邊空白和回車換行 

<#nt>// 取消上面的效果

四.escape, noescape

<#escape identifier as expression>
  ...
  <#noescape>...</#noescape>
  ...
</#escape>

描述

當你使用escape指令包圍模板中的一部分時,在塊中出現的插值 (${…}) 會和轉義表達式自動結合。這是一個避免編寫相似表達式的很方便的方法。
它不會影響在字符串形式的插值(比如在 <#assign x = “Hello ${user}!”>)。而且,它也不會影響數值插值 (#{…})

<#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}

請注意,它和你在指令中用什麼樣的標識符無關 - 它僅僅是作爲一個轉義表達式的正式參數。

當在調用宏或者 include 指令時, 理解 在模板文本 中轉義僅僅對出現在 <#escape …> 和 </#escape> 中的插值起作用是很重要的。
也就是說,它不會轉義文本中 <#escape …> 之前的東西或 </#escape> 之後的東西, 也不會從 escape 的部分中來調用

<#assign x = "<test>">
<#macro m1>
  m1: ${x}
</#macro>
<#escape x as x?html>
  <#macro m2>m2: ${x}</#macro>
  ${x}
  <@m1/>
</#escape>
${x}
<@m2/>

在這裏插入圖片描述
有時需要暫時爲一個或兩個在轉義區塊中的插值關閉轉義。你可以通過關閉, 過後再重新開啓轉義區塊來達到這個功能,但是那麼你不得不編寫兩遍轉義表達式。 你可以使用非轉義指令來替代

<#escape x as x?html>
  From: ${mailMessage.From}
  Subject: ${mailMessage.Subject}
  <#noescape>Message: ${mailMessage.htmlFormattedBody}</#noescape>
  ...
</#escape>
  和這個是等同的:

  From: ${mailMessage.From?html}
  Subject: ${mailMessage.Subject?html}
  Message: ${mailMessage.htmlFormattedBody}
  ...

五.flush

寫法:

<#flush>

描述
當 FreeMarker 生成輸出時,它通常不會立即發送到最終接收端 (比如web瀏覽器或最終的文件),而是會將內容累積在緩衝區,發送一個大塊的內容。
緩衝區的精確規則不是由 FreeMarker 決定的,而是由嵌入的軟件決定的。 將緩衝區中累積的內容發送出去稱爲沖洗。
儘管沖洗是自動發生的, 有時你想在模板處理時的一點強制執行,這就是 flush 指令要做的。
如果需要在確定之處用到它,這是由程序員決定的,而不是設計師
請注意, flush 告訴嵌入的軟件我們想要衝洗, 那麼也許就會決定忽略該請求。這不由 FreeMarker 之手控制
沖洗簡單調用當前使用 java.io.Writer 實例的 flush() 方法。 整個緩衝區和沖洗機制由 Writer(就是傳遞給 Template.process 方法的參數)實現; FreeMarker不用來處理它


## 六.ftl 寫法:
<#ftl param1=value1 param2=value2 ... paramN=valueN>
  • param1, param2 等: 參數的名字,不是表達式。允許的參數有: encoding, strip_whitespace, strip_text 等
  • value1, value2 等: 參數的值。必須是一個常量表達式(如 true, 或 “ISO-8859-5”,或 {x:1, y:2})。它不能用變量

描述

告訴 FreeMarker 和其他工具關於模板的信息, 而且幫助程序員來自動檢測一個文本文件是否是 FTL 文件。
該指令, 如果存在,必須是模板的第一句代碼。該指令前的任何 空白 將被忽略。 該指令的老式語法(#-less)格式是不支持

參數:

  • encoding: 使用它,你可以在模板文件本身中爲模板指定編碼方式(字符集)
  • strip_whitespace: 這將開啓/關閉 空白剝離。 合法的值是布爾值常量 true 和 false (爲了向下兼容,字符串 “yes”,“no”, “true”,“false” 也是可以的)。 默認值(也就是當你不使用這個參數時)是依賴於程序員對 FreeMarker 的配置, 但是對新的項目還應該是 true
  • strip_text:當開啓它時, 當模板被解析時模板中所有頂級文本被移除。這個不會影響宏,指令,或插值中的文本。 合法值是布爾值常量 true 和 false
  • strict_syntax:這會開啓/關閉"嚴格的語法"。 合法值是布爾值常量 true 和 false (爲了向下兼容,字符串 “yes”,“no”, “true”,“false” 也是可以的)。 默認值(也就是當你不使用這個參數時)是依賴於程序員對 FreeMarker 的配置, 但是對新的項目還應該是 true。
  • ns_prefixes:這是關聯結點命名空間前綴的哈希表。
  • attributes:這是關聯模板任意屬性(名-值對)的哈希表。 屬性的值可以是任意類型(字符串,數字,序列等)。

該指令也決定模板是否使用尖括號語法(比如 <#include ‘foo.ftl’>)或 方括號語法 (如 [#include ‘foo.ftl’])。簡單而言, 該指令使用的語法將會是整個模板使用的語法, 而不管 FreeMarker 是如何配置的。


七.function, return

寫法:

<#function name param1 param2 ... paramN>
  ...
  <#return returnValue>
  ...
</#function>
  • name:方法變量的名稱(不是表達式)
  • param1, param2 等: 局部變量的名稱, 存儲參數的值(不是表達式),在 = 號後面和默認值 (是表達式)是可選的。
  • paramN,最後一個參數, 可以可選的包含一個尾部省略(…), 這就意味着宏接受可變的參數數量。局部變量 paramN 將是額外參數的序列。
  • returnValue: 計算方法調用值的表達式。
  • return 指令可以在 <#function …> 和 </#function> 之間被用在任意位置和任意次數。
  • 沒有默認值的參數必須在有默認值參數 (paramName=defaultValue) 之前

描述

創建一個方法變量(在當前命名空間中,如果你知道命名空間的特性)。
這個指令和 macro 指令 的工作方式一樣,除了 return 指令必須有一個參數來指定方法的返回值,而且視圖寫入輸出的將會被忽略。
如果到達 </#function> (也就是說沒有 return returnValue), 那麼方法的返回值就是未定義變量

應用

1.創建一個方法來計算兩個數的平均值

官方文檔:
<#function avg x y>
  <#return (x + y) / 2>
</#function>
${avg(10, 20)}

2.創建一個方法來計算多個數的平均值

平均值方法
<#function avg nums...>
  <#local sum = 0>
  <#list nums as num>
    <#local sum = sum + num>
  </#list>
  <#if nums?size != 0>
    <#return sum / nums?size>
  </#if>
</#function>
${avg(10, 20)}
${avg(10, 20, 30, 40)}
${avg()!"N/A"}

在這裏插入圖片描述


## 八.global 1.寫法:
<#global name=value>
或
<#global name1=value1 name2=value2 ... nameN=valueN>
或
<#global name>
  capture this
</#global>
  • name:變量的名稱。 它不是表達式。但它可以被寫作是字符串形式,如果變量名包含保留字符這是很有用的, 比如 <#global “foo-bar” = 1>。 注意這個字符串沒有擴展插值(如 “${foo}”)。
  • =:賦值操作符,也可以簡寫的賦值操作符之一 (++, +=,等…),和 assign 指令 相似
  • value:存儲的值,是表達式。

描述

該指令和 assign 相似, 但是被創建的變量在所有的 命名空間 中都可見, 但又不會存在於任何一個命名空間之中。精確地說,正如你會創建 (或替換)一個數據模型變量。因此,這個變量是全局的。如果在數據模型中, 一個相同名稱的變量存在的話,它會被使用該指令創建的變量隱藏。 如果在當前的命名空間中,一個相同名稱的變量存在的話, 那麼會隱藏由 global 指令創建的變量。

例如,用 <#global x = 1> 創建一個變量, 那麼在所有命名空間中 x 都可見, 除非另外一個稱爲 x 的變量隱藏了它 (比如你已經用 <#assign x = 2> 創建了一個變量)。 這種情形下,你可以使用 特殊變量 globals,比如 ${.globals.x}。請注意, 使用 globals 你看到所有全局可訪問的變量; 不但由 global 指令創建的變量,而且是數據模型中的變量。

自定義JSP標記的用戶請注意:用這個指令創建的變量集合和JSP頁面範圍對應。 這就意味着,如果自定義JSP標記想獲得一個頁面範圍的屬性(page-scope bean), 在當前命名空間中一個相同名稱的變量,從JSP標記的觀點出發,將不會隱藏。
利用這個語法給變量賦值,那麼這個變量在所有的namespace中是可見的,如果這個變量被當前的assign語法覆蓋如<#global x=2><#assign x=1>在當前頁面裏x=2將被隱藏,或者通過${.globals.x} 來訪問


九.if, else, elseif

1.寫法:

<#if condition>
  ...
<#elseif condition2>
  ...
<#elseif condition3>
  ...
...
<#else>
  ...
</#if>
  • condition, condition2, 等:將被計算成布爾值的表達式
  • elseif 和 else 是可選的

描述

你可以使用 if, elseif 和 else 指令來條件判斷是否越過模板的一個部分。
condition 必須計算成布爾值, 否則錯誤將會中止模板處理。
elseif 和 else 必須出現在 if 內部 (也就是,在 if 的開始標籤和結束標籤之間)。
if 中可以包含任意數量的 elseif(包括0個) 而且結束時 else 是可選的。

應用

1.只有 if 沒有 elseif 和 else:

<#if x == 1>
  x is 1
</#if>

2.只有 if 沒有 elseif 但是有 else

<#if x == 1>
  x is 1
<#else>
  x is not 1
</#if>

3.有 if 和兩個 elseif 但是沒有 else

<#if x == 1>
  x is 1
<#elseif x == 2>
  x is 2
<#elseif x == 3>
  x is 3
</#if>

4.有 if 和三個 elseif 還有 else:

<#if x == 1>
  x is 1
<#elseif x == 2>
  x is 2
<#elseif x == 3>
  x is 3
<#elseif x == 4>
  x is 4
<#else>
  x is not 1 nor 2 nor 3 nor 4
</#if>

5.嵌套 if 指令

<#if x == 1>
  x is 1
  <#if y == 1>
    and y is 1 too
  <#else>
    but y is not
  </#if>
<#else>
  x is not 1
  <#if y < 0>
    and y is less than 0
  </#if>
</#if>

十.import

寫法:

<#import path as hash>
  • path:模板的路徑。 這是一個算作是字符串的表達式。(換句話說,它不是一個固定的字符串, 它可以是這樣的一些東西,比如,profile.baseDir + “/menu.ftl”。)
  • hash: 訪問命名空間的哈希表變量不帶引號的名字。不是表達式。 (如果要引入動態創建的名字,那麼就不得不使用 這個技巧。)

描述

引入一個庫。也就是說,它創建一個新的空命名空間, 然後在那個命名空間中執行給定 path 參數中的模板, 所以模板用變量(宏,函數等)填充命名空間。 然後使得新創建的命名空間對哈希表的調用者可用。 這個哈希表變量將會在命名空間中,由 import (就像你可以用 assign 指令來創建一樣。) 的調用者被創建成一個普通變量,名字就是 hash 參數給定的。

如果你用同一個 path 多次調用 import,它會創建命名空間, 但是隻運行第一次 import 的調用。 後面的調用僅僅創建一個哈希表變量,你只是通過它來訪問 同一個 命名空間。

由引入的模板打印的輸出內容將會被忽略 (不會在包含它的地方被插入)。模板的執行是來用變量填充命名空間, 而不是寫到輸出中

<#import "/libs/mylib.ftl" as my>

<@my.copyright date="1999-2002"/>

path 參數可以是一個相對路徑,比如 “foo.ftl” 和 “…/foo.ftl”,或者是像 “/foo.ftl” 一樣的絕對路徑。 相對路徑是相對於使用 import 指令模板的目錄。 絕對路徑是程序員配置 FreeMarker 時定義的相對於根路徑 (通常指代"模板的根目錄")的路徑。

通常使用/(斜槓)來分隔路徑組成, 而不是(反斜槓)。如果你從你本地的文件系統中加載模板, 那麼它使用反斜槓(比如在Windows環境下),FreeMarker 將會自動轉換它們。

像 include 指令一樣,獲得機制 和 本地化查找 也可以用來解決路徑問題


十一.include

1.寫法:

<#include path>
或
<#include path options>
  • path: 要包含文件的路徑;一個算作是字符串的表達式。(用其他話說, 它不用是一個固定的字符串,它也可以是像 profile.baseDir + "/menu.ftl"這樣的東西。)
  • options: 一個或多個這樣的選項: encoding=encoding, parse=parse

options:

  1. encoding: 算作是字符串的表達式
  2. parse: 算作是布爾值的表達式(爲了向下兼容,也接受一部分字符串值)
  3. ignore_missing: 算作是布爾值的表達式

描述

可以使用它在你的模板中插入另外一個 FreeMarker 模板文件 (由 path 參數指定)。 被包含模板的輸出格式是在 include 標籤出現的位置插入的。 被包含的文件和包含它的模板共享變量,就像是被複制粘貼進去的一樣。 include 指令不能由被包含文件的內容所替代, 它只是當 FreeMarker 每次在模板處理期間到達 include 指令時處理被包含的文件。所以對於如果 include 在 list 循環之中的例子, 你可以爲每個循環週期內指定不同的文件名

應用

假設 /common/copyright.ftl 包含:

Copyright 2001-2002 ${me}<br>
All rights reserved.
<#assign me = "Juila Smith">
<h1>Some test</h1>
<p>Yeah.
<hr>
<#include "/common/copyright.ftl">

在這裏插入圖片描述

十二.list, else, items, sep, break

1.1寫法一:

<#list sequence as item>
    Part repeated for each item
<#else>
    Part executed when there are 0 items
</#list>
  • else 部分是可選的, 而且僅僅從 FreeMarker 2.3.23 版本開始支持。
  • sequence: 將我們想要迭代的項,算作是序列或集合的表達式
  • item: 循環變量 的名稱 (不是表達式)
  • 在標籤之間的多個 “parts” 可以是任意的FTL (包括嵌套的 list)

1.2寫法二:

<#list sequence>
    Part executed once if we have more than 0 items
    <#items as item>
        Part repeated for each item
    </#items>
    Part executed once if we have more than 0 items
<#else>
    Part executed when there are 0 items
</#list>

描述

最簡形式

1.假設 users 包含 [‘Joe’, ‘Kate’, ‘Fred’] 序列

	<#assign users= ['Joe', 'Kate', 'Fred']>
    <#list users as user>
        <p>${user}
    </#list>

在這裏插入圖片描述
list 指令執行在 list 開始標籤和 list 結束標籤 ( list 中間的部分) 之間的代碼,
對於在序列(或集合)中每個值指定爲它的第一個參數。
對於每次迭代,循環變量(本例中的 user)將會存儲當前項的值。

循環變量(user) 僅僅存在於 list 標籤體內。
而且從循環中調用的宏/函數不會看到它(就像它只是局部變量一樣)。

else 指令
當沒有迭代項時,才使用 else 指令, 可以輸出一些特殊的內容而不只是空在那裏

<#assign users=[]>
    <#list users as user>
    <p>${user}
    <#else>
    <p>No users
    </#list>

該輸出和之前示例是相同的,除了當 users 包含0項時:
在這裏插入圖片描述
請注意,循環變量 (user) 在 else 標籤和 list 結束標籤中間不存在, 因爲那部分不是循環中的部分。

else 必須是真的在 (也就是在源代碼中) list 指令體內部。也就是說, 不能將它移出到宏或包含的模板中

items 指令
如果不得不在第一列表項之前或在最後一個列表項之後打印一些東西, 那麼就要使用 items 指令,但至少要有一項。典型的示例爲

	<#assign users= ['Joe', 'Kate', 'Fred']>
    <#list users>
    <ul>
        <#items as user>
        <li>${user}</li>
        </#items>
    </ul>
    </#list>

在這裏插入圖片描述
也就是說,當 list 指令沒有 as item 參數, 如果只有一個迭代項,指令體中的代碼僅僅執行一次,否則就不執行。
必須內嵌的 items 指令體會對每個迭代項執行, 那麼 items 指令使用 as item 定義循環變量,而不是 list

有 items 的 list 指令也可以有 else 指令:

<#assign users= ['Joe', 'Kate', 'Fred']>
<#list users>
  <ul>
    <#items as user>
      <li>${user}</li>
    </#items>
  </ul>
<#else>
  <p>No users
</#list>
  • 解析器會檢查沒有 as item 參數的 list 通常會有嵌入的 items 指令,該 items 指令通常會有一個包圍的 list,它沒有 as item 參數。當模板解析時就會檢查,而不是當模板執行的時候。因此,這些規則也適用於FTL源代碼本身, 所以不能將 items 移出到宏或者被包含的模板中。
  • list 可以有多個 items 指令, 但是隻有一個允許執行(直到不離開或重新進入包圍的 list 指令); 之後試圖調用 items 會發生錯誤。所以多個 items 可以用於不同的 if-else 分支中去,但不能迭代兩次。
  • items 指令不能有它自己的嵌入 else 指令,只能被包含的 list 可以有。
  • 循環變量 (user) 僅僅存在於 items 指令體內部。

sep 指令
當不得不顯示介於每個迭代項(但不能在第一項之前或最後一項之後) 之間的一些內容時,可以使用 sep。

<#assign users= ['Joe', 'Kate', 'Fred']>
<#list users as user>${user}<#sep>, </#list>

在這裏插入圖片描述
上面的 <#sep>, </#list> 是 <#sep>, </#sep></#list> 的簡寫; 如果將它放到被包含的指令關閉的位置時,sep 結束標籤可以忽略。下面的示例中,就不能使用該簡寫 (HTML標籤不會結束任何代碼,它們只是 FreeMarker 輸出的原生文本):

<#assign users= ['Joe', 'Kate', 'Fred']>
<#list users as user>
  <div>
    ${user}<#sep>, </#sep>
  </div>
</#list>

sep 是編寫 <#if item?has_next>…</#if> 的方便形式,有 list 或 items 循環變量時,它就可以使用,並且不限次數。而且, 也可以有任意的 FTL 作嵌入的內容。

break 指令
可以使用 break 指令在迭代的任意點退出

<#list 1..10 as x>
  ${x}
  <#if x == 3>
    <#break>
  </#if>
</#list>

在這裏插入圖片描述
break 指令可以放在 list 中的任意位置,直到有 as item 參數, 否則,可以放在 items 指令中的任意位置。 如果 break 在 items 內部, 那麼就只能從 items 開始時存在,而不能從 list 開始時存在。通常來說,break 將僅存在於爲每個迭代項調用的指令體中,而且只能存在於這樣的指令中。 例如不能在 list 的 else 部分使用 break,除非 list 內嵌到了其它 可以 break 的指令中。

像 else 和 items, break 只能在指令體內部使用,而不能移出到宏或被包含的模板中。

訪問迭代狀態
循環變量內建函數 就是訪問當前迭代狀態的最佳方式
使用 counter 和 item_parity 循環變量內建函數(在 循環變量內建函數參考 中查看它們全部)

 	<#assign users= ['Joe', 'Kate', 'Fred']>
    <#list users>
    <table border=4 cellspacing=0 cellpadding=4>
        <#items as user>
        <tr class="${user?item_parity}Row">
            <td>${user?counter}</td>
            <td>${user_index + 1}</td>
            <td>${user}</td>
        </#items>
    </table>
    </#list>
    所以在上面的示例中,可以將 ${user?counter} 替換爲 ${user_index + 1}

在這裏插入圖片描述
相互嵌套循環
list 或 items 可以包含更多 list:

	<#list 1..2 as i>
        <#list 2..5 as j>
            i: ${i},j:${j} 
            (${i},${j})<br>
        </#list>
    </#list>

在這裏插入圖片描述

	<#list 1..2 as i>
        Outer: ${i}
        <#list 10..12 as i>
            Inner: ${i}
        </#list>
        Outer again: ${i}<br>
    </#list>

在這裏插入圖片描述


## 十三.local 寫法:
<#local name=value>
或
<#local name1=value1 name2=value2 ... nameN=valueN>
或
<#local name>
  capture this
</#local>
  • name: 在root中局部對象的名稱。它不是一個表達式。但它可以被寫作是字符串形式, 如果變量名包含保留字符,這是很有用的,比如 <#local “foo-bar” = 1>。 請注意,這個字符串沒有擴展插值(如"${foo}")。
  • =:賦值操作符,也可以簡寫的賦值操作符之一 (++,+= 等…),和 the assign 指令 相似。
  • value: 存儲的值,是表達式。

描述

它和 assign 指令 類似,但是它創建或替換局部變量。 這僅僅在宏和方法的內部定義纔會有作用。


十四.macro, nested, return

寫法:

<#macro name param1 param2 ... paramN>
  ...
  <#nested loopvar1, loopvar2, ..., loopvarN>
  ...
  <#return>
  ...
</#macro>
  • name: 宏變量的名稱,它不是表達式。和 頂層變量 的語法相同,比如 myMacro 或 my-macro。 然而,它可以被寫成字符串的形式,如果宏名稱中包含保留字符時,這是很有用的, 比如 <#macro “foo~bar”>…。 注意這個字符串沒有擴展插值(如 “${foo}”)。
  • param1, param2,等…: 局部變量 的名稱,存儲參數的值 (不是表達式),在 = 號後面和默認值(是表達式)是可選的。 默認值也可以是另外一個參數,比如 <#macro section title label=title>。參數名稱和 頂層變量 的語法相同,所以有相同的特性和限制。
  • paramN, 最後一個參數,可能會有三個點(…), 這就意味着宏接受可變數量的參數,不匹配其它參數的參數可以作爲最後一個參數 (也被稱作籠統參數)。當宏被命名參數調用, paramN 將會是包含宏的所有未聲明的鍵/值對的哈希表。當宏被位置參數調用, paramN 將是額外參數的序列。 (在宏內部,要查找參數,可以使用 myCatchAllParam?is_sequence。)
  • loopvar1, loopvar2等…: 可選的,循環變量 的值, 是 nested 指令想爲嵌套內容創建的。這些都是表達式
  • return 和 nested 指令是可選的,而且可以在 <#macro …> 和 </#macro> 之間被用在任意位置和任意次數。
  • 沒有默認值的參數必須在有默認值參數 (paramName=defaultValue) 之前。

描述

創建一個宏變量(在當前命名空間中,如果你知道命名空間的特性)
宏變量存儲模板片段(稱爲宏定義體)可以被用作 自定義指令。 這個變量也存儲自定義指令的被允許的參數名。當你將這個變量作爲指令時, 你必須給所有參數賦值,除了有默認值的參數。 默認值當且僅當你調用宏而不給參數賦值時起作用。

應用

變量會在模板開始時被創建;而不管 macro 指令放置在模板的什麼位置。因此,這樣也可以:

<#-- call the macro; the macro variable is already created: -->
<@test/>
...

<#-- create the macro variable: -->
<#macro test>
  Test text
</#macro>

然而,如果宏定義被插在 include 指令中, 它們直到 FreeMarker 執行 include 指令時纔會可用。

例如:沒有參數的宏

<#macro test>
  Test text
</#macro>
<#-- call the macro: -->
<@test/>

在這裏插入圖片描述
示例:有參數的宏

<#macro test foo bar baaz>
  Test text, and the params: ${foo}, ${bar}, ${baaz}
</#macro>
<#-- call the macro: -->
<@test foo="a" bar="b" baaz=5*5-2/>

在這裏插入圖片描述
示例:有參數和默認值參數的宏

<#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"/>

在這裏插入圖片描述
示例:更爲複雜的宏

<#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"/>

在這裏插入圖片描述
示例:支持多個參數和命名參數的宏

<#macro img src extra...>
  <img src="/context${src?html}" 
  <#list extra?keys as attr>
    ${attr}="${extra[attr]?html}"
  </#list>
  >
</#macro>
<@img src="/images/test.png" width=100 height=50 alt="Test"/>

在這裏插入圖片描述
示例:支持多個位置參數的宏,不管是否使用命名或位置參數傳遞

<#macro m a b ext...>
  a = ${a}
  b = ${b}
  <#if ext?is_sequence>
    <#list ext as e>
      ${e?index} = ${e}
    </#list>
  <#else>
    <#list ext?keys as k>
      ${k} = ${ext[k]}
    </#list>
  </#if>
</#macro>

<@m 1 2 3 4 5 />

<@m a=1 b=2 c=3 d=4 e=5 data\-foo=6 myns\:bar=7 />

在這裏插入圖片描述
nested
nested 指令執行自定義指令開始和結束標籤中間的模板片段。 嵌套的片段可以包含模板中任意合法的內容:插值,指令等…它在上下文環境中被執行, 也就是宏被調用的地方,而不是宏定義體的上下文中。
因此,比如, 你不能看到嵌套部分的宏的局部變量。
如果你沒有調用 nested 指令, 自定義指令開始和結束標記中的部分將會被忽略

<#macro do_twice>
  1. <#nested>
  2. <#nested>
</#macro>
<@do_twice>something</@do_twice>

在這裏插入圖片描述
nested 指令可以對嵌套內容創建循環變量。例如:

<#macro do_thrice>
  <#nested 1>
  <#nested 2>
  <#nested 3>
</#macro>
<@do_thrice ; x>
  ${x} Anything.
</@do_thrice>

在這裏插入圖片描述
更爲複雜的示例:

<#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>

在這裏插入圖片描述
return
使用 return 指令, 你可以在任意位置留下一個宏或函數定義。比如:

<#macro test>
  Test text
  <#return>
  Will not be printed.
</#macro>
<@test/>

在這裏插入圖片描述


## 十五.noparse 寫法:
<#noparse>
  ...
</#noparse>

描述

FreeMarker 不會在這個指令體中間尋找FTL標籤, 插值和其他特殊的字符序列,除了noparse的結束標記。

Example:
--------

<#noparse>
  <#list animals as animal>
  <tr><td>${animal.name}<td>${animal.price} Euros
  </#list>
</#noparse>

在這裏插入圖片描述


## 十六.nt 寫法:
<#nt>

描述

“不要削減”。該指令禁用行中出現的 剝離空白。 它也關閉其他同一行中出現的削減指令(t, rt,lt的效果)。


## 十七.setting 寫法:
<#setting name=value>
  • name: 設置的名稱。不是表達式!
  • value: 設置的新值,是表達式。

描述

爲進一步的處理而設置。設置是影響 FreeMarker 行爲的值。 新值僅僅在被設置的模板處理時出現,而且不觸碰模板本身。 設置的初始值是由程序員設定的

比如:假設初始化的模板本地化是 de_DE (德國)。那麼:

${1.2}
<#setting locale="en_US">
${1.2}
因爲德國人使用逗號作爲小數分隔符,而美國人使用點。

在這裏插入圖片描述


十七.stop

寫法:

<#stop>
或
<#stop reason>

reason: 關於終止原因的信息化消息。是表達式,被算做是字符串。

描述

中止模板處理,給出(可選的)錯誤消息。 不要在普通情況下對結束模板處理使用! FreeMarker 模板的調用者會將它視爲失敗的模板呈現, 而不是普通完成的。


十八.switch, case, default, break

寫法:

<#switch value>
  <#case refValue1>
    ...
    <#break>
  <#case refValue2>
    ...
    <#break>
  ...
  <#case refValueN>
    ...
    <#break>
  <#default>
    ...
</#switch>
  • value, refValue1,等: 表達式將會計算成相同類型的標量。
  • break 和 default 是可選的。

描述

這個指令的用法是不推薦的,因爲向下通過的行爲容易出錯。使用 elseif來代替, 除非你想利用向下通過這種行爲。

Switch 被用來選擇模板中的一個片段,如何選擇依賴於表達式的值

<#switch animal.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>

當它選擇一個 case 指令後,它就會繼續處理其中的內容, 直到遇到 break 指令。也就是它遇到另外一個 case 指令或 <#default> 標記時也不會自動離開 switch 指令

<#switch x>
  <#case 1>
    1
  <#case 2>
    2
  <#default>
    d
</#switch>

如果 x 是 1,它會打印1 2 d;如果 x 是 2,那麼就會打印2 d;如果 x 是 3,那麼就會打印d。這就是前面提到的向下通過行爲。 break 標記指示 FreeMarker 直接略過剩下的 switch 代碼段


十九.t, lt, rt

寫法:

<#t>

<#lt>

<#rt>

描述

這些指令,指示FreeMarker去忽略標記中行的特定的空白:

  • t (整體削減):忽略本行中首和尾的所有空白。

  • lt (左側削減):忽略本行中首部所有的空白。

  • rt (右側削減):忽略本行中尾部所有的空白。

這裏:

“首部空白” 表示本行所有空格和製表符 (和其他根據 UNICODE 中的空白字符,除了換行符) 在第一個非空白字符之前。

“尾部空白” 表示本行所有的空格和製表符 (和其他根據 UNICODE 中的空白字符,除了換行符) 在最後一個非空白字符之後,還有 行末尾的換行符。

--
  1 <#t>
  2<#t>
  3<#lt>
  4
  5<#rt>
  6
--

在這裏插入圖片描述
這些指令在行內的放置不重要。也就是說,不管你是將它們放在行的開頭, 或是行的末尾,或是在行的中間,效果都是一樣的。


二十.User-defined directive (<@…>)

寫法:

<@user_def_dir_exp param1=val1 param2=val2 ... paramN=valN/>
(注意 XML 風格, / 在 > 之前)  
或如果需要循環變量 (更多細節...)
<@user_def_dir_exp 
param1=val1 param2=val2 ... paramN=valN ; lv1, lv2, ..., lvN/>

或和上面兩個相同但是使用結束標籤:

<@user_def_dir_exp ...>
  ...
</@user_def_dir_exp>
或
<@user_def_dir_exp ...>
  ...
</@>

或和上面的相同但是使用位置參數傳遞 :

<@user val1, val2, ..., valN/>
等...
  • user_def_dir_exp: 表達式算作是自定義指令(比如宏),將會被調用。
  • param1, param2等…: 參數的名稱,它們 不是 表達式。
  • val1, val2等…: 參數的值,它們 是 表達式。
  • lv1, lv2等…: 循環變量 的名稱, 它們 不是 表達式。

描述

這將調用用戶自定義指令,比如宏。參數的含義, 支持和需要的參數的設置依賴於具體的自定義指令。
示例1:調用存儲在變量 html_escape 中的指令:

<@html_escape>
  a < b
  Romeo & Juliet
</@html_escape>

在這裏插入圖片描述
示例2:調用有參數的宏:

<@list items=["mouse", "elephant", "python"] title="Animals"/>
...
<#macro list title items>
  <p>${title?cap_first}:
  <ul>
    <#list items as x>
      <li>${x?cap_first}
    </#list>
  </ul>
</#macro>

在這裏插入圖片描述
結束標籤:

你可以在 結束標籤 中忽略 user_def_dir_exp。 也就是說,你可以寫 </@> 來替代 </@anything>。 這個規則當表達式 user_def_dir_exp 太複雜時非常有用,因爲你不需要在結束標籤中重複表達式。 此外,如果表達式包含比簡單變量名和點還多的表達式,你就不能再重複它們了。比如, <@a_hash[a_method()]>...</@a_hash[a_method()]> 就是錯的,你必須寫爲 <@a_hash[a_method()]>...</@>。 但是 <@a_hash.foo>...</@a_hash.foo> 是可以的

循環變量:
一些自定義指令創建循環變量(和 list 指令相似)。
正如預定義指令(如 list)一樣,當你調用這個指令 (如 <#list foos as foo>…</#list>中的 foo)時循環變量的 名稱 就給定了, 而變量的 值 是由指令本身設置的。
在自定義指令的情形下,語法是循環變量的名稱在分號之後給定

<@myRepeatMacro count=4 ; x, last>
  ${x}. Something... <#if last> This was the last!</#if>
</@myRepeatMacro>

請注意,由自定義指令創建的循環變量數量和分號之後指定的循環變量數量需要不匹配。 
也就是說,如果你對重複是否是最後一個不感興趣,你可以簡單來寫:

<@myRepeatMacro count=4 ; x>
  ${x}. Something...
</@myRepeatMacro>

或者你可以:

<@myRepeatMacro count=4>
  Something...
</@myRepeatMacro>

二十一.visit, recurse, fallback

寫法:

<#visit node using namespace>
或
<#visit node>
<#recurse node using namespace>
或
<#recurse node>
或
<#recurse using namespace>
或
<#recurse>
<#fallback>
  • node: 算作 結點變量 的表達式。
  • namespace: 命名空間,或者是命名空間的序列。 命名空間可以以命名空間哈希表(又稱爲根哈希表)給定, 或者可以引入一個存儲模板路徑的字符串。代替命名空間哈希表, 你也可以使用普通哈希表
  • visit 和 recurse 指令是用來遞歸處理樹的。在實踐中,這通常被用來 處理XML。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章