日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

全面探索 FreeMarker 模版引擎的扩展性

發布時間:2025/3/21 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 全面探索 FreeMarker 模版引擎的扩展性 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

FreeMarker 模版引擎簡介

FreeMarker 是一個采用 Java 開發的模版引擎,是一個基于模版生成文本的通用工具。 FreeMarker 被設計用來生成 HTML Web 頁面,特別是基于 MVC 模式的應用程序。雖然 FreeMarker 具有一些編程的能力,但通常由 Java 程序準備要顯示的數據,由 FreeMarker 生成頁面,并通過模板顯示準備的數據(如下圖)。

圖 1. FreeMarker 工作原理

點擊查看大圖

FreeMarker 非常簡單,只需要一個 Freemarker.jar 文件(無需任何配置文件)即可包含所有的功能。但 FreeMarker 的功能卻是非常的強大,相比較另外一個非常著名的 Java 模版引擎 —— Velocity 來說,FreeMarker 的功能讓您驚嘆,但其學習的曲線也較 Velocity 要長很多。

本文主要介紹如何利用 FreeMarker 強大的可擴展性來輸出各種文本信息,這不是 FreeMarker 的入門學習材料,如果您尚未對 FreeMarker 有所了解,或者還沒有使用過 FreeMarker 的話,那不妨先上手后再來閱讀本文。

