在企業級應用中,動態生成 Word 文檔(合同、報表、證書等)是常見需求。Apache POI 是 Java 操作 Microsoft Office 格式的事實標準庫。本文演示兩種核心場景:純代碼生成文檔與基於模板佔位符替換生成文檔,針對舊版 .doc 格式(HWPF),並給出完整可運行代碼。
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.3.0</version> <!-- 請使用最新版 -->
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>5.3.0</version> <!-- HWPF 需要此模塊 -->
</dependency>
注意:HWPF 僅支持 .doc (Word 97-2003) 格式。現代 .docx (OOXML) 請使用 poi-ooxml 中的 XWPFDocument,功能更強、維護更活躍。
適用於結構固定、無現成模板的簡單導出。
public void exportDoc(String destFile, String content) {
try (ByteArrayInputStream bais = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
POIFSFileSystem fs = new POIFSFileSystem();
FileOutputStream fos = new FileOutputStream(destFile)) {
DirectoryEntry root = fs.getRoot();
root.createDocument("WordDocument", bais); // 核心:寫入流到 POIFS 文檔流
fs.writeFilesystem(fos); // 序列化為 .doc 文件
} catch (IOException e) {
throw new RuntimeException("生成 Word 失敗", e);
}
}
調用示例:
StringBuilder sb = new StringBuilder();
sb.append("姓名:張三\n性別:男\n身份證:1234567890\n");
// ... 追加更多內容
exportDoc("D:/output.doc", sb.toString());
準備一個 template.doc,內容包含佔位符如 ${name}、${idCard} 等。
public HWPFDocument replaceDoc(String templatePath, Map<String, String> placeholders) {
try (FileInputStream fis = new FileInputStream(templatePath)) {
HWPFDocument doc = new HWPFDocument(fis);
Range range = doc.getRange(); // 獲取全文範圍
for (Map.Entry<String, String> entry : placeholders.entrySet()) {
// 替換所有匹配的佔位符
range.replaceText("${" + entry.getKey() + "}", entry.getValue());
}
return doc; // 調用者負責 write 到輸出流
} catch (IOException e) {
throw new RuntimeException("模板處理失敗", e);
}
}
調用並保存:
Map<String, String> data = new HashMap<>();
data.put("name", "李四");
data.put("sex", "女");
data.put("idCard", "9876543210");
// ... 填充其他字段
HWPFDocument doc = replaceDoc("template.doc", data);
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
FileOutputStream fos = new FileOutputStream("D:/filled.doc")) {
doc.write(baos);
fos.write(baos.toByteArray());
}
| 類/接口 | 用途 | 備註 |
|---|---|---|
POIFSFileSystem | OLE2 複合文檔系統入口 | 舊版 .doc 底層存儲結構 |
HWPFDocument | Word 97-2003 文檔模型 | 需 poi-scratchpad 依賴 |
Range | 文檔文本範圍操作 | replaceText、getText 等 |
DirectoryEntry | POIFS 目錄節點 | 創建文檔流入口 |
${name})拆分,建議在 Word 中關閉「自動斷詞」或使用連續字符佔位符(如 #{name}#)。XWPFDocument (SXWPF 流式寫入)。docx4j 或 FreeMarker + docx 方案。<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.3.0</version>
</dependency>
// XWPF 替換佔位符示例
XWPFDocument doc = new XWPFDocument(new FileInputStream("template.docx"));
for (XWPFParagraph p : doc.getParagraphs()) {
for (XWPFRun run : p.getRuns()) {
String text = run.getText(0);
if (text != null && text.contains("${name}")) {
run.setText(text.replace("${name}", "張三"), 0);
}
}
}
// 表格、圖片、樣式操作豐富得多
Apache POI HWPF 可快速實現簡單 .doc 文檔的生成與模板填充,代碼量極小。但受限於舊格式架構,複雜排版、大文件、高併發場景下建議全面遷移至 .docx + XWPF 或模板引擎方案。掌握 Range.replaceText 核心 API,配合良好的模板設計,能覆蓋 80% 以上的業務導出需求。