FreeMarker <#include> 指令擴展


什么是 FreeMarker

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

FreeMarker 內建指令 —— include

FreeMarker 中包含很多內建的指令,猶如 JSP 中的標簽一樣。這里主要講下 include 指令。參考 Freemarker 官方文檔,其語法格式如下:
<#include path> 或 <#include path options>
其中:

  • path: 要包含文件的路徑;一個算作是字符串的表達式。(用其他話說, 它不用是一個固定的字符串,它也可以是像 profile.baseDir + "/menu.ftl" 這樣的東西。)
  • options: 一個或多個這樣的選項: encoding=encoding, parse=parse
    • encoding: 算作是字符串的表達式
    • parse: 算作是布爾值的表達式(為了向下兼容,也接受一部分字符串值)
    • ignore_missing: 算作是布爾值的表達式

你可以使用它在你的模板中插入另外一個 FreeMarker 模板文件 (由 path 參數指定)。 被包含模板的輸出格式是在 include 標簽出現的位置插入的。被包含的文件和包含它的模板共享變量,就像是被復制粘貼進去的一樣。值得注意的是,include 指令不能由被包含文件的內容所替代,它只是當 FreeMarker 每次在模板處理期間到達 include 指令時處理被包含的文件。也就是說,這邊可以在執行時,動態指定需包含的 FreeMarker 模板文件。

一個錯誤場景

假設有這樣一個場景,需要介紹全國的每一個省。每個省有一個對應的以省份名稱命名的 FreeMarker 模板(當然,這些模板都是在一個總的模板下顯示),如:js.ftl。
一般來說,我們可以這樣寫總的模板,來達到動態包含省份的模板。

<!DOCTYPE html>
<html>
  <head>
      ...
  </head>
  <body>
    <#include "/${province}.ftl"/>
  </body>
</html>

看着上面的代碼,是不是覺得 FreeMarker 還是很方便很強大的啊!但是坑來了,假設目前項目還沒有開發完成,也就是說,有的省份還沒有對應的 FreeMarker 模板,那么會出現什么情況呢?直接報錯了。對於項目沒做完這種事,我們得找個臨時方案啊,給那些沒有開發模板的省份來個默認頁面,那么用 include 指令貌似有點力不從心。如何解決呢?FreeMarker 有自定義指令的功能,那就定義一個加強版的 include 指令吧,使得該指令在找不到指定模板的情況下,包含一個默認的模板。

public class IncludeXMacro implements TemplateDirectiveModel {

    private static final String PATH_PARAM = "template";

    private static final String DEFALUT_PATH_PARAM = "default_template";

    @Override
    public void execute(Environment environment, @SuppressWarnings("rawtypes") Map params, TemplateModel[] templateModel,
            TemplateDirectiveBody directiveBody) throws TemplateException, IOException {
        TemplateLoader templateLoader = environment.getConfiguration().getTemplateLoader();

        String fullTemplatePath = getFullTemplatePath(environment, params, PATH_PARAM);
        if (templateLoader.findTemplateSource(fullTemplatePath) != null) {
            environment.include(environment.getTemplateForInclusion(fullTemplatePath, null, true));
        } else {
            String defaultFullTemplatePath = getFullTemplatePath(environment, params, DEFALUT_PATH_PARAM);
            if (templateLoader.findTemplateSource(defaultFullTemplatePath) == null) {
                throw new _MiscTemplateException(environment, "Missing template file path:" + defaultFullTemplatePath);
            }
            environment.include(environment.getTemplateForInclusion(defaultFullTemplatePath, null, true));
        }
    }

    /**
     * Description:獲取ftl完整路徑 <br>
     */
    private String getFullTemplatePath(Environment environment, @SuppressWarnings("rawtypes") Map params, String templatePath)
            throws MalformedTemplateNameException {
        if (!params.containsKey(templatePath)) {
            throw new MalformedTemplateNameException("missing required parameter '" + templatePath, "'");
        }

        String currentTemplateName = environment.getTemplate().getName();
        final String baseName = FilenameUtils.getPath(currentTemplateName);

        final String targetName = params.get(templatePath).toString();
        final String fullTemplatePath = environment.toFullTemplateName(baseName, targetName);

        return fullTemplatePath;
    }
}

FreeMarker 在這邊就不詳細講了,官網講的很清楚。我們給這個自定義的指令起個名字:includeX,然后就可以這樣使用了:
<@includeX template="/${province}.ftl" default_template="/default.ftl"/>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM