天天看點

FreeMarker的基礎文法

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 < 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>

[email protected]

[email protected]

<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.代碼如下:

&lt;servlet&gt;

        &lt;servlet-name&gt;freemarker&lt;/servlet-name&gt;

        &lt;servlet-class&gt;

            freemarker.ext.servlet.freemarkerservlet

        &lt;/servlet-class&gt;

        &lt;!--下面的配置freemarke的ftl檔案的位置 --&gt;

        &lt;init-param&gt;

            &lt;param-name&gt;templatepath&lt;/param-name&gt;

            &lt;param-value&gt;/&lt;/param-value&gt;

        &lt;/init-param&gt;

        &lt;!-- 是否和伺服器(tommcat)一起啟動。--&gt;

        &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;

    &lt;/servlet&gt;

    &lt;servlet-mapping&gt;

        &lt;url-pattern&gt;*.ftl&lt;/url-pattern&gt;

    &lt;/servlet-mapping&gt;

  &lt;!-- define a jspsupportservlet object --&gt;

  &lt;servlet-name&gt;jspsupportservlet&lt;/servlet-name&gt;

  &lt;servlet-class&gt;org.apache.struts2.views.jspsupportservlet&lt;/servlet-class&gt;

  &lt;!-- setting jspsupportservlet auto start --&gt;

  &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;

 &lt;/servlet&gt;

3.在freemarker模闆中使用assign指令導入标簽庫。代碼如下

&lt;#assign s=jsptaglibs["/web-inf/struts-tags.tld"] /&gt; 注:這裡我把struts-tags.tld放在web-inf下面

if

詳情可見web項目:testfreemarker2

作業:

1.      使用list标簽周遊list容器時,如何擷取索引(下劃線加index即可擷取):

-------------------------------------

測試list索引_index

&lt;#list list as city&gt;

         ${city}&lt;br/&gt;${city_index}

         &lt;#if city_index==1&gt;

                   &lt;#break&gt;

         &lt;/#if&gt;

**************************************

測試list中國_has_next

         &lt;#if city_has_next&gt;

                   我有下一項!------- ${city_index}

2.      調用對象或類的方法?

3.      .main特殊變量的作用

4.      定義的macro能否有傳回值,有的話,怎麼處理?

1、對activitymenu (集合對象)進行周遊:

知識點:集合對象判空、集合周遊、使用索引、if條件判斷

2、${menulist?size}  ——&gt;得到list集合的個數。  &lt;#if (a_list?size &gt;= 15)&gt; :  判斷大小

3、如果是long類型會有”,”區分,處理方式${c_list.refid?c}