首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 生成 Word 文檔方案大比拼:FreeMarker、POI、iText 選型指南

     編輯:Java 相關知識

方案對比總覽

方案核心原理模板維護複雜排版圖片/表格Android 支援授權
FreeMarker + XML/FTL模板引擎替換佔位符,生成 Word XML (OOXML)⭐⭐⭐ Word 編輯另存為 XML⭐⭐⭐⭐ 支援條件、循環、巢狀⭐⭐ Base64 嵌入,較繁瑣❌ 依賴 AWT/字體包Apache 2.0
Apache POI (XWPF)直接操作 OOXML DOM 模型⭐⭐ Word 模板含 ${} 佔位符⭐⭐⭐ 程式化控制,靈活但代碼量大⭐⭐⭐⭐ 原生支援圖片、表格、樣式✅ 純 Java,可裁剪依賴Apache 2.0
iText 7 + pdfHTMLHTML/CSS 轉 PDF,再轉 Word(或直接生成 PDF)⭐⭐⭐ HTML 模板最易維護⭐⭐⭐ CSS 排版強大⭐⭐⭐ HTML 標籤原生支援✅ 支援 AndroidAGPL / 商業授權
Aspose.Words商業級文檔處理引擎⭐⭐⭐ 支援 Word 原生模板⭐⭐⭐⭐⭐ 完美還原 Word 渲染⭐⭐⭐⭐⭐ 企業級功能全✅ 支援商業收費(貴)
JodConverter (LibreOffice)調用 LibreOffice 服務轉換⭐⭐⭐ 任意格式互轉⭐⭐⭐⭐ 依賴 LibreOffice 渲染⭐⭐⭐⭐ 原生支援❌ 需安裝 LibreOfficeLGPL

方案一:FreeMarker 生成 Word(適合報表、證書、合同)

核心步驟

  1. Word 編寫模板 → 另存為 XML (Word 2003 XML) 或 .ftl。
  2. 模板中使用 ${field}、<#list items as item>${item.name} 等指令。
  3. 圖片需轉 Base64 字符串嵌入 XML:${base64Img}。
  4. Java 代碼加載模板、填充數據、輸出文件。

關鍵代碼

public class DocxGenerator {
    private final Configuration cfg = new Configuration(Configuration.VERSION_2_3_32);
    
    public DocxGenerator() {
        cfg.setClassForTemplateLoading(this.getClass(), "/templates");
        cfg.setDefaultEncoding("UTF-8");
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
    }
    
    public void generate(Map data, String templateName, File output) 
            throws IOException, TemplateException {
        Template template = cfg.getTemplate(templateName + ".ftl");
        try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(output), "UTF-8"))) {
            template.process(data, out);
        }
    }
    
    // 圖片轉 Base64 輔助
    public String imageToBase64(File imgFile) throws IOException {
        byte[] bytes = Files.readAllBytes(imgFile.toPath());
        return Base64.getEncoder().encodeToString(bytes);
    }
}

模板技巧:列表換行與條件顯示

<!-- 列表項自動換行 -->
<#list deductItems as item>
    <w:t>${item}</w:t><w:br/>


<!-- 條件顯示 -->
<#if score >= 60>
    <w:t>通過</w:t>
<#else>
    <w:t style="color:red">不及格</w:t>

方案二:Apache POI 操作 Word(適合複雜動態文檔、需精確控制樣式)

核心類

  • XWPFDocument:文檔模型根節點。
  • XWPFParagraph/XWPFRun:段落與文本運行(樣式最小單位)。
  • XWPFTable/XWPFTableRow/XWPFTableCell:表格結構。

模板替換工具類(支援段落、表格、圖片)

public class PoiDocxUtil {
    public static XWPFDocument renderTemplate(String templatePath, Map data) 
            throws IOException, InvalidFormatException {
        try (FileInputStream fis = new FileInputStream(templatePath)) {
            XWPFDocument doc = new XWPFDocument(OPCPackage.open(fis));
            
            // 1. 替換段落文本(含表格內段落)
            replaceInParagraphs(doc.getParagraphs(), data);
            for (XWPFTable table : doc.getTables()) {
                for (XWPFTableRow row : table.getRows()) {
                    for (XWPFTableCell cell : row.getTableCells()) {
                        replaceInParagraphs(cell.getParagraphs(), data);
                    }
                }
            }
            
            // 2. 處理圖片佔位符:${img:logo} -> 圖片流
            processImages(doc, data);
            
            return doc;
        }
    }
    
    private static void replaceInParagraphs(List paragraphs, Map data) {
        for (XWPFParagraph p : paragraphs) {
            for (XWPFRun run : p.getRuns()) {
                String text = run.getText(0);
                if (text == null) continue;
                for (Map.Entry e : data.entrySet()) {
                    String placeholder = "${" + e.getKey() + "}";
                    if (text.contains(placeholder)) {
                        text = text.replace(placeholder, e.getValue().toString());
                        run.setText(text, 0);
                    }
                }
            }
        }
    }
    
    private static void processImages(XWPFDocument doc, Map data) throws IOException, InvalidFormatException {
        // 遍歷 runs 尋找 ${img:key} 格式佔位符
        // 刪除佔位符 run,在同一段落插入圖片 run
        // 代碼略...
    }
}

方案三:HTML 轉 Word(現代化、前後端共用模板)

使用 iText 7 pdfHTML 或 Flying Saucer 將 HTML+CSS 轉為 PDF,再用 LibreOffice/Pandoc 轉 Word;或直接生成 PDF 交付(現代業務多接受 PDF)。

選型決策樹

  1. 需在 Android/無圖形環境運行? → 排除 FreeMarker (AWT 依賴)、POI 需裁剪 ooxml-schemas 依賴。
  2. 模板由業務人員維護(Word 操作)? → FreeMarker (XML/FTL) 或 POI (Word 模板)。
  3. 極其複雜排版(郵件合併、目錄、引用、水印)? → Aspose.Words 或 JodConverter (LibreOffice)。
  4. 預算有限、開源優先? → POI 功能最全、社區活躍;FreeMarker 模板分離度最高。
  5. 前端已有 HTML 模板? → HTML→PDF→Word 鏈路或直接交付 PDF。

生產環境避坑指南

  • 字體缺失:Linux 服務器安裝中文字體 yum install fontconfig dejavu-sans-fonts google-noto-sans-cjk-ttc-fonts,或在代碼註冊字體目錄。
  • 大文件內存溢出:POI 使用 XWPFDocument 全量載入 DOM,大文件改用 SAX 事件流模式 (XWPFDocument.write() 仍需完整 DOM),極大文檔考慮分章生成再合併。
  • 版本衝突:POI 5.x 需 JDK 8+,ooxml-schemas 替換為 poi-ooxml-full 避免傳遞依賴地獄。
  • 併發安全:FreeMarker Configuration 線程安全可單例;POI XWPFDocument 非線程安全,每請求新建實例。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved