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