freemarker語言
freemarker是一個模闆引擎,一個基于模闆生成文本輸出的通用工具,使用純java編寫。
freemarker被設計用來生成html web頁面,特别是基于mvc模式的應用程式
雖然freemarker具有一些程式設計的能力,但通常由java程式準備要顯示的資料,由freemarker生成頁面,通過模闆顯示準備的資料(如下圖)
freemarker不是一個web應用架構,而适合作為web應用架構一個元件。
freemarker與容器無關,因為它并不知道http或servlet;freemarker同樣可以應用于非web應用程式環境。
freemarker更适合作為model2架構(如struts)的視圖元件,你也可以在模闆中使用jsp标記庫。
freemarker是免費的。
能夠生成各種文本:html、xml、rtf、java源代碼等等
易于嵌入到你的産品中:輕量級;不需要servlet環境
插件式模闆載入器:可以從任何源載入模闆,如本地檔案、資料庫等等
你可以按你所需生成文本:儲存到本地檔案;作為email發送;從web應用程式發送它傳回給web浏覽器
所有常用的指令:include、if/elseif/else、循環結構
在模闆中建立和改變變量
幾乎在任何地方都可以使用複雜表達式來指定值
命名的宏,可以具有位置參數和嵌套内容
名字空間有助于建立和維護可重用的宏庫,或者将一個大工程分成子產品,而不必擔心名字沖突
輸出轉換塊:在嵌套模闆片段生成輸出時,轉換html轉義、壓縮、文法高亮等等;你可以定義自己的轉換
freemarker不是直接反射到java對象,java對象通過插件式對象封裝,以變量方式在模闆中顯示
你可以使用抽象(接口)方式表示對象(javabean、xml文檔、sql查詢結果集等等),告訴模闆開發者使用方法,使其不受技術細節的打擾
在模闆語言中内建處理典型web相關任務(如html轉義)的結構
能夠內建到model2 web應用架構中作為jsp的替代
支援jsp标記庫
為mvc模式設計:分離可視化設計和應用程式邏輯;分離頁面設計員和程式員
字元集智能化(内部使用unicode)
數字格式本地化敏感
日期和時間格式本地化敏感
非us字元集可以用作辨別(如變量名)
多種不同語言的相同模闆
1. 建立一個普通的java項目:testfreemarker
2. 引入freemarker.jar包
3. 在項目目錄下建立模闆目錄:templates
4. 在templates目錄下,建立a.ftl模闆檔案,内容如下:
你好啊,${user},今天你的精神不錯!
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檔案,控制台列印:
一、直接指定值
直接指定值可以是字元串、數值、布爾值、集合及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>
應該寫成:
<#ifisbig>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":"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 &lt; 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 else語句測試:
<#if random gte 90>
優秀!
<#elseif random gte 80>
良好!
一般!
----------------------------------------------------
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/>
增加被包含檔案,放于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}
<@m2 a="老高" b="老張" c="老馬" />
nested指令:
<#macro border>
<table border=4 cellspacing=0 cellpadding=4><tr><td>
<#nested>
</td></tr></table>
<@border >表格中的内容!</@border>
歐陽鴻:宏指令中,有沒有類似于方法的傳回值?
當運作 ftl 模闆時,就會有使用assign 和 macro 指令建立的變量的集合(可能是空的),可以從前一章節來看如何使用它們。像這樣的變量集合被稱為 namespace 命名空間。在簡單的情況下可以隻使用一個命名空間,稱之為 main namespace 主命名空間。因為通常隻使用本頁上的命名空間,是以就沒有意識到這點。
如果想建立可以重複使用的宏,函數和其他變量的集合,通常用術語來說就是引用
library 庫。使用多個命名空間是必然的。隻要考慮你在一些項目中,或者想和他人共享使用的時候,你是否有一個很大的宏的集合。但要確定庫中沒有宏(或其他變量)名和資料模型中變量同名,而且也不能和模闆中引用其他庫中的變量同名。通常來說,變量因為名稱沖突也會互相沖突。是以要為每個庫中的變量使用不同的命名空間。
定義b.ftl檔案:
<#macro copyright date>
<p>copyright (c) ${date} 北京尚學堂.</p>
<#assign mail = "[email protected]">
在a.ftl檔案中引入b.ftl,進而可以使用b.ftl中定義的宏和變量:
測試命名空間:
<#import "b.ftl" as bb />
<@bb.copyright date="2010-2011" />
${bb.mail}
<#assign mail="[email protected]" />
${mail}
<#assign mail="[email protected]" in bb />
執行後,控制台列印:
<p>copyright (c) 2010-2011 北京尚學堂.</p>
<a href="mailto:[email protected]" target="_blank">[email protected]</a>
如果你為 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>
<url-pattern>*.ftl</url-pattern>
</servlet-mapping>
<!-- 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中國_has_next
<#if city_has_next>
我有下一項!------- ${city_index}
2. 調用對象或類的方法?
3. .main特殊變量的作用
4. 定義的macro能否有傳回值,有的話,怎麼處理?
1、對activitymenu (集合對象)進行周遊:
知識點:集合對象判空、集合周遊、使用索引、if條件判斷
2、${menulist?size} ——>得到list集合的個數。 <#if (a_list?size >= 15)> : 判斷大小
3、如果是long類型會有”,”區分,處理方式${c_list.refid?c}