20200420 --2020042004222關於ftl----FreeMarker知識梳理 入門和數值,類型

 

目錄

官網鏈接:http://freemarker.foofun.cn/index.html

1.是什麼

2.爲什麼

3.如何用

3.1 模板 + 數據模型 = 輸出

3.2  數據模型一覽(重要)

3.2.1  數據模型1-子變量

3.2.1  數據模型2----sequences 

3.2.3 標量類型的分類:

3.2.4 小結

3.3 模板一覽(重要,重要)

3.3.1 基本指令之if指令  <#if condition> 和   ,多個if ,else, else if 

3.3.2 基本指令之list指令 item,加逗號分隔,list, items, sep, else

<#list sequence as loopVariable>repeatThis

3.3.3 基本指令之include

3.3.4 聯合指令

3.3.5 使用內建函數

3.3.6 處理不存在變量  加! 或者 ??

3.4 數值,類型

3.4.1 基本內容-數值

3.4.2 基本內容-類型

3.4.3 基本內容-數據模型是哈希表

3.4.4 類型------標量

3.4.5 類型------容器

3.4.6 類型------子程序(方法和函數)

3.4.7 類型------子程序(用戶自定義指令)

3.4.8  類型------子程序(函數/方法和用戶自定義指令的比較)

3.4.9  類型------結點



官網鏈接:http://freemarker.foofun.cn/index.html

1.是什麼

FreeMarker 是一款 模板引擎: 即一種基於模板和要改變的數據, 並用來生成輸出文本(HTML網頁,電子郵件,配置文件,源代碼等)的通用工具。 它不是面向最終用戶的,而是一個Java類庫,是一款程序員可以嵌入他們所開發產品的組件。

模板編寫爲FreeMarker Template Language (FTL)。它是簡單的,專用的語言, 不是 像PHP那樣成熟的編程語言。 那就意味着要準備數據在真實編程語言中來顯示,比如數據庫查詢和業務運算, 之後模板顯示已經準備好的數據。在模板中,你可以專注於如何展現數據, 而在模板之外可以專注於要展示什麼數據。

Figure

2.爲什麼

這種方式通常被稱爲 MVC (模型 視圖 控制器) 模式,對於動態網頁來說,是一種特別流行的模式。 它幫助從開發人員(Java 程序員)中分離出網頁設計師(HTML設計師)。設計師無需面對模板中的複雜邏輯, 在沒有程序員來修改或重新編譯代碼時,也可以修改頁面的樣式。

而FreeMarker最初的設計,是被用來在MVC模式的Web開發框架中生成HTML頁面的,它沒有被綁定到 Servlet或HTML或任意Web相關的東西上。它也可以用於非Web應用環境中

FreeMarker 是 免費的, 基於Apache許可證2.0版本發佈。

3.如何用

3.1 模板 + 數據模型 = 輸出

假設在一個在線商店的應用系統中需要一個HTML頁面,和下面這個頁面類似:

<html>
<head>
  <title>Welcome!</title>
</head>
<body>
  <h1>Welcome John Doe!</h1>
  <p>Our latest product:
  <a href="products/greenmouse.html">green mouse</a>!
</body>
</html>

這裏的用戶名(上面的"Big Joe"),應該是登錄這個網頁的訪問者的名字, 並且最新產品的數據應該來自於數據庫,這樣它才能隨時更新。那麼不能直接在HTML頁面中輸入它們, 不能使用靜態的HTML代碼。此時,可以使用要求輸出的 模板。 模板和靜態HTML是相同的,只是它會包含一些 FreeMarker 將它們變成動態內容的指令:

<html>
<head>
  <title>Welcome!</title>
</head>
<body>
  <h1>Welcome ${user}!</h1>
  <p>Our latest product:
  <a href="${latestProduct.url}">${latestProduct.name}</a>!
</body>
</html>

模板文件存放在Web服務器上,就像通常存放靜態HTML頁面那樣。當有人來訪問這個頁面, FreeMarker將會介入執行,然後動態轉換模板,用最新的數據內容替換模板中 ${...} 的部分, 之後將結果發送到訪問者的Web瀏覽器中。訪問者的Web瀏覽器就會接收到例如第一個HTML示例那樣的內容 (也就是沒有FreeMarker指令的HTML代碼),訪問者也不會察覺到服務器端使用的FreeMarker。 (當然,存儲在Web服務器端的模板文件是不會被修改的;替換也僅僅出現在Web服務器的響應中。)

