FreeMarker是一個模板引擎,一個基於模板生成文本輸出的通用工具,使用純Java編寫。html
FreeMarker被設計用來生成HTML Web頁面,特別是基於MVC模式的應用程序java
雖然FreeMarker具備一些編程的能力,但一般由Java程序準備要顯示的數據,由FreeMarker生成頁面,經過模板顯示準備的數據(以下圖)程序員
FreeMarker不是一個Web應用框架,而適合做爲Web應用框架一個組件。web
FreeMarker與容器無關,由於它並不知道HTTP或Servlet;FreeMarker一樣能夠應用於非Web應用程序環境。數據庫
FreeMarker更適合做爲Model2框架(如Struts)的視圖組件,你也能夠在模板中使用JSP標記庫。apache
FreeMarker是免費的。編程
可以生成各類文本:HTML、XML、RTF、Java源代碼等等瀏覽器
易於嵌入到你的產品中:輕量級;不須要Servlet環境服務器
插件式模板載入器:能夠從任何源載入模板,如本地文件、數據庫等等app
你能夠按你所需生成文本:保存到本地文件;做爲Email發送;從Web應用程序發送它返回給Web瀏覽器
全部經常使用的指令:include、if/elseif/else、循環結構
在模板中建立和改變變量
幾乎在任何地方均可以使用複雜表達式來指定值
命名的宏,能夠具備位置參數和嵌套內容
名字空間有助於創建和維護可重用的宏庫,或者將一個大工程分紅模塊,而沒必要擔憂名字衝突
輸出轉換塊:在嵌套模板片斷生成輸出時,轉換HTML轉義、壓縮、語法高亮等等;你能夠定義本身的轉換
FreeMarker不是直接反射到Java對象,Java對象經過插件式對象封裝,以變量方式在模板中顯示
你可使用抽象(接口)方式表示對象(JavaBean、XML文檔、SQL查詢結果集等等),告訴模板開發者使用方法,使其不受技術細節的打擾
在模板語言中內建處理典型Web相關任務(如HTML轉義)的結構
可以集成到Model2 Web應用框架中做爲JSP的替代
支持JSP標記庫
爲MVC模式設計:分離可視化設計和應用程序邏輯;分離頁面設計員和程序員
字符集智能化(內部使用UNICODE)
數字格式本地化敏感
日期和時間格式本地化敏感
非US字符集能夠用做標識(如變量名)
多種不一樣語言的相同模板
<#recurse> 和<#visit>指令(2.3版本)用於遞歸遍歷XML樹。在模板中清楚和直覺的訪問XML對象模型。開源論壇 JForum 就是使用了 FreeMarker 作爲頁面模板。
1. 創建一個普通的java項目:testFreeMarker
2. 引入freemarker.jar包
3. 在項目目錄下創建模板目錄:templates
4. 在templates目錄下,創建a.ftl模板文件,內容以下:
|
5. 創建com.sxt.test.freemarker包,而後創建Test1.java文件,內容以下:
package com.sxt.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. 編譯和運行Test1.java文件,控制檯打印:
1、直接指定值
直接指定值能夠是字符串、數值、布爾值、集合及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表達式一致,類型可自動轉化!很是方便!
2、輸出變量值
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"]
使用點語法時,變量名字有和頂層變量同樣的限制,但中括號語法沒有任何限制。
3、字符串操做
1. 字符串鏈接
字符串鏈接有兩種語法:
(1)使用${..}或#{..}在字符串常量內插入表達式的值;
(2) 直接使用鏈接運算符「+」鏈接字符串。
如,下面兩種寫法等效:
${"Hello,${user}"}
${"Hello, " + user +"!"}
有一點須要注意: ${..}只能用於文本部分做爲插值輸出,而不能用於比較等其餘用途,如:
<#if ${isBig}>Wow!</#if>
<#if"${isBig}">Wow!</#if>
應該寫成:
<#ifisBig>Wow!</#if>
2. 截取子串
截取子串能夠根據字符串的索引來進行,若是指定一個索引值,則取得字符串該索引處的字符;若是指定兩個索引值,則截取兩個索引中間的字符串子串。如:
<#assign number="01234">
${number[0]} <#-- 輸出字符0-->
${number[0..3]}<#-- 輸出子串「0123」-->
4、集合鏈接操做
鏈接集合的運算符爲「+」
5、Map鏈接操做
Map鏈接操做的運算符爲「+」
6、算術運算符
FreeMarker表達式中支持「+」、「-」、「*」、「/」、「%」運算符。
7、比較運算符
表達式中支持的比較運算符有以下幾種:
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); |
8、邏輯運算符
1. &&: 邏輯與;
2. ||:邏輯或;
3. !:邏輯非
邏輯運算符只能用於布爾值。
9、內建函數
FreeMarker提供了一些內建函數來轉換輸出,能夠在任何變量後緊跟?,?後緊跟內建函數,就能夠經過內建函數來轉換輸出變量。
字符串相關經常使用的內建函數:
1. html:對字符串進行HTML編碼;
2. cap_first:使字符串第一個字母大寫;
3. lower_case:將字符串轉成小寫;
4. upper_case:將字符串轉成大寫;
集合相關經常使用的內建函數:
1. size:得到集合中元素的個數;
數字值相關經常使用的內建函數:
1. int:取得數字的整數部分。
舉例:
root.put("htm2", "<b>粗體</b>"); |
內建函數: ${htm2?html} |
10、空值處理運算符
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":"greenmouse", "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 標籤」和「指令」看作是同義詞便可。)
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 = 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/> |
增長被包含文件,放於templates目錄下:
文件內容以下:
模板文件中代碼以下:
測試include指令: <#include "included.txt" /> |
<#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 = "bjsxt@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) 2010-2011 北京尚學堂.</p> bjsxt@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。
參考Freemarker包中example目錄下webapp1項目!
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下面
if
詳情可見web項目:testFreeMarker2
做業:
1. 使用list標籤遍歷list容器時,如何獲取索引(下劃線加index便可獲取):
------------------------------------- 測試list索引_index <#list list as city> ${city}<br/>${city_index} <#if city_index==1> <#break> </#if> </#list> ************************************** 測試list中國_has_next <#list list as city> ${city}<br/>${city_index} <#if city_has_next> 我有下一項!------- ${city_index} </#if> </#list> |
2. 調用對象或類的方法?
3. .main特殊變量的做用
4. 定義的macro可否有返回值,有的話,怎麼處理?
=======================華麗分割線================
一、對activityMenu (集合對象)進行遍歷:
知識點:集合對象判空、集合遍歷、使用索引、if條件判斷
二、${MenuList?size} ——>獲得List集合的個數。 <#if (a_list?size >= 15)> : 判斷大小
三、若是是Long類型會有」,」區分,處理方式${c_List.refId?c}