FreeMarker 是一個基於模板的文本生成引擎,最初為 Web 視圖層設計(替代 JSP),憑藉強大的宏系統、指令體系、數據模型抽象,早已超越 Web 領域,廣泛應用於:
本文系統梳理 FreeMarker 核心概念、配置體系、模板語法進階與非 Web 場景集成方案。
process(dataModel, writer)。// 1. 構建 Configuration(僅在應用啟動時執行一次)
Configuration cfg = new Configuration(Configuration.VERSION_2_3_32);
cfg.setDirectoryForTemplateLoading(new File("/path/to/templates"));
cfg.setDefaultEncoding("UTF-8");
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
cfg.setLogTemplateExceptions(false);
cfg.setWrapUncheckedExceptions(true);
cfg.setSharedVariable("siteName", "MyApp"); // 全局共享變量
// 2. 獲取/緩存 Template
Template template = cfg.getTemplate("user/profile.ftl");
// 3. 準備數據模型
Map model = new HashMap<>();
model.put("user", userService.getById(1L));
model.put("roles", roleService.listByUserId(1L));
// 4. 渲染輸出
try (StringWriter out = new StringWriter()) {
template.process(model, out);
String html = out.toString(); // 直接獲取生成內容
// 寫入文件、返回響應、發送郵件...
}
<#-- 基礎輸出 -->
${user.name?html} <#-- HTML 轉義,防 XSS -->
${user.age!0} <#-- 缺失值默認 0 -->
${user.tags?join(", ")} <#-- 序列轉字符串 -->
${(user.balance/100)?string("0.00")} <#-- 數字格式化 -->
${user.createTime?datetime?string("yyyy-MM-dd HH:mm")} <#-- 日期格式化 -->
<#list users as u>
<#if u_index == 0>| ${u.name} | <#if u.vip>VIP<#else>普通#if> |
<#-- 定義宏 --> <#macro btn type="primary" size="md" label="按鈕" onclick=""> #macro> <#-- 調用宏 --> <@btn type="success" label="提交" onclick="submitForm()"/> <@btn label="取消" onclick="closeModal()"/> <#-- 使用默認值 -->
<#include "common/header.ftl"> <#-- 靜態包含,編譯期合併 -->
<@layout title="用戶詳情">
<#-- 動態填充區塊 -->
<#nested>
@layout>
| 加載器 | 適用場景 | 特點 |
|---|---|---|
| FileTemplateLoader | 開發/外部化模板 | 熱加載友好,需文件系統權限 |
| ClassTemplateLoader | 打包進 JAR 的內部模板 | 加載快、不可熱更、適合生產 |
| WebappTemplateLoader | 傳統 WAR 部署 | 基於 ServletContext 獲取資源 |
| MultiTemplateLoader | 多源混合 | 鏈式委託,優先級可控 |
cfg.setTemplateUpdateDelayMilliseconds(-1) — 生產環境推薦,重啟應用生效。cfg.setTemplateUpdateDelayMilliseconds(5000) — 開發環境,5秒檢查一次文件變更。TemplateCache 接口,接入 Redis/分布式緩存。默認 DefaultObjectWrapper 將 POJO/Map/List 自動包裝為 TemplateHashModel/TemplateSequenceModel。可通過 cfg.setObjectWrapper(new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_32).build()) 微調:
wrapper.setExposeFields(false)public class CodeGenerator {
private final Configuration cfg;
public CodeGenerator(String templateRoot) throws IOException {
cfg = new Configuration(Configuration.VERSION_2_3_32);
cfg.setDirectoryForTemplateLoading(new File(templateRoot));
cfg.setDefaultEncoding("UTF-8");
}
public void generateEntity(TableMeta meta, File outputDir) throws Exception {
Template tpl = cfg.getTemplate("entity.ftl");
Map model = Map.of(
"table", meta,
"columns", meta.getColumns(),
"pkg", "com.demo.entity",
"author", System.getProperty("user.name"),
"date", LocalDate.now()
);
File outFile = new File(outputDir, meta.getClassName() + ".java");
try (Writer w = new OutputStreamWriter(new FileOutputStream(outFile), "UTF-8")) {
tpl.process(model, w);
}
}
}
配合 entity.ftl 宏定義 getter/setter、Builder、toString 等樣板代碼,可在秒級生成數百個實體類,並保證風格統一。
!default 或 ?? 判空,否則拋 TemplateModelException。${flag?c} 輸出 "true/false",${flag?string("是","否")} 自定義標籤。1.23E7,用 ?string("0") 或 ?c 強制定點。u_index、u_has_next 僅在 #list 內部可用。FreeMarker 以模板即代碼、數據驅動視圖的極簡哲學,成為 Java 生態最通用的文本生成引擎。掌握其核心 API、指令體系、宏復用機制與配置調優,即可從 Web 視圖渲染延伸至代碼生成、文檔自動化、配置管理等諸多場景,實現「寫一次模板,到處生成代碼」的工程效能躍升。
官方文檔:FreeMarker Manual | 版本基線:2.3.32 (LTS)