核心思路
无论使用哪种库,核心思路都是相似的:

- 准备 HTML 内容:你可以从一个字符串、一个文件或一个 URL 加载 HTML。
- 选择一个转换库:该库需要能够解析 HTML,并将其元素(如
<p>,<h1>,<table>,<img>等)映射到 Word 文档的对应元素(段落、标题、表格、图片等)。 - 执行转换:调用库的方法,将 HTML 内容写入到一个
.docx文件中。 - 处理样式:这是最复杂也最关键的一步,HTML 的 CSS 样式(如
font-size,color,text-align)需要被正确地转换成 Word 的样式(如ParagraphFormat,Run的字体属性)。
Apache POI + Flying Saucer (推荐,功能最强大)
这是目前公认的功能最强大、控制最灵活的方案,它结合了两个优秀的库:
- Apache POI:用于创建和操作
.docx文件的 Java API,它是 Java 操作 Office 文档的“瑞士军刀”。 - Flying Saucer (xhtmlrenderer):一个 XHTML/CSS 渲染器,它可以将 HTML/CSS 渲染成可绘制的图像或文档。
原理:Flying Saucer 将 HTML 渲染成一个虚拟的文档,Apache POI 遍历这个虚拟文档的结构,用 POI 的组件在 Word 文档中重新构建出来。
优点
- 样式支持最好:能较好地支持 HTML 和 CSS 样式,是目前最接近“所见即所得”的方案。
- 功能最全面:可以处理复杂的 HTML 结构,如表格、列表、嵌套元素等。
- 高度可控:你可以通过 POI 对生成的 Word 文件进行精细化的后处理。
缺点
- 依赖复杂:需要引入多个较大的依赖库,项目体积会增加。
- 性能一般:对于非常大的 HTML 文件,转换过程可能较慢。
- 样式兼容性问题:并非所有的 CSS 属性都能完美支持,可能需要一些调试。
Maven 依赖
<dependencies>
<!-- Apache POI for .docx creation -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version> <!-- 使用较新版本 -->
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
<version>1.4</version>
</dependency>
<!-- Flying Saucer for HTML to XHTML rendering -->
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf</artifactId>
<version>9.1.22</version> <!-- 使用较新版本 -->
</dependency>
<!-- 如果你需要生成 PDF,可以加这个,否则不需要 -->
<!-- <dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf-itext5</artifactId>
<version>9.1.22</version>
</dependency> -->
</dependencies>
代码示例
这个例子会创建一个简单的 Word 文档,内容是带样式的 HTML。
import org.apache.poi.xwpf.usermodel.*;
import org.jsoup.Jsoup;
import org.jsoup.helper.W3CDom;
import org.xhtmlrenderer.pdf.ITextRenderer;
import org.xhtmlrenderer.swing.Java2DRenderer;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class HtmlToWordWithPOI {
public static void main(String[] args) {
String htmlContent = "<h1 style=\"color: red;\">Hello, Word!</h1>"
+ "<p>This is a <b>paragraph</b> with some <i>italic</i> text.</p>"
+ "<table border=\"1\" style=\"width:50%; border-collapse: collapse;\">"
+ "<tr><th>Header 1</th><th>Header 2</th></tr>"
+ "<tr><td>Cell 1</td><td>Cell 2</td></tr>"
+ "</table>";
try {
// 1. 使用 Flying Saucer 将 HTML 转换为 XHTML (一个格式良好的 XML)
org.jsoup.nodes.Document jsoupDoc = Jsoup.parse(htmlContent);
org.w3c.dom.Document doc = new W3CDom().fromJsoup(jsoupDoc);
// 2. 创建一个 ByteArrayOutputStream 来存储 Flying Saucer 生成的内容
// 注意:这里我们直接用 POI 来构建,而不是先转成 PDF 再处理。
// 更常见的做法是利用 Flying Saucer 的 DOM 结构来辅助 POI 的构建。
// 下面是一个更直接的 POI + Flying Saucer 结合的简化示例。
// 创建一个新的 Word 文档
XWPFDocument document = new XWPFDocument();
// 创建一个段落
XWPFParagraph paragraph = document.createParagraph();
XWPFRun run = paragraph.createRun();
run.setText("This is a title from POI directly.");
run.setBold(true);
run.setColor("FF0000"); // 红色
// 创建第二个段落
XWPFParagraph p2 = document.createParagraph();
XWPFRun r2 = p2.createRun();
r2.setText("This is a paragraph with bold and italic text. ");
r2.setBold(true);
XWPFRun r3 = p2.createRun();
r3.setText("This part is italic.");
r3.setItalic(true);
// 创建表格
XWPFTable table = document.createTable();
XWPFTableRow headerRow = table.getRow(0);
headerRow.getCell(0).setText("Header 1");
headerRow.addNewTableCell().setText("Header 2");
XWPFTableRow dataRow = table.createRow();
dataRow.getCell(0).setText("Cell 1");
dataRow.getCell(1).setText("Cell 2");
// 保存到文件
try (FileOutputStream out = new FileOutputStream("poi_flying_saucer_output.docx")) {
document.write(out);
System.out.println("Document created successfully: poi_flying_saucer_output.docx");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
说明:上面的例子为了简单,直接用 POI API 构建了和 HTML 类似的内容,一个更完整的 POI + Flying Saucer 结合方案会复杂得多,通常需要一个中间层来解析 Flying Saucer 生成的 DOM 树,然后递归地用 POI 的组件去创建 Word 文档,市面上有基于此方案封装好的开源项目,docx4j 的 HTML 导入功能就是基于 Flying Saucer 的。

docx4j (推荐,最简单直接)
docx4j 是一个专门用于处理 Office Open XML 格式(.docx, .xlsx, .pptx)的库,它有一个非常方便的 HtmlImporter 类,可以直接将 HTML 字符串转换为 Word 文档的底层结构。
优点
- 使用极其简单:API 设计非常直观,几行代码就能完成转换。
- 依赖单一:只需要
docx4j一个核心库(以及一些它依赖的库如javax.xml.bind等)。 - 功能强大:同样支持表格、列表、图片和大部分常用样式。
缺点
- 样式支持不如 POI+Flying Saucer 灵活:对于复杂的 CSS 样式,可能会有兼容性问题,转换效果可能需要微调。
- 项目活跃度:虽然项目仍在维护,但社区活跃度不如 Apache POI。
Maven 依赖
<dependencies>
<!-- docx4j core -->
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j-core</artifactId>
<version>11.4.4</version> <!-- 使用较新版本 -->
</dependency>
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j-export-fo</artifactId>
<version>11.4.4</version>
</dependency>
<!-- For JDK 9+ you might need these -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.3</version>
</dependency>
</dependencies>
代码示例
这个例子展示了 docx4j 的简洁性。
import org.docx4j.Docx4J;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.*;
public class HtmlToWordWithDocx4j {
public static void main(String[] args) {
String htmlContent = "<h1 style=\"color: blue;\">Hello from docx4j!</h1>"
+ "<p>This is a <strong>paragraph</strong> generated from HTML.</p>";
try {
// 1. 创建一个空的 WordprocessingMLPackage
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
// 2. 获取主文档部分
MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();
// 3. 使用 HtmlImporter 将 HTML 字符串导入
// 这会返回一个 org.docx4j.wml.ObjectFactory 创建的列表
HtmlImporterImpl htmlImporter = new HtmlImporterImpl(wordMLPackage);
List<Object> htmlElements = htmlImporter.importHtml(htmlContent);
// 4. 将导入的 HTML 元素添加到文档中
for (Object element : htmlElements) {
documentPart.addObject(element);
}
// 5. 保存文档
Docx4J.save(wordMLPackage, new File("docx4j_output.docx"), Docx4J.FLAG_NONE);
System.out.println("Document created successfully: docx4j_output.docx");
} catch (Exception e) {
e.printStackTrace();
}
}
}
注意:docx4j 的 HtmlImporter 可能需要一些额外的配置来处理某些 HTML 标签或 CSS 属性,但其默认功能已经能满足大部分需求。
使用模板引擎 (如 FreeMarker, Thymeleaf)
这种方法不直接“转换”HTML,而是生成一个符合 Word 结构的 XML(本质上就是 .docx 的内部结构)。

原理:
- 你创建一个 Word 文档,用一些占位符(如
${title},${content})标记需要动态填充的内容。 - 你将这个 Word 文档另存为
Word 2003 XML或Flat OPC XML格式,这会得到一个巨大的.xml文件。 - 你使用 FreeMarker 或 Thymeleaf 这样的模板引擎,创建一个与这个 XML 文件对应的模板文件(
.ftl或.html)。 - 在 Java 代码中,准备数据(如标题、正文内容),然后让模板引擎将数据填充到模板中,生成最终的 XML 内容。
- 将这个 XML 内容保存为
.docx扩展名,它就是一个合法的 Word 文档。
优点
- 样式完美保留:因为 Word 模板本身就是最终样式,所以样式问题最少。
- 性能高:生成过程非常快,没有复杂的解析和转换。
- 逻辑与表现分离:设计模板和编写业务逻辑是分开的,非常清晰。
缺点
- 不适用于“动态HTML转Word”:这种方法最适合基于数据生成固定格式的报告,而不是将一个已有的、复杂的网页导出。
- 模板制作繁琐:需要手动制作和调试 Word 模板。
适用场景
- 生成标准格式的财务报表、合同、工单等。
- 报告的格式非常固定,只有数据是动态变化的。
总结与选择建议
| 特性 | Apache POI + Flying Saucer | docx4j | 模板引擎 |
|---|---|---|---|
| 易用性 | 复杂 | 简单 | 中等(需制作模板) |
| 样式支持 | 最好 | 良好 | 完美 |
| 功能灵活性 | 最强 | 强 | 一般(受模板限制) |
| 性能 | 一般 | 良好 | 最快 |
| 主要用途 | 将任意复杂 HTML 尽可能完美地转为 Word | 快速将 HTML 内容转为 Word | 基于数据生成固定格式的 Word 报告 |
如何选择?
-
如果你的需求是“把一个网页或者一段富文本 HTML 导出成 Word,并且希望样式尽量保持一致”:
- 首选
docx4j:如果追求快速开发和简洁的代码,docx4j是最佳选择,它的HtmlImporter非常好用。 docx4j的样式转换结果不理想,或者你对样式有极高的要求:那么选择 Apache POI + Flying Saucer 组合,虽然配置复杂,但能提供最强的样式控制能力。
- 首选
-
如果你的需求是“根据数据生成一个格式固定的 Word 文档,比如月度报告”:
- 使用模板引擎(FreeMarker/Thymeleaf),这是最稳定、最高效的方案,能确保生成的 Word 文件格式完全符合预期。
对于绝大多数“HTML 导出 Word”的场景,docx4j 是最推荐的起点,如果它无法满足你的样式需求,再考虑更复杂的 POI + Flying Saucer 方案。
