標籤:winform style blog http color io os 使用 java
4.1 自訂指令 4.1.1 簡介
自訂指令可以使用macro指令來定義。Java程式員若不想在模板中實現定義指令,而是在Java語言中實現指令的定義,這時可以使用freemarker.template.TemplateDirectiveModel類來擴充,後邊會講。 4.1.2 基本內容
宏是有一個變數名的模板片段。你可以在模板中使用宏作為自訂指令,這樣就能進行重複性的工作。例如,建立一個宏變數來列印大號的”hello Joe!“;
<#macro greet> <font size="+2">Hello Joe!</font></#macro>
可以在FTL標記中通過@代替#來使用自訂指令。
<@greet></@greet>
4.1.3 參數
我們僅在greet宏中定義一個變數,person;
<#macro greet person> <font size="+2">Hello ${person}!</font></#macro>
那麼可以這樣使用宏:
<@greet person="Fred"/>and<@greet person="Batman"/>
可以去掉雙引號, <@greet person=Fred/>
多個參數時,可以設定預設值,要不然的話使用的時候必須指定對應的多個參數:
<#macro greet person color="black"> <font size="+2" color="${color}">Hello ${person}!</font></#macro>
那麼就可以這樣使用了
<@greet person="Fred"/>
執行個體
/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/macro.ftl
<h2>沒有參數</h2> <p> <#macro greet> <font size="+2">Hello Joe!</font> </#macro> <@greet/> </p> <h2>有參數</h2> <p> <#macro greet person> <font size="+2">Hello ${person}!</font> </#macro> <@greet person="Fred"/> and <@greet person="Bob"/> </p> <h2>多個參數時,可以設定預設值</h2> <p> <#macro greet person color="black"> <font size="+2" color="${color}">Hello ${person}!</font> </#macro> <@greet person="Fred"/> and <@greet person="Bob" color="red"/> </p>
輸出:
4.1.4 嵌套內容
自訂指令可以嵌套內容,和預定義指令相似:<#if ...>nested content</#if>。比如,下面這個例子中是建立了一個可以為嵌套的內容畫出邊框;
<#macro border> <table border=4 cellspacing=0 cellpadding=4> <tr> <td> <#nested> </td> </tr> </table></#macro>
<#nested>標籤執行位於開始和結束標籤之間的模板代碼塊,例如:
<@border>The bordered text</@border>
輸出:
<table border=4 cellspacing=0 cellpadding=4> <tr> <td> The bordered text </td> </tr></table>
<#nested>指令可以被執行多次;
<#macro do_thrice> <#nested> <#nested> <#nested></#macro>
使用時:
<@do_thrice>anything</@do_trice>
輸出:
anythinganythinganything
如果不使用nested指令,那麼嵌套的內容就會被執行,如果不小心寫成這樣:
<@greet person="Joe"> Anything.</@greet>
輸出是:
<font size="+2">Hello Joe!</font>
嵌套的內容被忽略了,因為greet沒有使用nested指令;
嵌套內容可以是其他FTL指令,包含其他自訂指令也是可以的。
<@border> <ul> <@do_thrice> <li><@greet person="Joe"></li> </@do_thrice> </ul></@border>
在嵌套的內容中,宏的局部變數是不可見的;
<#macro repeat count> <#local y="test"> <#list 1..count as x> ${y} ${count}/${x} : <#nested> </#list></#macro><@repeat count=3>${y!"?"} ${x!"?"} ${count!"?"}</@repeat>
將會輸出:
test 3/1: ? ? ?test 3/2: ? ? ?test 3/3: ? ? ?
不同的局部變數的設定是為每個宏自己調用的,所以不會導致混亂;
<#macro test foo>${foo} (<#nested>) ${foo}</#macro><@test foo="A"><@test foo="B"><@test foo="C"/></@test></@test>
輸出:
A (B (C () C) B) A
4.1.5 宏與迴圈變數
迴圈變數的名字是已經給定了,變數值的設定由指令本身完成。
<#macro do_thrice> <#nested 1> <#nested 2> <#nested 3></#macro><p> <#--自訂迴圈變數需要用;代替as--> <@do_thrice ; x> do_something : ${x} </@do_thrice></p>
輸出:
do_something : 1 do_something : 2 do_something : 3
例子:/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/nested.ftl
<h3>宏與迴圈變數</h3><#macro do_thrice> <#nested 1> <#nested 2> <#nested 3></#macro><p> <#--自訂迴圈變數需要用;代替as--> <@do_thrice ; x> do_something : ${x} </@do_thrice></p>
一個宏可以使用多個迴圈變數(變數的順序是很重要的):
<#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!
例子:/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/nested.ftl
<h3>一個宏可以使用多個迴圈變數</h3> <#macro repeat count> <#list 1..count as x> <#nested x, x/2, x==count><br> </#list> </#macro> <p> <@repeat count=4 ; c, half, last> ${c}. ${half} <#if last> Last!</#if> </@repeat> </p>
如果分號後指定的變數少了或多了,多出的會忽略掉;
@repeat count=4 ; c, half> ${c}. ${half} </@repeat>
4.1.6 自訂指令和宏進階
你也可以在FTL中定義方法,參見function指令;
也許你對命名空間感興趣。命名空間可以協助你組織和重用你經常使用的宏;4.2 在模板中定義變數
可以訪問一個在模板裡定義的變數,就像是訪問資料模型根上的變數一樣。這個變數比定義在資料模型中的同名參數具有更高的優先順序。如果你恰巧定義了一個名為“foo”的變數,而在資料模型中也有一個名為“foo”的變數,那麼模板中的變數就會將資料模型根上的變數隱藏(而不是覆蓋!)。
在模板中可以定義三種類型的變數:
- 簡單變數:它能從模板中的任何位置訪問,或者從使用
include指令引入的模板訪問。可以使用assign或macro指令來建立或替換這些變數。
- 局部變數:它們只能被設定在宏定義體內,而且只在宏內可見。一個局部變數的生命週期只是宏的調用過程。可以使用
local來建立或替換局部變數。
- 迴圈變數:迴圈變數是由指令(如
list)自動建立的,而且它們只在指令的開始和結束標記內有效。宏的參數是局部變數而不是迴圈變數。
使用assign建立和替換變數;
/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/variable.ftl
<h3>簡單變數</h3> <p> <#assign x=1> <#--建立變數x--> ${x}<br> <#assign x=x+3> <#--替換變數x--> ${x} </p>
輸出:
簡單變數14
局部變數也會隱藏(而不是)同名的簡單變數。迴圈變數也會隱藏(不是覆蓋)同名的局部變數和簡單變數。
執行個體:/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/variable.ftl
<#macro test> 2. ${x}<br> <#local x="local"> 3. ${x}<br> <#list ["loop"] as x> 4. ${x}<br> </#list> 5. ${x}<br> </#macro> <p> <#assign x="plain"> 1. ${x}<br> <@test/> 6. ${x}<br> <#list ["loop"] as x> 7. ${x}<br> <#assign x="plain2"> <#--在這裡替換了簡單變數x--> 8. ${x}<br> </#list> 9. ${x} </p>
輸出:
1. plain2. plain3. local4. loop5. local6. plain7. loop8. loop9. plain2
內部迴圈可以隱藏外部迴圈的變數;
執行個體:/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/variable.ftl
<#list ["loop 1"] as x> ${x}<br> <#list ["loop 2"] as x> ${x}<br> <#list ["loop 3"] as x> ${x}<br> </#list> ${x}<br> </#list> ${x}<br> </#list>
輸出:
loop 1loop 2loop 3loop 2loop 1
有時發生一個變數隱藏資料模型中的同名變數,但是如果想訪問資料模型中的變數,就可以使用特殊變數globals。
執行個體:/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/variable.ftl
<#assign user="Cindy"> ${user}, ${.globals.user}
/FreeMarker-hello-web/src/main/java/org/yejq/fre/service/Exercises.java
public void testVariable(Model model){ model.addAttribute("user", "lucy"); }
測試:http://localhost/test/4/variable/testVariable,輸出結果:
Cindy, lucy
4.3 命名空間4.3.1 簡介
如果想建立可以重複使用的宏、函數和其他變數的集合,通常用術語來說就是引用library庫,使用命名空間是必然的;4.3.2 建立一個庫
執行個體:/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/lib/my_test.ftl
<#macro copyright date> <p>Copyright (C) ${date} Julia Smith. All rights reserved.</p></#macro><#assign mail="[email protected]">
/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/namespace.ftl
<h3>使用import匯入</h3> <p> <#import "../lib/my_test.ftl" as my> <@my.copyright date="2014-2016"/> ${my.mail} </p>
輸出:
使用import匯入Copyright (C) 2014-2016 Julia Smith. All rights reserved.[email protected]
測試不同的命名空間;
/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/lib/my_test.ftl
<#macro copyright date> <p>Copyright (C) ${date} Julia Smith. All rights reserved. <br>Mail: ${mail} </p></#macro><#assign mail="[email protected]">
/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/namespace.ftl
<h3>示範不同的命名空間</h3> <p> <#import "../lib/my_test.ftl" as my> <#assign mail="[email protected]"> <@my.copyright date="2014-2016"/> ${my.mail}<br> ${mail} </p>
測試:http://localhost/test/4/namespace/null4.3.3 在引入的命名空間上編寫變數
/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/namespace.ftl
<#import "../lib/my_test.ftl" as my> ${my.mail}<br> <#assign mail="[email protected]" in my> ${my.mail}
http://localhost/test/4/namespace/null,輸出:
[email protected][email protected]
4.3.4 命名空間和資料模型
資料模型中的變數在任何位置都是可見的。如果在資料模型中有一個名為user的變數,那麼lib/my_test.ftl也能訪問TA。
/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/lib/my_test.ftl
<#macro copyright date> <p>Copyright (C) ${date} ${user} Julia Smith. All rights reserved. <br>Mail: ${mail} </p></#macro><#assign mail="${user}@acme.com">
/FreeMarker-hello-web/src/main/java/org/yejq/fre/service/Exercises.java
public void testNamespace(Model model){ model.addAttribute("user", "lucy"); }
/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/namespace.ftl
<h3>資料模型中的變數在任何位置都是可見的</h3> <p> <#import "../lib/my_test.ftl" as my> <@my.copyright date="2014-2015"/> </p>
測試:http://localhost/test/4/namespace/testNamespace?11,輸出結果:
Copyright (C) 2014-2015 lucy Julia Smith. All rights reserved. Mail: [email protected]
4.3.5 命名空間的生命週期
命名空間由使用的import指令中所寫的路徑來識別。如果想多次import這個路徑,那麼只會為第一次的import引用建立命名空間執行模板。後邊相同的路徑的import只是建立一個雜湊表當做訪問相同命名空間的“門”。
/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/namespace.ftl
<h3>命名空間的聲明周期</h3> <p> <#import "/lib/my_test.ftl" as my> <#import "/lib/my_test.ftl" as foo> <#import "/lib/my_test.ftl" as bar> <#--只會在第一次建立命名空間執行模板,之後相同路徑的import只是建立雜湊表當做訪問相同命名空間的"門"--> ${my.mail}, ${foo.mail}, ${bar.mail}<br> <#assign mail="[email protected]" in my> ${my.mail}, ${foo.mail}, ${bar.mail}<br> <#--其中一個命名空間的值修改了,所有都相應修改,就像java裡邊的對象引用修改一樣--> <#assign mail="[email protected]" in foo> ${my.mail}, ${foo.mail}, ${bar.mail} </p>
訪問:http://localhost/test/4/namespace/null,輸出:
命名空間的聲明周期[email protected], [email protected], [email protected][email protected], [email protected], [email protected][email protected], [email protected], [email protected]
還要注意命名空間是不分層次的,它們相互之間是獨立存在的。那麼,如果在命名空間N1中import命名空N2,那N2也不在N1中,N1隻是通過雜湊表訪問N2。這和主命名空間中importN2,然後直接存取命名空間N2是一樣的過程。
每一次模板的執行過程,它都有一個私人的命名空間的集合。每一次模板執行工作都是一個分離且有序的過程,它們僅僅存在一段很短的時間,同時頁面用以呈現內容,然後就和所有填充過的命名空間一起消失了。4.3.6 為他人編寫庫
http://freemarker.org/libraries.html
標準庫路徑的格式:
/lib/yourcompany.com/your_library.ftl
如果你的公司的首頁是www.example.com,那麼;
/lib/example.com/widget.ftl/lib/example.com/commons/string.ftl
一個重要的規則是路徑不應該包含大寫字母,winForm改成win_form;4.4 空白處理4.4.1 簡介
來看看這個模板;
按照Freemarker規則輸出後是:
這麼多多餘的空白是很令人頭疼,而且增加處理後的HTML檔案大小也是沒必要的;
FreeMarker提供了以下工具來處理這個問題:
- 忽略某些檔案的空白的工具(解析階段空白就被移除了)
- 剝離空白:這個特性會自動忽略FTL標籤周圍的空白。這個特性可以通過模板來隨時使用和禁用;
- 微調指令:
t, rt和lt,使用這些指令可以明確告訴FreeMarker去忽略某些空白;
- FTL參數
strip_text:這將從模板中刪除所有頂級文本。對模板來說很有用,它包含某些定義的宏,因為它可以移除宏定義和其他頂級指令中的分行符號,這樣可以提高模板的可讀性;
- 從輸出移除空白的工具(移除臨近的空白)
4.4.2 剝離空白
它會自動忽略兩種典型的空白:
- 縮排空白和行末尾的尾部空白;如果這行上包含
<#if ...>x,那麼空白不會忽略,因為x不是標籤。而一行上有<#if ...> <#list ...>,這樣也不會忽略空白,因為標籤之間的空格是嵌入空白;
- 加在這些指令之間的空白會被忽略:macro,function,assign,global,local,ftl,import;
使用剝離空白之後,上面的例子輸出是:
剝離空白功能可以在ftl指令在模板中開啟或關閉。預設開啟。開啟剝離空白不會降低模板執行的效率,剝離空白的操作在模板載入時就已經完成了。
剝離空白可以為單獨的一行關閉,就是使用nt指令;4.4.3 使用compress指令
和剝離空白相反,這個工作是直接基於生產的輸出內容,而不是對模板進行的。它會強勢地移除縮排,空行和重複的空格/定位字元;
對於下邊這段代碼:
/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/compress.ftl
<h2>使用compress指令,在輸出的內容中移除縮排,空行和空格/定位字元</h2> <p> <#compress> <#assign users = [{"name":"Joe", "hidden":false}, {"name":"James Bond", "hidden":true}, {"name":"Julia", "hidden":false}]> list of users:<br> <#list users as user> <#if !user.hidden> - ${user.name}<br> </#if> </#list> </#compress> </p>
輸出:
<h2>使用compress指令,在輸出的內容中移除縮排,空行和空格/定位字元</h2> <p> list of users:<br>- Joe<br>- Julia<br> </p>
由於向下相容性,名稱為compress的使用者自訂指令是存在的,有個single_line的屬性,如果設定為true,那麼會移除其中的分行符號;
<h3>@compress的屬性single_line</h3> <p> <@compress single_line=true> <#assign users = [{"name":"Joe", "hidden":false}, {"name":"James Bond", "hidden":true}, {"name":"Julia", "hidden":false}]> list of users:<br> <#list users as user> <#if !user.hidden> - ${user.name}<br> </#if> </#list> </@compress> </p>
貌似不起作用,反而#compress是single_line;4.5 替換(方括弧)文法
版本2.3.4之後才有;
在指令和注釋中使用[]代替<>;
[#list ...]...[/list][@mymacro .../][#-- the comment --]
為了使用這種文法從而代替預設文法,那麼就需要用[#ftl]來開始模板。
/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/ftl.ftl
[#ftl]<!doctype html><html lang="en"><head> <meta charset="UTF-8" /> <title>Document</title></head><body> <h3>替換文法</h3> <p> [#assign users = [{"name":"Joe", "hidden":false}, {"name":"James Bond", "hidden":true}, {"name":"Julia", "hidden":false}]] list of users:<br> [#list users as user] [#if !user.hidden] - ${user.name}<br> [/#if] [/#list] </p></body></html>
測試:http://localhost/test/4/ftl/null
項目
- P1:https://github.com/yejq/FreeMarker-hello-java.git。
- P2:https://github.com/yejq/FreeMarker-hello-web.git
FreeMarker筆記 第四章 其它