杰瑞科技汇

Java如何导出HTML与Word?

核心思路

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

Java如何导出HTML与Word?-图1
(图片来源网络,侵删)
  1. 准备 HTML 内容:你可以从一个字符串、一个文件或一个 URL 加载 HTML。
  2. 选择一个转换库:该库需要能够解析 HTML,并将其元素(如 <p>, <h1>, <table>, <img> 等)映射到 Word 文档的对应元素(段落、标题、表格、图片等)。
  3. 执行转换:调用库的方法,将 HTML 内容写入到一个 .docx 文件中。
  4. 处理样式:这是最复杂也最关键的一步,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 的。

Java如何导出HTML与Word?-图2
(图片来源网络,侵删)

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();
        }
    }
}

注意docx4jHtmlImporter 可能需要一些额外的配置来处理某些 HTML 标签或 CSS 属性,但其默认功能已经能满足大部分需求。


使用模板引擎 (如 FreeMarker, Thymeleaf)

这种方法不直接“转换”HTML,而是生成一个符合 Word 结构的 XML(本质上就是 .docx 的内部结构)。

Java如何导出HTML与Word?-图3
(图片来源网络,侵删)

原理

  1. 你创建一个 Word 文档,用一些占位符(如 ${title}, ${content})标记需要动态填充的内容。
  2. 你将这个 Word 文档另存为 Word 2003 XMLFlat OPC XML 格式,这会得到一个巨大的 .xml 文件。
  3. 你使用 FreeMarker 或 Thymeleaf 这样的模板引擎,创建一个与这个 XML 文件对应的模板文件(.ftl.html)。
  4. 在 Java 代码中,准备数据(如标题、正文内容),然后让模板引擎将数据填充到模板中,生成最终的 XML 内容。
  5. 将这个 XML 内容保存为 .docx 扩展名,它就是一个合法的 Word 文档。

优点

  • 样式完美保留:因为 Word 模板本身就是最终样式,所以样式问题最少。
  • 性能高:生成过程非常快,没有复杂的解析和转换。
  • 逻辑与表现分离:设计模板和编写业务逻辑是分开的,非常清晰。

缺点

  • 不适用于“动态HTML转Word”:这种方法最适合基于数据生成固定格式的报告,而不是将一个已有的、复杂的网页导出。
  • 模板制作繁琐:需要手动制作和调试 Word 模板。

适用场景

  • 生成标准格式的财务报表、合同、工单等。
  • 报告的格式非常固定,只有数据是动态变化的。

总结与选择建议

特性 Apache POI + Flying Saucer docx4j 模板引擎
易用性 复杂 简单 中等(需制作模板)
样式支持 最好 良好 完美
功能灵活性 最强 一般(受模板限制)
性能 一般 良好 最快
主要用途 将任意复杂 HTML 尽可能完美地转为 Word 快速将 HTML 内容转为 Word 基于数据生成固定格式的 Word 报告

如何选择?

  1. 如果你的需求是“把一个网页或者一段富文本 HTML 导出成 Word,并且希望样式尽量保持一致”

    • 首选 docx4j:如果追求快速开发和简洁的代码,docx4j 是最佳选择,它的 HtmlImporter 非常好用。
    • docx4j 的样式转换结果不理想,或者你对样式有极高的要求:那么选择 Apache POI + Flying Saucer 组合,虽然配置复杂,但能提供最强的样式控制能力。
  2. 如果你的需求是“根据数据生成一个格式固定的 Word 文档,比如月度报告”

    • 使用模板引擎(FreeMarker/Thymeleaf),这是最稳定、最高效的方案,能确保生成的 Word 文件格式完全符合预期。

对于绝大多数“HTML 导出 Word”的场景,docx4j 是最推荐的起点,如果它无法满足你的样式需求,再考虑更复杂的 POI + Flying Saucer 方案。

分享:
扫描分享到社交APP
上一篇
下一篇