杰瑞科技汇

Java如何用HTML生成Word文档?

使用 Apache POI + Flying Saucer (推荐)

这是目前最流行、功能最强大的方法之一,它的工作原理是:

Java如何用HTML生成Word文档?-图1
(图片来源网络,侵删)
  1. 编写 HTML/CSS: 你创建一个包含样式和内容的 HTML 文件。
  2. 渲染为 XHTML: Flying Saucer (一个 XHTML 渲染器) 会读取你的 HTML,并将其渲染成一个符合 XHTML 规范的文档模型。
  3. 转换为 XWPF: Apache POI 的 XWPF (XML Word Processing Format) 组件负责将这个 XHTML 模型中的内容(段落、表格、列表、图片等)写入到 .docx 文件的底层 XML 结构中。

优点

  • 样式支持强大: 可以使用大部分 CSS 属性来控制 Word 文档的样式,如字体、颜色、边距、背景色、浮动等。
  • 功能全面: 支持表格、列表、图片、超链接、页眉页脚等复杂元素。
  • 标准技术: Apache POI 是 Java 操作 Office 文档的事实标准,Flying Saucer 是成熟的 XHTML 渲染器,社区活跃,文档丰富。

缺点

  • 依赖较多: 需要同时引入 poi-ooxmlflying-saucer 等多个库。
  • 性能: 对于非常复杂的文档,渲染过程可能会比较耗时。
  • CSS 兼容性: 并非所有 CSS 属性都能被完美支持,需要一定的调试。

详细步骤和代码示例

添加 Maven 依赖

在你的 pom.xml 文件中添加以下依赖:

<dependencies>
    <!-- Apache POI for .docx file creation -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>5.2.3</version>
    </dependency>
    <!-- Flying Saucer for XHTML rendering -->
    <dependency>
        <groupId>org.xhtmlrenderer</groupId>
        <artifactId>flying-saucer-pdf</artifactId>
        <version>9.1.22</version>
    </dependency>
    <!-- 如果你只需要生成 Word,可以只用 flying-saucer-core,但 PDF 版本包含了所有核心功能 -->
    <dependency>
        <groupId>org.xhtmlrenderer</groupId>
        <artifactId>flying-saucer-core</artifactId>
        <version>9.1.22</version>
    </dependency>
</dependencies>

编写 Java 代码

import org.apache.poi.xwpf.converter.core.XWPFConverterException;
import org.apache.poi.xwpf.converter.xhtml.XHTMLConverter;
import org.apache.poi.xwpf.converter.xhtml.XHTMLOptions;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.jsoup.Jsoup;
import org.jsoup.helper.W3CDom;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class HtmlToWordWithPoi {
    public static void main(String[] args) {
        // 1. 准备你的 HTML 内容
        // 注意:最好使用完整的 HTML 结构,包括 <html>, <head>, <body>
        String htmlContent = "<!DOCTYPE html>"
                + "<html>"
                + "<head>"
                + "<meta charset=\"UTF-8\">"
                + "<style>"
                + "  body { font-family: 'Microsoft YaHei', sans-serif; }"
                + "  h1 { color: #333; text-align: center; }"
                + "  .highlight { background-color: yellow; font-weight: bold; }"
                + "  table { border-collapse: collapse; width: 100%; }"
                + "  th, td { border: 1px solid #dddddd; text-align: left; padding: 8px; }"
                + "  th { background-color: #f2f2f2; }"
                + "</style>"
                + "</head>"
                + "<body>"
                + "  <h1>HTML to Word 生成报告</h1>"
                + "  <p>这是一个通过 <span class=\"highlight\">Java</span> 从 HTML 生成的 Word 文档。</p>"
                + ""
                + "  <h2>员工信息表</h2>"
                + "  <table>"
                + "    <tr>"
                + "      <th>姓名</th>"
                + "      <th>职位</th>"
                + "      <th>部门</th>"
                + "    </tr>"
                + "    <tr>"
                + "      <td>张三</td>"
                + "      <td>软件工程师</td>"
                + "      <td>技术部</td>"
                + "    </tr>"
                + "    <tr>"
                + "      <td>李四</td>"
                + "      <td>产品经理</td>"
                + "      <td>产品部</td>"
                + "    </tr>"
                + "  </table>"
                + "</body>"
                + "</html>";
        // 2. 将 HTML 转换为 XWPFDocument
        XWPFDocument document = htmlToXWPFDocument(htmlContent);
        // 3. 保存为 .docx 文件
        try (OutputStream out = new FileOutputStream("output_from_poi.docx")) {
            document.write(out);
            System.out.println("Word 文档生成成功: output_from_poi.docx");
        } catch (IOException e) {
            e.printStackTrace();
        } catch (XWPFConverterException e) {
            e.printStackTrace();
        }
    }
    /**
     * 使用 Flying Saucer 将 HTML 字符串转换为 XWPFDocument 对象
     * @param htmlContent HTML 字符串
     * @return XWPFDocument 对象
     * @throws XWPFConverterException
     * @throws IOException
     */
    public static XWPFDocument htmlToXWPFDocument(String htmlContent) throws XWPFConverterException, IOException {
        // 使用 Jsoup 解析 HTML,使其成为标准的 XHTML
        org.jsoup.nodes.Document jsoupDoc = Jsoup.parse(htmlContent);
        org.w3c.dom.Document w3cDoc = new W3CDom().fromJsoup(jsoupDoc);
        // 创建一个空的 Word 文档
        XWPFDocument document = new XWPFDocument();
        // 设置转换选项
        XHTMLOptions options = XHTMLOptions.create();
        // 如果需要处理图片,可以设置图片根目录
        // options.setExtractor(new ThreadLocalFSImageExtractor(new File("C:/path/to/images")));
        // 执行转换
        XHTMLConverter.getInstance().convert(w3cDoc, document, options);
        return document;
    }
}