請注意,模板並沒有包含程序邏輯來查找當前的訪問者是誰,或者去查詢數據庫獲取最新的產品。 顯示的數據是在 FreeMarker 之外準備的,通常是一些 "真正的" 編程語言(比如Java) 所編寫的代碼。模板作者無需知道這些值是如何計算出的。事實上,這些值的計算方式可以完全被修改, 而模板可以保持不變,而且頁面的樣式也可以完全被修改而無需改動模板。 當模板作者(設計師)和程序員不是同一人時,顯示邏輯和業務邏輯相分離的做法是非常有用的, 即便模板作者和程序員是一個人,這麼來做也會幫助管理應用程序的複雜性。 保證模板專注於顯示問題(視覺設計,佈局和格式化)是高效使用模板引擎的關鍵。

爲模板準備的數據整體被稱作爲 數據模型。 模板作者要關心的是,數據模型是樹形結構(就像硬盤上的文件夾和文件),在視覺效果上, 數據模型可以是:

(root)
  |
  +- user = "Big Joe"
  |
  +- latestProduct
      |
      +- url = "products/greenmouse.html"
      |
      +- name = "green mouse"

Note:

上面只是一個形象化顯示;數據模型不是文本格式,它來自於Java對象。 對於Java程序員來說,root就像一個有 getUser() 和 getLatestProduct() 方法的Java對象, 也可以有 "user" 和 "latestProducts" 鍵值的Java Map對象。相似地,latestProduct 就像是有 getUrl() 和 getName() 方法的Java對象。

早期版本中,可以從數據模型中選取這些值,使用 user 和 latestProduct.name 表達式即可。如果我們繼續類推, 數據模型就像一個文件系統,那麼 "(root)" 和 latestProduct 就對應着目錄(文件夾),而 userurl 和 name 就是這些目錄中的文件。

總的來說,模板和數據模型是FreeMarker來生成輸出(比如第一個展示的HTML)所必須的:

模板 + 數據模型 = 輸出

3.2  數據模型一覽(重要)

3.2.1  數據模型1-子變量

正如已經看到的,數據模型的基本結構是樹狀的。 這棵樹可以很複雜,並且可以有很大的深度,比如:

上圖中的變量扮演目錄的角色(比如 root, animalsmouseelephantpythonmisc) 被稱爲 hashes (哈希表或哈希,譯者注)哈希表存儲其他變量(被稱爲 子變量), 它們可以通過名稱來查找(比如 "animals", "mouse" 或 "price")。

存儲單值的變量 (sizepricemessage 和 foo) 稱爲 scalars (標量,譯者注)。

如果要在模板中使用子變量, 那應該從根root開始指定它的路徑,每級之間用點來分隔開。要訪問 mouse 的 price ,要從root開始,首先進入到 animals ,之後訪問 mouse ,最後訪問 price 。就可以這樣來寫 animals.mouse.price

3.2.1  數據模型2----sequences 

另外一種很重要的變量是 sequences (序列,譯者注)。 它們像哈希表那樣存儲子變量,但是子變量沒有名字,它們只是列表中的項。 比如,在下面這個數據模型中, animals 和 misc.fruits 就是序列:

要訪問序列的子變量,可以使用方括號形式的數字索引下標。 索引下標從0開始(從0開始也是程序員的傳統),那麼第一項的索引就是0, 第二項的索引就是1等等。要得到第一個動物的名稱的話,可以這麼來寫代碼 animals[0].name。要得到 misc.fruits 中的第二項(字符串"banana")可以這麼來寫 misc.fruits[1]。(實踐中,通常按順序遍歷序列,而不用關心索引, 這點會在 後續介紹。)

3.2.3 標量類型的分類:

  • 字符串:就是文本,也就是任意的字符序列,比如上面提到的 ''m'', ''o'', ''u'', ''s'', ''e''。比如 name 和 size 也是字符串。

  • 數字:這是數值類型,就像上面的 price。 在FreeMarker中,字符串 "50" 和數字 50 是兩種完全不同的東西。前者是兩個字符的序列 (這恰好是人們可以讀的一個數字),而後者則是可以在數學運算中直接被使用的數值。

  • 日期/時間: 可以是日期-時間格式(存儲某一天的日期和時間), 或者是日期(只有日期,沒有時間),或者是時間(只有時間,沒有日期)。

  • 布爾值:對應着對/錯(是/否,開/關等值)類似的值。 比如動物可以有一個 protected (受保護的,譯者注) 的子變量, 該變量存儲這個動物是否被保護起來的值。

3.2.4 小結

數據模型可以被看成是樹形結構。

標量用於存儲單一的值。這種類型的值可以是字符串,數字,日期/時間或者是布爾值。

