方案選型對比
| 方案 | 優點 | 缺點 | 推薦場景 |
| Jacob (COM) | 完美支援 Word 所有功能 | 僅 Windows、需 Office 安裝、重依賴 | Windows 伺服器、極複雜排版 |
| Apache POI (XWPF) | 純 Java、跨平台 | 樣式支援有限、複雜表格難控制 | 簡單文檔、純文字替換 |
| Java2Word | API 簡單、支援書籤/表格 | 第三方閉源、維護不確定 | 快速原型 |
| iText (RTF/PDF) | PDF 輸出強 | Word 輸出非原生 | 最終需 PDF |
| JSP 輸出 | 極簡單 | 樣式控制弱、分頁困難 | 極簡報表 |
| FreeMarker + Word XML | 樣式 100% 保真、跨平台、模板可視化編輯 | 模板製作需 Word 另存為 XML | 企業級報表、合同、複雜文檔首選 |
FreeMarker + Word XML 完整流程
步驟 1:設計 Word 模板
- Word 中排版好完整文檔(字型、段落、表格、頁眉頁腳、分頁符)
- 將動態內容標記為佔位符:
${title}、${user.name}、${list[i].amount}
- 列表區域用
<#list list as item>...</#list> 包裹
- 另存為「Word XML 格式」(.xml),非 .docx
步驟 2:轉換為 .ftl 模板
- 用文字編輯器開啟 .xml
- 將佔位符確認為 FreeMarker 語法(已兼容)
- 另存為
template.ftl,放入 classpath (如 src/main/resources/templates)
步驟 3:Java 程式碼生成
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.32</version>
</dependency>
public class WordExporter {
private final Configuration cfg = new Configuration(Configuration.VERSION_2_3_32);
public WordExporter() {
cfg.setClassForTemplateLoading(this.getClass(), "/templates");
cfg.setDefaultEncoding("UTF-8");
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
}
public void export(Map data, String outputPath) throws Exception {
Template t = cfg.getTemplate("contract.ftl");
try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputPath), "UTF-8"))) {
t.process(data, out);
}
}
}
步驟 4:資料模型範例
Map data = new HashMap<>();
data.put("title", "合作協議書");
data.put("date", LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
data.put("partyA", "甲方公司");
data.put("partyB", "乙方公司");
List
模板關鍵語法速查
| 需求 | FreeMarker 語法 |
| 變數輸出 | ${variable} / ${obj.prop} |
| 空值預設 | ${var!'預設值'} |
| 列表迴圈 | <#list items as item> ${item.no} </#list> |
| 條件判斷 | <#if user.vip>VIP<#else>普通</#if> |
| 數字格式化 | ${price?string.currency} / ${price?string['#,##0.00']} |
| 日期格式化 | ${date?string['yyyy-MM-dd']} |
| 插入圖片 | Word 模板預留書籤 → Java 端用 POI 替換書籤為圖片 (混合方案) |
進階:複雜表格跨頁、頁眉頁腳、目錄自動生成
- Word XML 完整保留
w:tbl、w:hdr/w:ftr、w:toc 等結構
- FreeMarker 僅替換文字節點,不破壞任何排版屬性
- 生成的 .doc (實為 XML) 用 Word 開啟後另存為 .docx 即為標準格式
常見問題
- 中文亂碼:模板檔案編碼必須 UTF-8,Java 端
OutputStreamWriter(..., "UTF-8")
- XML 命名空間衝突:模板中
xmlns:w="..." 保持原樣,勿手動修改
- 大檔案記憶體:FreeMarker 流式輸出,模板載入佔記憶體,超大模板可分片