使用 docx4j

docx4j 是另一个功能强大的 Java 库,专门用于处理 Office Open XML 格式(即 .docx, .xlsx, .pptx),它也支持从 HTML 转换。

优点

  • 专注: 专门为处理 Office 文档设计,API 更贴近 Word 的内部结构。
  • 功能强大: 对 Word 的高级特性(如复杂样式、图表、内容控件等)支持非常好。
  • 性能: 通常比 POI+Flying Saucer 的组合性能更好。

缺点

  • 学习曲线: API 相对复杂,不如 POI+Flying Saucer 的“HTML 黑盒”方式直观。
  • 依赖: 需要引入 docx4j 的核心库和 org.jsoup 用于解析 HTML。

详细步骤和代码示例

添加 Maven 依赖

<dependencies>
    <!-- docx4j core -->
    <dependency>
        <groupId>org.docx4j</groupId>
        <artifactId>docx4j-core</artifactId>
        <version>11.4.4</version>
    </dependency>
    <!-- docx4j - OOXML import/export -->
    <dependency>
        <groupId>org.docx4j</groupId>
        <artifactId>docx4j-export-ooxml</artifactId>
        <version>11.4.4</version>
    </dependency>
    <!-- For HTML parsing -->
    <dependency>
        <groupId>org.jsoup</groupId>
        <artifactId>jsoup</artifactId>
        <version>1.15.3</version>
    </dependency>
</dependencies>

编写 Java 代码

import org.docx4j.Docx4J;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.File;
import java.io.FileOutputStream;
public class HtmlToWordWithDocx4j {
    public static void main(String[] args) throws Exception {
        // 1. 准备 HTML 内容 (与方法一相同)
        String htmlContent = "<!DOCTYPE html>"
                + "<html><head><style>"
                + "body { font-family: 'Microsoft YaHei'; }"
                + "h1 { color: blue; }"
                + "p { font-size: 12pt; }"
                + "table { border: 1px solid black; }"
                + "th, td { border: 1px solid black; padding: 5px; }"
                + "</style></head>"
                + "<body>"
                + "  <h1>docx4j 生成示例</h1>"
                + "  <p>这是一个使用 <b>docx4j</b> 生成的段落。</p>"
                + "  <table><tr><th>Header</th><td>Data</td></tr></table>"
                + "</body></html>";
        // 2. 创建 Word 包
        WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
        // 3. 获取主文档部分
        MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();
        // 4. 使用 Jsoup 解析 HTML
        Document doc = Jsoup.parse(htmlContent);
        Element body = doc.body();
        // 5. 递归地将 HTML 元素转换为 Word 内容
        htmlToWord(body, documentPart);
        // 6. 保存文件
        File output = new File("output_from_docx4j.docx");
        wordMLPackage.save(output);
        System.out.println("Word 文档生成成功: output_from_docx4j.docx");
    }
    private static void htmlToWord(Element element, MainDocumentPart documentPart) throws Exception {
        // 这里是一个简化的转换逻辑,实际项目中需要更复杂的处理
        // docx4j 提供了更高级的转换器,但手动转换可以更好地控制细节
        String tagName = element.tagName().toLowerCase();
        String text = element.ownText();
        if (tagName.equals("p") || tagName.equals("div")) {
            // 创建段落
            org.docx4j.wml.P p = docx4j.XmlUtils.deepCopy(documentPart.getContents().getBody().getPArray()[0]);
            org.docx4j.wml.R run = (org.docx4j.wml.R) p.getContent().get(0);
            ((org.docx4j.wml.Text) run.getContent().get(0)).setValue(text);
            documentPart.getContents().getBody().addObject(p);
        } else if (tagName.equals("h1")) {
            // 创建标题 (简化处理,实际应创建不同级别的标题)
            org.docx4j.wml.P p = docx4j.XmlUtils.deepCopy(documentPart.getContents().getBody().getPArray()[0]);
            org.docx4j.wml.R run = (org.docx4j.wml.R) p.getContent().get(0);
            ((org.docx4j.wml.Text) run.getContent().get(0)).setValue(text);
            // 设置标题样式... (需要更复杂的代码)
            documentPart.getContents().getBody().addObject(p);
        } else if (tagName.equals("table")) {
            // 创建表格... (逻辑更复杂)
            System.out.println("表格转换逻辑需要进一步实现");
        }
        // ... 其他标签处理
    }
}

注意: 上面的 docx4j 示例是一个简化的手动转换过程。docx4j 官方也提供了更高级的 HtmlImporter,但使用起来可能不如 POI+Flying Saucer 直接,对于复杂需求,建议查阅 docx4j 的官方文档。


使用 iText (不推荐)

iText 是一个著名的 PDF 库,它也支持操作 Word 文档,但其 Word 支持能力远不如 PDF,它更适合在已有 Word 模板的基础上进行内容填充,而不是从零开始用 HTML 生成。

Java如何用HTML生成Word文档?-图2
(图片来源网络,侵删)

为什么不推荐?

  • 功能有限: 对 Word 文档的样式和布局支持非常弱,很多 HTML/CSS 特性无法实现。
  • 易用性差: API 设计不友好,操作复杂。
  • 已过时: iText 5 的 Word 支持基于旧的 .doc 格式,非常陈旧,iText 7 的 Word 支持有所改善,但仍不是首选。

除非你有非常特殊的需求(比如在 PDF 和 Word 之间共享大量底层代码),否则强烈不推荐使用 iText 来生成 Word。


总结与选择建议

特性 Apache POI + Flying Saucer docx4j iText
易用性 (HTML 黑盒,简单直接) 中 (需要理解 Word 结构)
样式支持 (CSS 支持) 强 (更接近 Word 原生样式)
功能全面性 (表格、列表、图片等) 非常强 (支持高级 Word 特性)
性能 中等 中等
适用场景 绝大多数从 HTML 生成 Word 的场景,特别是对样式有要求的报表、合同等。 需要精细控制 Word 文档结构,或利用其高级功能的场景。 不推荐,除非已有其他项目依赖且需求简单。

最终建议:

  • 首选方案: 如果你只是想把一个设计好的 HTML 页面转换成 Word,并且希望样式能最大限度地保留,请使用 Apache POI + Flying Saucer,这是最平衡、最省心的选择。
  • 高级方案: 如果你需要对 Word 文档进行像素级的控制,或者需要生成包含复杂内容控件、引用等高级特性的文档,可以考虑 docx4j,但需要投入更多学习成本。
  • 避免方案: 尽量避免使用 iText 来处理 Word 文档生成。
分享:
扫描分享到社交APP
上一篇
下一篇