哈希表是一種存儲變量及其相關且有唯一標識名稱的容器。

序列是存儲有序變量的容器。存儲的變量可以通過數字索引來檢索,索引通常從0開始。

3.3 模板一覽(重要,重要)

最簡單的模板通常是普通的HTML文件(或者是其他任何文本文件; FreeMarker本身不屬於HTML)。當客戶端訪問某個頁面時, FreeMarker要發送HTML代碼至客戶端瀏覽器中去顯示。如果想要頁面動起來 (這裏指動態網頁技術,譯者注),那麼就要在HTML中放置能被FreeMarker所解析的特殊代碼片段

${...}: FreeMarker將會輸出真實的值來替換大括號內的表達式,這樣的表達式被稱爲 interpolation(插值,譯者注)

FTL 標籤 (FreeMarker模板的語言標籤): FTL標籤和HTML標籤有一些相似之處,但是它們是FreeMarker的指令,是不會在輸出中打印的。 這些標籤的名字以 # 開頭。(用戶自定義的FTL標籤則需要使用 @ 來代替 #,但這屬於更高級的話題了。)

註釋 註釋和HTML的註釋也很相似, 但是它們使用 <#-- and --> 來標識。 不像HTML註釋那樣,FTL註釋不會出現在輸出中(不出現在訪問者的頁面中), 因爲 FreeMarker會跳過它們。

其他任何不是FTL標籤,插值或註釋的內容將被視爲靜態文本, 這些東西不會被FreeMarker所解析;會被按照原樣輸出出來。

FTL標籤也被稱爲 指令。 這些指令在HTML的標籤 (比如: <table> 和 </table>) 和HTML元素 (比如: table 元素) 中的關係是相同的。(如果現在還沒有感覺到它們的不同, 那麼把“FTL標籤”和“指令”看做是同義詞即可。)

可以在 http://freemarker-online.kenshoo.com/ 上很方便的嘗試編寫模板

3.3.1 基本指令之if指令  <#if condition> 和 </#if>  ,多個if ,else, else if 

使用 if 指令可以有條件地跳過模板的一些片段。

比如,假設在 最初的示例 中, 想向你的老闆Big Joe特別地問好,可其他人不同:

此時,告訴 FreeMarker,當和 "Big Joe" 相同時 ", our beloved leader" (我們最尊敬的領導,譯者注) 纔是if條件中那唯一的 user 變量的值。 通常來講,如果 condition 是false(布爾值),那麼介於<#if condition> 和 </#if>  標籤中的內容會被略過。

 condition 的使用:

 == 是用來判斷它兩側的值是否相等的操作符, 比較的結果是布爾值,也就是true或者false

在 == 的左側,是 被引用的變量 我們很熟悉這樣的語法結構;最終它會被變量的值所替代。

通常來說, 在指令或插值中沒有被引號標註的內容都被視爲變量的引用。

右側則是指定的字符串, 在模板中的字符串 只能 放在引號內。

當價格爲0時,就會打印出 "Pythons are free today!":

<#if animals.python.price == 0> Pythons are free today! </#if>

和之前示例中,字符串被直接指定相似, 但這裏則是數字(0)被直接指定了。 請注意,這裏的數字 沒有 放在引號內。 如果將("0")放在引號中, 那麼FreeMarker就會將其誤判爲字符串了(也就是字符串0,譯者注)。

當價格不爲0時,則會打印出"Pythons are not free today!":

<#if animals.python.price != 0> Pythons are not free today! </#if>

 != 就是"不等於"。

<#if animals.python.price < animals.elephant.price> Pythons are cheaper than elephants today. </#if>

使用 <#else> 標籤可以指定當條件爲false時程序所要執行的內容。比如:

這個示例中,如果蟒蛇的價格比大象的價格低的話, 程序將會打印出 "Pythons are cheaper than elephants today."。 否則會打印 "Pythons are not cheaper than elephants today."。 後面也可以使用 elseif 來完善它:

如果變量本身就是布爾值(true/false),則可以直接讓其作爲 if 的 condition (判斷條件,譯者注):

3.3.2 基本指令之list指令 item,加逗號分隔,listitemssepelse

<#list sequence as loopVariable>repeatThis</#list>

當需要列表顯示內容時,list指令是必須的。

list 指令的一般格式爲: <#list sequence as loopVariable>repeatThis</#list>。 

repeatThis 部分將會在給定的 sequence 遍歷時在每一項中重複, 從第一項開始,一個接着一個。

在所有的重複中, loopVariable 將持有當前遍歷項的值。

這個變量僅存在於 <#list ...> 和 </#list> 標籤內。

sequence 可以是任意表達式, 比如我們可以列表顯示示例數據模型中的水果,就像這樣:

另一個列表相關的常見任務是:使用一些分隔符來列出水果,比如逗號:


 

所有的這些指令(listitemssepelse)可以聯合起來使用:

3.3.3 基本指令之include

使用 include 指令, 我們可以在模板中插入其他文件的內容。

假設要在一些頁面中顯示版權聲明的信息。那麼可以創建一個文件來單獨包含這些版權聲明, 之後在需要它的地方插入即可。比方說,我們可以將版權信息單獨存放在頁面文件 copyright_footer.html 中:

3.3.4 聯合指令

在頁面上也可以多次使用指令,而且指令間也可以很容易地相互嵌套。 比如,在 list 指令中嵌套 if 指令:

請注意,FreeMarker並不解析FTL標籤以外的文本、插值和註釋, 上面示例在HTML屬性中使用FTL標籤也不會有問題。

3.3.5 使用內建函數

內建函數很像子變量(如果瞭解Java術語的話,也可以說像方法), 它們並不是數據模型中的東西,是 FreeMarker 在數值上添加的。 爲了清晰子變量是哪部分,使用 ?(問號)代替 .(點)來訪問它們。常用內建函數的示例:

3.3.6 處理不存在變量  加! 或者 ??

數據模型中經常會有可選的變量(也就是說有時並不存在)。 除了一些典型的人爲原因導致失誤外,FreeMarker 絕不能容忍引用不存在的變量, 除非明確地告訴它當變量不存在時如何處理。這裏來介紹兩種典型的處理方法。

這部分對程序員而言: 一個不存在的變量和一個是 null 值的變量, 對於FreeMarker來說是一樣的,所以這裏所指的"丟失"包含這兩種情況。

3.4 數值,類型

3.4.1 基本內容-數值

變量 user 的 value 是"Big Joe"(字符串), today 的 value 是 Jul 6, 2007 (日期),todayHoliday 的 value 是false(布爾值,比如yes/no等值)。 lotteryNumbers 的 value 是包含20,14, 42, 8, 15的序列。當然在這種意義上, lotteryNumbers 是多值類型。它 包含 多個值(比如,其中的第二項的 value 是14),但是 lotteryNumbers 本身還是單值。它就像一個裝有其它很多東西的盒子 (或稱之爲容器,譯者注),但盒子作爲整體還是視作單獨的。最後還有一個數值 cargo,它的 value 是一個哈希表 (也是類似盒子一樣的東西)。所以說,數值就是存儲在變量中的(比如,在 user 或 cargo 或 cargo.name 中)的那個東西。但是, 不需要存儲於變量之中的數值也可以稱之爲數值,比如下面的數字100:

3.4.2 基本內容-類型

數值中非常重要的一個概念就是類型。比方說,變量 user 的類型是字符串,變量 lotteryNumbers 的類型是序列。數值的類型這個概念非常的重要,因爲它決定了這些數值可以在哪裏使用的最大限度。 比如說,使用 ${user / 2} 就是錯誤的,但是使用 ${cargo.weight / 2} 就能計算出結果,爲20, 因爲算術中的除法僅對數字類型的值有效,而不能用於字符串。 僅當 cargo 是一個哈希表變量時,表達式 cargo.name 纔可以使用點。也可以用 <#list ...> 指令來遍歷序列。而 <#if ...> 指令的條件只能是布爾值等。

3.4.3 基本內容-數據模型是哈希表

注意觀察每個數據模型的例子你也許能發現:被"(root)"所標識的內容就是哈希表類型的值。 當編寫如 user 這樣的代碼時,那就意味着要把"user"變量存儲在哈希表的根上。 就像編寫 root.user一樣,這裏但並沒有名"root"爲的變量, 那麼這就起不到任何作用了。

某些人也許會被這種數據模型的例子所困惑,也就是說,根哈希表包含更多的哈希表或序列 (lotteryNumbers and cargo)。其它就沒有更特殊的內容了。 哈希表包含其他變量,那些變量包含其它值,這些數值可以是字符串,數字等變量, 當然也可以是哈希表或序列變量。最初我們解釋過的,就像字符串和數字, 序列或哈希表也是一種值的表示形式。

3.4.4 類型------標量

3.4.5 類型------容器

3.4.6 類型------子程序(方法和函數)

3.4.7 類型------子程序(用戶自定義指令)

3.4.8  類型------子程序(函數/方法和用戶自定義指令的比較)

3.4.9  類型------結點

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章