FreeMarker 主要提供了如下幾個方面的擴展性功能:

  • 自定義宏
  • 自定義函數
  • 自定義模版文件加載器
  • 緩存處理
  • 異常處理
  • FreeMarker 自定義宏

    FreeMarker 和 Velocity 都提供可自定義宏的功能,但 FreeMarker 的宏功能更加強大,包括允許通過名稱和參數的位置進行參數傳遞;允許設置參數的默認值;支持宏的嵌套;宏可以先使用再聲明;支持命名空間等。

    下面我們針對這些功能給出一個簡單但是完整的演示例子,先看看代碼:

    清單 1. 宏定義文件 ( html.ftl )

    <#macro html title charset="utf-8" lang="zh-CN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=${charset}" /> <meta http-equiv="Content-Language" content="${lang}"/> <title>${title}</title> </head> <body> <#nested> </body> </html> </#macro>

    在這個宏定義文件中,我們聲明了一個名為 html 的宏,該宏是為了生成一個 HTML 頁面的框架。它具有三個參數分別是 title 、charset 和 lang ,其中 charset 和 lang 分別指定了默認的值。

    再來看看如何調用該宏:

    清單 2. 調用宏

    <#include "html.ftl"> <@html title="FreeMarker 宏測試 "> 歡迎使用 FreeMarker 模版引擎</@html>

    在 FreeMarker 中,用戶自定義的宏必須以 @ 開頭來調用,并傳入頁面標題 title 的參數。而 <@html> 標簽中包含的文本“歡迎使用 FreeMarker 模版引擎”將替換宏定義中的 <#nested> 標簽。因此這個模版將會生成如下的 HTML 信息:

    清單 3. 模版生成結果

    <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Language" content="zh-CN"/> <title>FreeMarker 宏測試 </title> </head> <body> 歡迎使用 FreeMarker 模版引擎</body> </html>

    而 Velocity 本身并不提供嵌套模版的功能,它必須依賴 Velocity-Tools 這個項目來實現。另外對于一些需要實現更復雜邏輯的宏,還可以通過 Java 類來進行定義。 FreeMarker 提供了一個 TemplateDirectiveModel 接口,通過實現該接口可以實現自定義宏的功能,這樣可以更好的跟應用邏輯進行集成,不過需要注意的是暫不支持通過參數的位置來調用宏,調用時必須指定參數名,該問題將在 FreeMarker 2.4 中得以解決。下面是一個簡單的例子:

    清單 4. 自定義宏功能的例子

    /*** 將標簽中的代碼全部轉為大寫并輸出* @author Winter Lau (javayou@gmail.com)* 使用方法:* <@upper>Welcome to http://www.oschina.net</@upper>*/ public class UpperDirective implements TemplateDirectiveModel {public void execute(Environment env,Map params, TemplateModel[] loopVars,TemplateDirectiveBody body)throws TemplateException, IOException {// Check if no parameters were given:if (!params.isEmpty()) {throw new TemplateModelException("This directive doesn't allow parameters.");}if (loopVars.length != 0) {throw new TemplateModelException("This directive doesn't allow loop variables.");}// If there is non-empty nested content:if (body != null) {// Executes the nested body. Same as <#nested> in FTL, except// that we use our own writer instead of the current output writer.body.render(new UpperCaseFilterWriter(env.getOut()));} else {throw new RuntimeException("missing body");}}/*** A {@link Writer} that transforms the character stream to upper case* and forwards it to another {@link Writer}.*/ private static class UpperCaseFilterWriter extends Writer {private final Writer out;UpperCaseFilterWriter (Writer out) {this.out = out;}public void write(char[] cbuf, int off, int len)throws IOException {char[] transformedCbuf = new char[len];for (int i = 0; i < len; i++) {transformedCbuf[i] = Character.toUpperCase(cbuf[i + off]);}out.write(transformedCbuf);}public void flush() throws IOException {out.flush();}public void close() throws IOException {out.close();}}}

    接下來我們需要重載 FreemarkerServlet ,植入該指令擴展,代碼如下:

    清單 5. 重載 FreemarkerServlet

    @Override protected Configuration createConfiguration() {Configuration cfg = super.createConfiguration();cfg.setSharedVariable("upper", new UpperDirective());return cfg; }

    在頁面模版中使用<@upper>Welcome to http://www.oschina.net</@upper>試試吧。

    FreeMarker 自定義函數

    與宏不同,宏一般用來執行某個過程,而函數可以定義返回值,例如對一組數據求和、平均值、最大值、最小值等等運算。 FreeMarker 的函數支持可變個數的參數。例如下面定義了一個求平均值的函數:

    清單 6. 求平均值的函數例子

    <#function avg nums...> <#local sum = 0> <#list nums as num> <#local sum = sum + num> </#list> <#if nums?size != 0> <#return sum / nums?size> </#if> </#function>

    其中函數名為 avg ,支持可變個數的參數 nums 。可用下面的代碼來要調用該函數:

    ${avg(3,5,100,3453)}

    跟宏相同,FreeMarker 也可以用 Java 來編寫自定義函數。例如我們用 Java 代碼來生成一個隨機的整數,其代碼如下:

    清單 7. 使用 Java 編寫的自定義函數

    /*** 生成一個隨機的整數* @author Winter Lau (javayou@gmail.com)* @url http://www.oschina.net*/ public class RandomFunction implements TemplateMethodModel {final static Random rnd_seed = new Random(System.currentTimeMillis());/* (non-Javadoc)* @see freemarker.template.TemplateMethodModel#exec(java.util.List)*/@SuppressWarnings("unchecked")public Object exec(List args) throws TemplateModelException {return rnd_seed.nextInt(Integer.parseInt((String)args.get(0)));}}

    同樣的,需要將該函數的定義植入 FreeMarker :

    cfg.setSharedVariable("rand",newRandomFunction());

    使用方法:${rand(1000)} 。

    FreeMarker 自定義模版文件加載器

    模版文件加載器用來告訴 FreeMarker 引擎到什么地方去加載模版文件。 FreeMarker 自帶了三種文件加載器,分別是:文件目錄加載器、類路徑加載器以及 Web 上下文加載器。當在 Web 環境中使用 FreemarkerServlet 來加載模版文件時,默認使用第三種加載器,并通過 Servlet 的配置 TemplatePath 來指定模版文件所存放的路徑,該路徑是相對于 Web 的根目錄的。

    在某種情況下,我們可能會希望把模版文件的源碼進行加密處理,例如我們使用 DES 加密方式將模版源文件加密后進行存儲,然后我們通過自行實現一個加密的模版文件加載器來讀取這些模版文件,解密后交給 FreeMarker 引擎解釋執行并得到執行的結果。 FreeMarker 為模版文件加載器定義了一個統一的接口 —— TemplateLoader ,該接口有以下四個方法:

    closeTemplateSource關閉模版資源
    findTemplateSource根據名稱返回指定的模版資源
    getLastModified返回模版資源最后一次修改的時間
    getReader返回讀取模版資源的 Reader

    為了簡單起見,我們可以在 FreeMarker 自帶的加載器上進行擴展,重寫 getReader 方法對讀取到的模版文件內容進行解密后生成一個新的 Reader 實例并返回(詳細過程不再敘述)。

    FreeMarker 自帶的幾個 TemplateLoader 分別是:

  • ClassTemplateLoader :基于類路徑的模版加載器
  • FileTemplateLoader :基于文件目錄的模版加載器
  • MultiTemplateLoader :多種加載器的混合
  • StringTemplateLoader :基于字符串的模版加載器
  • URLTemplateLoader :基于 URL 的模版加載器
  • WebappTemplateLoader :基于 Web 上下文的模版加載器
  • 重載模版加載器后通過下面代碼使之生效:

    cfg.setTemplateLoader(loader)

    FreeMarker 緩存處理

    FreeMarker 的緩存處理主要用于模版文件的緩存,一般來講,模版文件改動不會很頻繁,在一個流量非常大的網站中,如果頻繁的讀取模版文件對系統的負擔還是很重的,因此 FreeMarker 通過將模版文件的內容進行緩存,來降低模版文件讀取的頻次,降低系統的負載。

    當處理某個模版時,FreeMarker 直接從緩存中返回對應的 Template 對象,并有一個默認的機制來保證該模版對象是跟模版文件同步的。如果使用的時候 FreemarkerServlet 時,有一個配置項 template_update_delay 用來指定更新模版文件的間隔時間,相當于多長時間檢測一下是否有必要重新加載模版文件,0 表示每次都重新加載,否則為多少毫秒鐘檢測一下模版是否更改。

    FreeMarker 定義了一個統一的緩存處理接口 CacheStorage ,默認的實現是 MruCacheStorage 最近最少使用的緩存策略。一般情況下,很少需要對緩存進行擴展處理。您可以通過下面的代碼指定最大緩存的模版數:

    cfg.setCacheStorage(new freemarker.cache.MruCacheStorage(20, 250))

    其中第一個參數是最大的強引用對象數,第二個為最大的弱引用對象數。這兩個值 FreeMarker 默認的是 0 和 Integer.MAX_VALUE,表明模版緩存數是無限的。

    FreeMarker 異常處理

    當使用 FreeMarker 做為模版引擎的時候,可能發生的異常包括:

    配置異常:配置異常指的是 FreeMarker 初始化時發生的異常,例如錯誤的配置導致,該異常時由 FreeMarker 的 API 拋出來的。

    模版加載異常:模版加載異常可能是模版不存在或者沒有讀權限,或者是解析模版時發生錯誤,例如模版語法錯誤等。

    模版執行異常:模版執行異常是指模版已經成功的加載但在執行過程中由于代碼執行錯誤所拋出的異常,這類異常一般都是用戶的代碼導致。

    正常情況下,前兩種異常會在開發過程中就會發現并得以解決,而第三種異常往往跟實際的運行環境和數據有關,例如由于某些數據不存在導致的空指針異常等等。因此第三種異常才是我們真正需要關心以及監控的。

    為此,FreeMarker 定義了一個統一的異常處理接口 TemplateExceptionHandler 。該接口只有一個方法如下:

    void handleTemplateException(TemplateException te,Environment env,java.io.Writer out)

    通過調用 cfg.setTemplateExceptionHandler 來使用自定義的異常處理方法。下面是一個簡單的異常處理擴展的例子:

    清單 8. 異常處理擴展的例子

    class MyTemplateExceptionHandler implements TemplateExceptionHandler {public void handleTemplateException(TemplateException te, Environment env, java.io.Writer out) throws TemplateException {try {out.write("[ERROR: " + te.getMessage() + "]");} catch (IOException e) {throw new TemplateException("Failed to print error message. Cause: " + e, env);}}}...cfg.setTemplateExceptionHandler(new MyTemplateExceptionHandler());

    Eclipse 的 FreeMarker 插件

    為了方便編寫 FreeMarker 模版,您可以使用 FreeMarker IDE 這個 Eclipse 插件。該插件具有語法高亮、錯誤提示等功能。雖然該插件還有很多問題,而且已經很久沒更新了,但也能很好地使用。

    總結

    從上面對于 FreeMarker 的可擴展性的介紹來看,FreeMarker 確實是一個功能非常之強大的模版引擎,可以說遠在 Velocity 之上。不過從使用的直觀程度以及上手的時間來看,其復雜度也大大的超過了 Velocity 。當我們在面臨這兩個模版引擎的選擇時,不能只是從功能或者容易上手的角度來決定,更應該根據業務本身的需要綜合進行比較。

    相關主題

    • 查看?FreeMarker?相關信息。
    • 查看?Velocity?相關信息。
    • 查看 FreeMarker 的?Eclipse 編輯插件?相關信息。
    • “編寫自定義的 Velocity 指令”(developerWorks,2009 年 4 月):本文通過一個實際應用例子對 Velocity 的模板語言中的指令系統進行了介紹,并演示了如何通過編寫自定義的指令來擴展 Velocity 的功能。
    • Java 技術專區:尋找 Java 編程各方面的技術文章。

    from:?https://www.ibm.com/developerworks/cn/java/j-lo-freemarker/index.html

    總結

    以上是生活随笔為你收集整理的全面探索 FreeMarker 模版引擎的扩展性的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。