1. 程式人生 > >FreeMarker模板語言開發(整理版)

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 &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 標籤”和“指令”看做是同義詞即可。)

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="[email protected]com"  />

${mail}

<#assign mail="[email protected]com" in bb  />

${bb.mail}

執行後,控制檯列印:

測試名稱空間:

  <p>Copyright (C) 2017-2018 泰中.</p>

[email protected]

[email protected]

[email protected]

名稱空間命名規則

如果你為 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.程式碼如下:

http://www.blogjava.net/Images/OutliningIndicators/None.gif<servlet>
http://www.blogjava.net/Images/OutliningIndicators/None.gif        <servlet-name>freemarker</servlet-name>
http://www.blogjava.net/Images/OutliningIndicators/None.gif        <servlet-class>
http://www.blogjava.net/Images/OutliningIndicators/None.gif            freemarker.ext.servlet.FreemarkerServlet
http://www.blogjava.net/Images/OutliningIndicators/None.gif        
</servlet-class>
http://www.blogjava.net/Images/OutliningIndicators/None.gif        <!--下面的配置freemarke的ftl檔案的位置 -->
http://www.blogjava.net/Images/OutliningIndicators/None.gif        <init-param>
http://www.blogjava.net/Images/OutliningIndicators/None.gif            <param-name>TemplatePath</param-name>
http://www.blogjava.net/Images/OutliningIndicators/None.gif            <param-value>/</param-value>
http://www.blogjava.net/Images/OutliningIndicators/None.gif        </init-param>
http://www.blogjava.net/Images/OutliningIndicators/None.gif        <!-- 是否和伺服器(tommcat)一起啟動。-->
http://www.blogjava.net/Images/OutliningIndicators/None.gif        <load-on-startup>1</load-on-startup>
http://www.blogjava.net/Images/OutliningIndicators/None.gif    </servlet>
http://www.blogjava.net/Images/OutliningIndicators/None.gif
http://www.blogjava.net/Images/OutliningIndicators/None.gif    
<servlet-mapping>
http://www.blogjava.net/Images/OutliningIndicators/None.gif        <servlet-name>freemarker</servlet-name>
http://www.blogjava.net/Images/OutliningIndicators/None.gif        <url-pattern>*.ftl</url-pattern>
http://www.blogjava.net/Images/OutliningIndicators/None.gif    </servlet-mapping>
http://www.blogjava.net/Images/OutliningIndicators/None.gif
http://www.blogjava.net/Images/OutliningIndicators/None.gif
http://www.blogjava.net/Images/OutliningIndicators/None.gif
<servlet>
http://www.blogjava.net/Images/OutliningIndicators/None.gif  <!-- define a JspSupportServlet Object -->
http://www.blogjava.net/Images/OutliningIndicators/None.gif  <servlet-name>JspSupportServlet</servlet-name>
http://www.blogjava.net/Images/OutliningIndicators/None.gif  <servlet-class>org.apache.struts2.views.JspSupportServlet</servlet-class>
http://www.blogjava.net/Images/OutliningIndicators/None.gif  <!-- setting JspSupportServlet auto start -->
http://www.blogjava.net/Images/OutliningIndicators/None.gif  <load-on-startup>1</load-on-startup>
http://www.blogjava.net/Images/OutliningIndicators/None.gif </servlet>

 

3.在FreeMarker模板中使用assign指令匯入標籤庫。程式碼如下

<#assign s=JspTaglibs["/WEB-INF/struts-tags.tld"] /> 注:這裡我把struts-tags.tld放在WEB-INF下面

4.現在我們可以在FreeMarker模板中使用標籤了。