什么是 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=parseencoding
: 算作是字符串的表達式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"/>