FreeMarker模板语言开发(整理版)
FreeMarker語(yǔ)言
FreeMarker語(yǔ)言概述
FreeMarker是一個(gè)模板引擎,一個(gè)基于模板生成文本輸出的通用工具,使用純Java編寫。
FreeMarker被設(shè)計(jì)用來生成HTML Web頁(yè)面,特別是基于MVC模式的應(yīng)用程序
雖然FreeMarker具有一些編程的能力,但通常由Java程序準(zhǔn)備要顯示的數(shù)據(jù),由FreeMarker生成頁(yè)面,通過模板顯示準(zhǔn)備的數(shù)據(jù)(如下圖)
?
FreeMarker不是一個(gè)Web應(yīng)用框架,而適合作為Web應(yīng)用框架一個(gè)組件。
FreeMarker與容器無關(guān),因?yàn)樗⒉恢繦TTP或Servlet;FreeMarker同樣可以應(yīng)用于非Web應(yīng)用程序環(huán)境。
FreeMarker更適合作為Model2框架(如Struts)的視圖組件,你也可以在模板中使用JSP標(biāo)記庫(kù)。
FreeMarker是免費(fèi)的。
FreeMarker特性
通用目標(biāo)
能夠生成各種文本:HTML、XML、RTF、Java源代碼等等
易于嵌入到你的產(chǎn)品中:輕量級(jí);不需要Servlet環(huán)境
插件式模板載入器:可以從任何源載入模板,如本地文件、數(shù)據(jù)庫(kù)等等
你可以按你所需生成文本:保存到本地文件;作為Email發(fā)送;從Web應(yīng)用程序發(fā)送它返回給Web瀏覽器
強(qiáng)大的模板語(yǔ)言
所有常用的指令:include、if/elseif/else、循環(huán)結(jié)構(gòu)
在模板中創(chuàng)建和改變變量
幾乎在任何地方都可以使用復(fù)雜表達(dá)式來指定值
命名的宏,可以具有位置參數(shù)和嵌套內(nèi)容
名字空間有助于建立和維護(hù)可重用的宏庫(kù),或者將一個(gè)大工程分成模塊,而不必?fù)?dān)心名字沖突
輸出轉(zhuǎn)換塊:在嵌套模板片段生成輸出時(shí),轉(zhuǎn)換HTML轉(zhuǎn)義、壓縮、語(yǔ)法高亮等等;你可以定義自己的轉(zhuǎn)換
通用數(shù)據(jù)模型
FreeMarker不是直接反射到Java對(duì)象,Java對(duì)象通過插件式對(duì)象封裝,以變量方式在模板中顯示
你可以使用抽象(接口)方式表示對(duì)象(JavaBean、XML文檔、SQL查詢結(jié)果集等等),告訴模板開發(fā)者使用方法,使其不受技術(shù)細(xì)節(jié)的打擾
為Web準(zhǔn)備
在模板語(yǔ)言中內(nèi)建處理典型Web相關(guān)任務(wù)(如HTML轉(zhuǎn)義)的結(jié)構(gòu)
能夠集成到Model2 Web應(yīng)用框架中作為JSP的替代
支持JSP標(biāo)記庫(kù)
為MVC模式設(shè)計(jì):分離可視化設(shè)計(jì)和應(yīng)用程序邏輯;分離頁(yè)面設(shè)計(jì)員和程序員
智能的國(guó)際化和本地化
字符集智能化(內(nèi)部使用UNICODE)
數(shù)字格式本地化敏感
日期和時(shí)間格式本地化敏感
非US字符集可以用作標(biāo)識(shí)(如變量名)
多種不同語(yǔ)言的相同模板
強(qiáng)大的XML處理能力
<#recurse> 和<#visit>指令(2.3版本)用于遞歸遍歷XML樹。在模板中清楚和直覺的訪問XML對(duì)象模型。開源論壇 JForum 就是使用了 FreeMarker 做為頁(yè)面模板。
第一個(gè)FreeMarker程序
1、建立一個(gè)普通的java項(xiàng)目:testFreeMarker
2、引入freemarker.jar包
3、在項(xiàng)目目錄下建立模板目錄:templates
4、在templates目錄下,建立a.ftl模板文件,內(nèi)容如下:
| Hello world,${user},今天天氣不錯(cuò)! |
5、建立com.sxt.test.freemarker包,然后建立Testjava文件,內(nèi)容如下:
| package com.thaifintech.test.freemarker; ? import java.io.File; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.HashMap; import java.util.Map; ? import freemarker.template.Configuration; import freemarker.template.DefaultObjectWrapper; import freemarker.template.Template; ? public class Test1 { ???????? public static void main(String[] args) throws Exception { ?????????????????? //創(chuàng)建Freemarker配置實(shí)例 ?????????????????? Configuration cfg = new Configuration(); ?????????????????? ?????????????????? cfg.setDirectoryForTemplateLoading(new File("templates")); ?????????????????? ?????????????????? //創(chuàng)建數(shù)據(jù)模型 ?????????????????? Map root = new HashMap(); ?????????????????? root.put("user", "老高"); ?????????????????? ?????????????????? //加載模板文件 ?????????????????? Template t1 = cfg.getTemplate("a.ftl"); ?????????????????? ?????????????????? //顯示生成的數(shù)據(jù),//將合并后的數(shù)據(jù)打印到控制臺(tái) ?????? Writer out = new OutputStreamWriter(System.out); ?????? t1.process(root, out); ?????? out.flush(); ? ?????? //顯示生成的數(shù)據(jù),//將合并后的數(shù)據(jù)直接返回成字符串! //???? StringWriter out = new StringWriter();?? //???? t1.process(root, out); //???? out.flush(); //???? String temp = out.toString(); //???? System.out.println(temp);??????? } } |
6、編譯和運(yùn)行Testjava文件,控制臺(tái)打印:
?
數(shù)據(jù)類型 一、 直接指定值 直接指定值可以是字符串、數(shù)值、布爾值、集合及Map對(duì)象。 1. 字符串 直接指定字符串值使用單引號(hào)或雙引號(hào)限定。字符串中可以使用轉(zhuǎn)義字符”\"。如果字符串內(nèi)有大量的特殊字符,則可以在引號(hào)的前面加上一個(gè)字母r,則字符串內(nèi)的所有字符都將直接輸出。2. 數(shù)值 數(shù)值可以直接輸入,不需要引號(hào)。FreeMarker不支持科學(xué)計(jì)數(shù)法。3. 布爾值 直接使用true或false,不使用引號(hào)。4. 集合 集合用中括號(hào)包括,集合元素之間用逗號(hào)分隔。 使用數(shù)字范圍也可以表示一個(gè)數(shù)字集合,如1..5等同于集合[1, 2, 3, 4, 5];同樣也可以用5..1來表示[5, 4, 3, 2, 1]。5. Map對(duì)象 Map對(duì)象使用花括號(hào)包括,Map中的key-value對(duì)之間用冒號(hào)分隔,多組key-value對(duì)之間用逗號(hào)分隔。 注意:Map對(duì)象的key和value都是表達(dá)式,但key必須是字符串。6. 時(shí)間對(duì)象 root.put("date1", new Date()); ${date1?string("yyyy-MM-dd HH:mm:ss")}7. JAVABEAN的處理Freemarker中對(duì)于javabean的處理跟EL表達(dá)式一致,類型可自動(dòng)轉(zhuǎn)化!非常方便! 二、 輸出變量值 FreeMarker的表達(dá)式輸出變量時(shí),這些變量可以是頂層變量,也可以是Map對(duì)象的變量,還可以是集合中的變量,并可以使用點(diǎn)(.)語(yǔ)法來訪問Java對(duì)象的屬性。1. 頂層變量 所謂頂層變量就是直接放在數(shù)據(jù)模型中的值。輸出時(shí)直接用${variableName}即可。2. 輸出集合元素 可 以根據(jù)集合元素的索引來輸出集合元素,索引用中括號(hào)包括。如: 輸出[“1”, “2”, “3”]這個(gè)名為number的集合,可以用${number[0]}來輸出第一個(gè)數(shù)字。FreeMarker還支持用number[1..2]來表示原 集合的子集合[“2”, “3”]。3. 輸出Map元素 對(duì)于JavaBean實(shí)例,FreeMarker一樣把它看作屬性為key,屬性值為value的Map對(duì)象。 輸出Map對(duì)象時(shí),可以使用點(diǎn)語(yǔ)法或中括號(hào)語(yǔ)法,如下面的幾種寫法的效果是一樣的:book.author.name book.author["name"] book["author"].name book["author"]["name"] 使用點(diǎn)語(yǔ)法時(shí),變量名字有和頂層變量一樣的限制,但中括號(hào)語(yǔ)法沒有任何限制。 三、字符串操作 1. 字符串連接 字符串連接有兩種語(yǔ)法: (1) 使用${..}或#{..}在字符串常量?jī)?nèi)插入表達(dá)式的值; (2) 直接使用連接運(yùn)算符“+”連接字符串。 如,下面兩種寫法等效:${"Hello, ${user}"} ${"Hello, " + user + "!"} 有一點(diǎn)需要注意: ${..}只能用于文本部分作為插值輸出,而不能用于比較等其他用途,如:<#if ${isBig}>Wow!</#if> <#if "${isBig}">Wow!</#if> 應(yīng)該寫成:<#if isBig>Wow!</#if> 2. 截取子串 截取子串可以根據(jù)字符串的索引來進(jìn)行,如果指定一個(gè)索引值,則取得字符串該索引處的字符;如果指定兩個(gè)索引值,則截取兩個(gè)索引中間的字符串子串。如:<#assign number="01234">${number[0]} <#-- 輸出字符0 -->${number[0..3]} <#-- 輸出子串“0123” -->四、集合連接操作連接集合的運(yùn)算符為“+”五、Map連接操作Map連接操作的運(yùn)算符為“+”六、算術(shù)運(yùn)算符FreeMarker表達(dá)式中支持“+”、“-”、“*”、“/”、“%”運(yùn)算符。七、比較運(yùn)算符 表達(dá)式中支持的比較運(yùn)算符有如下幾種: 1. =(或者==): 判斷兩個(gè)值是否相等; 2. !=: 判斷兩個(gè)值是否不相等; 注: =和!=可以用作字符串、數(shù)值和日期的比較,但兩邊的數(shù)據(jù)類型必須相同。而且FreeMarker的比較是精確比較,不會(huì)忽略大小寫及空格。 3. >(或者gt): 大于 4. >=(或者gte): 大于等于 5. <(或者lt): 小于 6. <=(或者lte): 小于等于 注: 上面這些比較運(yùn)算符可以用于數(shù)字和日期,但不能用于字符串。大部分時(shí)候,使用gt比>有更好的效果,因?yàn)镕reeMarker會(huì)把>解釋成標(biāo)簽的結(jié)束字符。可以使用括號(hào)來避免這種情況,如:<#if (x>y)>。 if else 語(yǔ)句測(cè)試: <#if num0 gt 18> <#--不是使用>,大部分時(shí)候,freemarker會(huì)把>解釋成標(biāo)簽結(jié)束! -->及格! <#else>不及格! </#if> root.put("num0", 18);八、邏輯運(yùn)算符 1. &&: 邏輯與; 2. ||: 邏輯或; 3. !: 邏輯非 邏輯運(yùn)算符只能用于布爾值。 九、內(nèi)建函數(shù) FreeMarker提供了一些內(nèi)建函數(shù)來轉(zhuǎn)換輸出,可以在任何變量后緊跟?,?后緊跟內(nèi)建函數(shù),就可以通過內(nèi)建函數(shù)來轉(zhuǎn)換輸出變量。字符串相關(guān)常用的內(nèi)建函數(shù): 1. html: 對(duì)字符串進(jìn)行HTML編碼; 2. cap_first: 使字符串第一個(gè)字母大寫; 3. lower_case: 將字符串轉(zhuǎn)成小寫; 4. upper_case: 將字符串轉(zhuǎn)成大寫;集合相關(guān)常用的內(nèi)建函數(shù): 1. size: 獲得集合中元素的個(gè)數(shù);數(shù)字值相關(guān)常用的內(nèi)建函數(shù): 1. int: 取得數(shù)字的整數(shù)部分。舉例: root.put("htm2", "<b>粗體</b>"); 內(nèi)建函數(shù): ${htm2?html}十、空值處理運(yùn)算符 FreeMarker的變量必須賦值,否則就會(huì)拋出異常。而對(duì)于FreeMarker來說,null值和不存在的變量是完全一樣的,因?yàn)镕reeMarker無法理解null值。 FreeMarker提供兩個(gè)運(yùn)算符來避免空值: 1. !: 指定缺失變量的默認(rèn)值; 2. ??:判斷變量是否存在。 !運(yùn)算符有兩種用法:variable!或variable!defaultValue。第一種用法不給變量指定默認(rèn)值,表明默認(rèn)值是空字符串、長(zhǎng)度為0的集合、或長(zhǎng)度為0的Map對(duì)象。 使用!運(yùn)算符指定默認(rèn)值并不要求默認(rèn)值的類型和變量類型相同。測(cè)試空值處理: <#-- ${sss} 沒有定義這個(gè)變量,會(huì)報(bào)異常! --> ${sss!} <#--沒有定義這個(gè)變量,默認(rèn)值是空字符串! --> ${sss!"abc"} <#--沒有定義這個(gè)變量,默認(rèn)值是字符串a(chǎn)bc! -->??運(yùn)算符返回布爾值,如:variable??,如果變量存在,返回true,否則返回false。數(shù)據(jù)類型常見示例
?直接指定值?
- 字符串 : "Foo"或 者'Foo'或"It's \"quoted\""或r"C:\raw\string"?
- 數(shù)字:123.45?
- 布爾值:true, false?
- 序列:["foo", "bar", 123.45], 1..100?
- 哈希表:{"name":"green mouse", "price":150}?
- 檢索變量 ? ? 頂層變量:user?
- 從哈希表中檢索數(shù)據(jù):user.name, user[“name”]?
- 從序列中檢索:products[5]?
- 特殊變量:.main?
- 字符串操作?
- 插值(或連接):"Hello ${user}!"(或"Free" + "Marker")?
- 獲取一個(gè)字符:name[0]?
- 序列操作?
- 連接:users + ["guest"]?
- 序列切分:products[10..19] ?或 ?products[5..]?
- 哈希表操作?
- 連接:passwords + {"joe":"secret42"}?
- 算數(shù)運(yùn)算: (x * 1.5 + 10) / 2 - y % 100?
- 比 較 運(yùn) 算 : x == y, ? x != y, ? x < y, ? x > y, ? x >= y, ? x <= y,?x < y, ?等等?
- 邏輯操作:!registered && (firstVisit || fromEurope)?
- 內(nèi)建函數(shù):name?upper_case?
- 方法調(diào)用:repeat("What", 3)?
- 處理不存在的值?
- 默認(rèn)值:name!"unknown" ?或者(user.name)!"unknown" ?或者name! ?或者 ?(user.name)!?
- 檢測(cè)不存在的值:name?? 或者(user.name)???
參考:運(yùn)算符的優(yōu)先級(jí)
?
模板開發(fā)語(yǔ)句
最簡(jiǎn)單的模板是普通? HTML? 文件(或者是其他任何文本文件—FreeMarker? 本身不屬于HTML)。當(dāng)客戶端訪問頁(yè)面時(shí),FreeMarker 要發(fā)送 HTML 代碼至客戶端瀏覽器端顯示。如果想要頁(yè)面動(dòng)起來,就要在 HTML 中放置能被 FreeMarker 所解析的特殊部分。
???
${…}:FreeMarker 將會(huì)輸出真實(shí)的值來替換花括號(hào)內(nèi)的表達(dá)式,這樣的表達(dá)式被稱為
interpolations 插值,可以參考第上面示例的內(nèi)容。
?
??? FTL tags 標(biāo)簽(FreeMarker? 模板的語(yǔ)言標(biāo)簽):FTL 標(biāo)簽和 HTML 標(biāo)簽有一點(diǎn)相似,但是它們是? FreeMarker? 的指令而且是不會(huì)直接輸出出來的東西。這些標(biāo)簽的使用一般以符號(hào)#開頭。(用戶自定義的 FTL 標(biāo)簽使用@符號(hào)來代替#,但這是更高級(jí)的主題內(nèi)容了,后面會(huì)詳細(xì)地討論)
??
Comments 注釋:FreeMarker 的注釋和 HTML 的注釋相似,但是它用<#--和-->來分隔的。任何介于這兩個(gè)分隔符(包含分隔符本身)之間內(nèi)容會(huì)被 FreeMarker? 忽略,就不會(huì)
輸出出來了。
?
??? 其他任何不是? FTL? 標(biāo)簽,插值或注釋的內(nèi)容將被視為靜態(tài)文本,這些東西就不會(huì)被
FreeMarker 所解析,會(huì)被按照原樣輸出出來。
?
??? directives指令:就是所指的? FTL? 標(biāo)簽。這些指令在? HTML? 的標(biāo)簽(如<table>和
</table>)和 HTML 元素(如 table 元素)中的關(guān)系是相同的。(如果現(xiàn)在你還不能區(qū)
分它們,那么把“FTL 標(biāo)簽”和“指令”看做是同義詞即可。)
if指令
| root.put("random", new Random().nextInt(100)); |
| ------------------------------------------------ if語(yǔ)句測(cè)試: ${user}是<#if user=="老高">我們的老師</#if> ------------------------------------------------ if else 語(yǔ)句測(cè)試: <#if num0 gt 18>? <#--不是使用>,大部分時(shí)候,freemarker會(huì)把>解釋成標(biāo)簽結(jié)束! --> ??? 及格! <#else> ??? 不及格! </#if> --------------------------------------------------- if else if else語(yǔ)句測(cè)試: <#if random gte 90> ??? 優(yōu)秀! <#elseif random gte 80> ??? 良好! <#else> ??? 一般!? </#if> ---------------------------------------------------- |
list指令?
| ?????? List list = new ArrayList(); ?????? list.add(new Address("中國(guó)","北京")); ?????? list.add(new Address("中國(guó)","上海")); ?????? list.add(new Address("美國(guó)","紐約")); ?????? root.put("lst", list); |
| 測(cè)試list指令: <#list lst as dizhi > ??? <b>${dizhi.country}</b> <br/> </#list> ? 思考問題:<c:forEach> status屬性。在此處如何實(shí)現(xiàn)? ? |
| 控制臺(tái)打印: 測(cè)試list語(yǔ)句: ??? <b>中國(guó)</b> <br/> ??? <b>中國(guó)</b> <br/> ??? <b>美國(guó)</b> <br/> |
?
include指令
增加被包含文件,放于templates目錄下:
文件內(nèi)容如下:
模板文件中代碼如下:
| 測(cè)試include指令: <#include "included.txt" /> |
自定義指令(macro指令)
| <#macro m1>?? <#--定義指令m1 --> ??? <b>aaabbbccc</b> ??? <b>dddeeefff</b> </#macro> |
| <@m1 /><@m1 />? <#--調(diào)用上面的宏指令 --> |
?
定義帶參的宏指令:
| <#macro m2 a b c > ??? ${a}--${b}--${c} </#macro> |
| <@m2 a="老高" b="老張" c="老馬" /> |
?
nested指令:
| <#macro border> ? <table border=4 cellspacing=0 cellpadding=4><tr><td> ??? <#nested> ? </td></tr></table> </#macro> |
| <@border >表格中的內(nèi)容!</@border> |
宏指令中,有沒有類似于方法的返回值?
?
命名空間
當(dāng)運(yùn)行 FTL 模板時(shí),就會(huì)有使用 assign 和 macro 指令創(chuàng)建的變量的集合(可能是空的),可以從前一章節(jié)來看如何使用它們。像這樣的變量集合被稱為 namespace 命名空間。在簡(jiǎn)單的情況下可以只使用一個(gè)命名空間,稱之為 main namespace 主命名空間。因?yàn)橥ǔV皇褂帽卷?yè)上的命名空間,所以就沒有意識(shí)到這點(diǎn)。
??? 如果想創(chuàng)建可以重復(fù)使用的宏,函數(shù)和其他變量的集合,通常用術(shù)語(yǔ)來說就是引用
library 庫(kù)。使用多個(gè)命名空間是必然的。只要考慮你在一些項(xiàng)目中,或者想和他人共享使用的時(shí)候,你是否有一個(gè)很大的宏的集合。但要確保庫(kù)中沒有宏(或其他變量)名和數(shù)據(jù)模型中變量同名,而且也不能和模板中引用其他庫(kù)中的變量同名。通常來說,變量因?yàn)槊Q沖突也會(huì)相互沖突。所以要為每個(gè)庫(kù)中的變量使用不同的命名空間。
?
定義b.ftl文件:
| <#macro copyright date> ? <p>Copyright (C) ${date} 泰中.</p> </#macro> <#assign mail = "thaifintech@163.com"> |
?
在a.ftl文件中引入b.ftl,從而可以使用b.ftl中定義的宏和變量:
| 測(cè)試命名空間: <#import "b.ftl" as bb? /> <@bb.copyright date="2010-2011" /> ${bb.mail} <#assign mail="my@163.com"? /> ${mail} <#assign mail="my@163.com" in bb? /> ${bb.mail} |
執(zhí)行后,控制臺(tái)打印:
| 測(cè)試命名空間: ? <p>Copyright (C) 2017-2018 泰中.</p> thaifintech@163.com my@163.com my@163.com |
命名空間命名規(guī)則
如果你為 Example 公司工作,它們擁有 www.example.com 網(wǎng)的主頁(yè),你的工作是開發(fā)
一個(gè)部件庫(kù),那么要引入你所寫的 FTL 的路徑應(yīng)該是:
/lib/example.com/widget.ftl
?
注意到 www 已經(jīng)被省略了。第三次路徑分割后的部分可以包含子目錄,可以像下面這
樣寫:
???????? /lib/example.com/commons/string.ftl
一個(gè)重要的規(guī)則就是路徑不應(yīng)該包含大寫字母,為了分隔詞語(yǔ),使用下劃線_,就像
wml_form(而不是 wmlForm)。
?
如果你的工作不是為公司或組織開發(fā)庫(kù),也要注意,你應(yīng)該使用項(xiàng)目主頁(yè)的 URL,比如
/lib/example.sourceforge.net/example.ftl或/lib/geocities.com/jsmith/example.ftl。
?
在Servlet中使用Freemarker
參考Freemarker包中example目錄下webapp1項(xiàng)目!
?
struts2中整合FreeMarker
1.解壓struts2-core-X.X.X.jar文件,把在META-INF文件夾下面的struts-tags.tld文件復(fù)制到WEB-INF文件夾下。???將freemark的jar導(dǎo)入到工程中
?
2.在web.xml文件中配置freemark同時(shí)啟動(dòng)JSPSupportServlet.代碼如下:
<servlet>
????????<servlet-name>freemarker</servlet-name>
????????<servlet-class>
????????????freemarker.ext.servlet.FreemarkerServlet
????????</servlet-class>
????????<!--下面的配置freemarke的ftl文件的位置?-->
????????<init-param>
????????????<param-name>TemplatePath</param-name>
????????????<param-value>/</param-value>
????????</init-param>
????????<!--?是否和服務(wù)器(tommcat)一起啟動(dòng)。-->
????????<load-on-startup>1</load-on-startup>
????</servlet>
????<servlet-mapping>
????????<servlet-name>freemarker</servlet-name>
????????<url-pattern>*.ftl</url-pattern>
????</servlet-mapping>
<servlet>
??<!--?define?a?JspSupportServlet?Object?-->
??<servlet-name>JspSupportServlet</servlet-name>
??<servlet-class>org.apache.struts2.views.JspSupportServlet</servlet-class>
??<!--?setting?JspSupportServlet?auto?start?-->
??<load-on-startup>1</load-on-startup>
?</servlet>
?
3.在FreeMarker模板中使用assign指令導(dǎo)入標(biāo)簽庫(kù)。代碼如下
<#assign s=JspTaglibs["/WEB-INF/struts-tags.tld"] /> 注:這里我把struts-tags.tld放在WEB-INF下面
4.現(xiàn)在我們可以在FreeMarker模板中使用標(biāo)簽了。
?
總結(jié)
以上是生活随笔為你收集整理的FreeMarker模板语言开发(整理版)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JAVA WEB 中间件为SERVLET
- 下一篇: 利用photoshop创建一个3D绚丽的