概要
在FreeMarker中最簡單的模板文件是一個純 HTML 文件 (或者別的文本文件,FreeMarker並不將模板文件限於 HTML)。 當用戶端訪問這個頁面的時候就將其發給用戶端就好了,不過當你想讓你的模板文件具有更多的動態性的時候,你只需要將FreeMarker能懂的特殊部分加到 HTML 文件就OK了,這些個部分包含以下三大類:
- ${ ... } : FreeMarker會用花括號裏邊變量所持有的值將這部分全部替換掉,這樣就組成了輸出文件。我們稱這部分的名稱爲插值 (interpolations)。 可以看前面的例子
- FTL tags (FreeMarker Template Languages tags 的簡稱) : FTL tags 和 HTML 存在相似性,不過他們是 FreeMarker 中的指令並且是不會出現在輸出文件中。他們的名字是以 # 打頭的。 (在 FreeMarker 中還有中 FTL tags 是用戶的, 它們以
@ 開頭,是一個更高的主題了,後邊會涉及到)
- 註釋 : 這個註釋和 HTML 中的也是類似的,不過它們是以 <#-- 和 -->分隔的。任何在分隔符合分隔符中間的部分都會被 FreeMarker 忽略掉的,同樣是不會出現在輸出文件中。
在 FreeMarker 中只要不是插值、 FTL 標籤、註釋都是被當作靜態文本,不會被 FreeMarker 解析,會被原樣寫到輸出中。
FTL 標籤也可以被說成是指令 (directives)。其實它倆的關係和 HTML 中的 標籤 (tags, e.g.: <table> and </table>) 和元素 (elements, e.g.: tableelement)之間的關係類似。(如果你沒覺得這倆孩子有什麼不同可以 把 FTL 標籤和 指令當作是同義詞)
指令例子
雖然 FreeMarker 有很多的指令,在這裏我們值介紹三個常用的指令。
if 指令
用 if 指令就可以根據條件忽視掉模板中的指定部分。舉個例子,比如前邊的例子中你想將自己的老闆, Big Joe, 與其他的用戶區別開來:
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<h1>
Welcome ${user}<#if user == "Big Joe">, our beloved leader</#if>!
</h1>
<p>Our latest product:
<a href="${latestProduct.url}">${latestProduct.name}</a>!
</body>
</html>
這個例子中,你相當於告訴 FreeMarker 當變量 user 的值是 "Big Joe"時那麼 ", out beloved leader" 將會出現在那裏。根據規則,當condition的只是 false 的時候<#if condition> 和 </#if> 之間的部分是會被忽略掉的。
讓我們詳細看看 condition 的用法 : == 是用來測試其左邊和右邊的值是否相等,最終的結果是一個boolean值,相應的值就是 true or false。在 == 的左邊我引用了一個我們已經比較熟悉其語法的變量,這部分會被變量的值替換掉。這裏要注意下,在指令或是 插值中沒有用被單、雙引號擴起來的值都被視爲引用之的變量。右邊,我指定了一個字符串,在 FreeMarker 中字符串是必須處在引號裏邊的。
當 price 的值爲 0 的時候,下邊這個例子是會輸出 “Pythons are free today!”:
<#if animals.python.price == 0>
Pythons are free today!
</#if>
就像前邊的字符串一樣,這裏的數字也是被直接指定了,當然 0 是沒有被引號包圍。如果你寫成這樣"0",那麼 FreeMarker 就會誤解成字符串。
下邊這個例子,當 price 不等於 0 的時候會打印 "Pythons are not free today!":
<#if animals.python.price != 0>
Pythons are not free today!
</#if>
就像你所猜的, != 代表不等於。
同樣你也可以這麼寫: (數據來自這裏)
<#if animals.python.price < animals.elephant.price>
Pythons are cheaper than elephants today.
</#if>
在使用 <#else> 時,可以顯示當條件爲 false 時指定的內容。如下例:
<#if animals.python.price < animals.elephant.price>
Pythons are cheaper than elephants today.
<#else>
Pythons are not cheaper than elephants today.
</#if>
這個例子中當 elephant 的 price 小於 python 的 price 時會打印 "Pythons are not cheaper than elephant today." 否則就會打印另外一句了。
當一個變量的值是 boolean 類型的時候,那麼它就可以直接 用在 if 的 condition 部分 :
<#if animals.python.protected>
Warning! Pythons are protected animals!
</#if>
list 指令
這個指令在需要窮舉某些數據的時候很有用。 比如你打算將之前例子中的數據和下邊的模板結合起來:
<p>We have these animals:
<table border=1>
<tr><th>Name<th>Price
<#list animals as being>
<tr><td>${being.name}<td>${being.price} Euros
</#list>
</table>
那麼經過解析後,結果就是這樣了:
<p>We have these animals:
<table border=1>
<tr><th>Name<th>Price
<tr><td>mouse<td>50 Euros
<tr><td>elephant<td>5000 Euros
<tr><td>python<td>4999 Euros
</table>
list 指令的一般格式:
<#list sequenceasloopVariable>repeatThis</#list>
當每次窮舉 sequence 中的值時,每次窮舉一個都會重複一次輸出 repeatThis 。在所有的窮舉中, loopVariable 變量會持有當前的窮舉值, 並且這個變量只會存在於 <#list ..> 和</#list> 之間,這點和局部變量的生命週期比較類似的。
在下邊的例子中我們將 data-model 裏邊的 fruits 窮舉出來:
<p>And BTW we have these fruits:
<ul>
<#list whatnot.fruits as fruit>
<li>${fruit}
</#list>
<ul>
whatnot.fruits 表達式你應該是比較熟悉了,在這裏我們有提到過。
include 指令
用include指令你就可以將另一個文件插入到模板中了。
假如你想在多個頁面上顯示同樣的版權信息,那麼這時我們就只需要創建一個包含版權信息的文本,在任何需要這個信息的文件中插入就好了。比如我們將信息寫入 copyright_footer.html :
<hr>
<i>
Copyright (c) 2000 <a href="http://www.acmee.com">Acmee Inc</a>,
<br>
All Rights Reserved.
</i>
無論在什麼地方,你只需要在需要的時候將其插入即可:
<html>
<head>
<title>Test page</title>
</head>
<body>
<h1>Test page</h1>
<p>Blah blah...
<#include "/copyright_footer.html">
</body>
</html>
那麼他會輸出如下內容:
<html>
<head>
<title>Test page</title>
</head>
<body>
<h1>Test page</h1>
<p>Blah blah...
<hr>
<i>
Copyright (c) 2000 <a href="http://www.acmee.com">Acmee Inc</a>,
<br>
All Rights Reserved.
</i>
</body>
</html>
而且當你在改變了版權文件後,用戶訪問時在所有的頁面上看到的信息都是更改過後的了。
指令的組合使用
指令的使用是比較靈活的,只要你願意,一個頁面上的指令可以多次使用,並且他們之間是可以相互嵌套的,這點和 HTML 的元素之間的嵌套一樣。比如下例,會顯示所有動物的名稱並且會將大型動物的名字也給設置爲大字體:
<p>We have these animals:
<table border=1>
<tr><th>Name<th>Price
<#list animals as being>
<tr>
<td>
<#if being.size == "large"><font size="+1"></#if>
${being.name}
<#if being.size == "large"></font></#if>
<td>${being.price} Euros
</#list>
</table>
我們要注意一點,因爲 FreeMarker 對於在 FTL 標籤、插值、註釋外的靜態文本是不會進行解析的,所以像上邊的 font 這類信息對其是不可見的,其他內容類似。
處理丟失的變量
在實際開發中的 data-model 是包含了許多可選的變量(i.e, 信息丟失)。爲了早點的發現一些典型的人爲失誤, FreeMarker 一般是不會容忍變量的丟失除非顯示告訴它當它碰到類似情況後的處理方式,目前是主要有兩種典型的情況:
程序員需要特別注意: 對於 FreeMarker 來說一個不存在的變量和 null 值的變量是同樣的概念,所以 “丟失” 就意味着這兩種情況。
無論何時使用變量,以防萬一其值丟失了,可以通過在變量後邊跟上感嘆號 (!) 和默認值的組合值的方式來阻止拋出異常。就像下邊的例子一樣,當 user 這個變量從 data-model 中丟失的時候,模板本身好像是沒有注意到一樣,並且會將 字符串 “Anonymous” 作爲 user 的值。(同樣的,當 user 的值存在的時候它會當 !"Anonymous"不存在一樣)
<h1>Welcome ${user!"Anonymous"}!</h1>
我們也可以使用 ?? 來判斷某個變量的值是否存在,它如同 !一樣跟在變量後就好了。當和 if 組合使用時,當變量user丟失的時候那麼整個的問候語句會被忽略的。
<#if user??><h1>Welcome ${user}!</h1></#if>
我們還要考慮具有多層次解析的情況,比如 animals.python.price,當判斷默認值的寫法爲這樣的時候animals.python.price!0,要確保其不報錯那麼只能是當animals.python 本身是存在的才行,也只有 price 是可以丟失的。 因此,當animals 和 python 中任何一個出錯時解析都會停止並且報 "undefined variable" 異常。針對這種情況的解決方案是, (animals.python.price)!0,這樣在三個變量中任何一個變量丟失都會給出默認值0 ,這招對?? 也是同樣管用的。