Word 本质上是流式文档(类似 HTML),所以“转富文本再转回 Word”的成功率和样式还原度,比 PDF 要高得多。
但依然会面临图片处理、复杂表格和样式降级的问题。以下是完整的技术方案与工程落地细节:
一、 核心技术选型 (Java 后端)
| 环节 | 推荐方案 | 备选方案 | 说明 |
|---|---|---|---|
| Word 转 HTML | docx4j + XHTMLImporter | 商业库 Aspose.Words | docx4j 开源免费,支持将 docx 转为带 CSS 的 HTML。商业库还原度几乎 100%,但收费。 |
| HTML 转 Word | docx4j (反向操作) | 商业库 Aspose.Words | 将前端传回的 HTML 转回 docx 格式。 |
| 图片处理 | MinIO 对象存储 | 转 Base64 嵌入 | 将 Word 中的图片提取存 MinIO,HTML 中放 URL;前端提交后,后端下载 URL 图片重新塞入 Word。 |
二、 完整业务流程与代码实现
步骤 1:前端上传 Word,后端解析为 HTML (JSON)
Maven 依赖:
xml
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j-JAXB-ReferenceImpl</artifactId>
<version>11.4.9</version>
</dependency>
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j-ImportXHTML</artifactId>
<version>11.4.9</version>
</dependency>
后端解析代码:
java
import org.docx4j.Docx4J;
import org.docx4j.convert.out.HTMLSettings;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
public String wordToHtml(MultipartFile file) {
try (InputStream is = file.getInputStream()) {
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(is);
// 配置 HTML 输出选项
HTMLSettings htmlSettings = Docx4J.createHTMLSettings();
htmlSettings.setWmlPackage(wordMLPackage);
// 图片处理策略:可以将图片提取并上传到 MinIO,返回 URL
// htmlSettings.setImageDirPath("...");
// htmlSettings.setImageTargetUri("...");
ByteArrayOutputStream os = new ByteArrayOutputStream();
Docx4J.toHTML(htmlSettings, os, Docx4J.FLAG_EXPORT_PREFER_XSL);
return os.toString("UTF-8"); // 返回给前端的 HTML 片段
} catch (Exception e) {
throw new RuntimeException("Word 解析失败", e);
}
}
步骤 2:后端返回 JSON 给前端
json
{
"docId": "123456",
"contentHtml": "<h1>合同标题</h1><p>甲方:<b>张三</b></p><img src='http://minio/image1.png' />"
}
步骤 3:前端富文本编辑
前端收到 HTML,塞入编辑器(如 WangEditor / Tiptap)。
用户在编辑过程中:
-
可能会修改文字。
-
可能会插入新图片(前端通常会把新图片上传到你们的 OSS/MinIO,并拿到新图片的 URL)。
-
点击保存,将最新的
contentHtml发给后端。
步骤 4:后端将 HTML 渲染成 Word (核心难点)
docx4j 提供了 XHTMLImporter 来将 HTML 转换为 Word 格式,但需要处理图片链接(因为 Word 无法直接渲染外链图片,必须把图片下载下来并嵌入到 Word 包里)。
Maven 依赖:
xml
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j-ImportXHTML</artifactId>
<version>11.4.9</version>
</dependency>
后端渲染代码:
java
import org.docx4j.convert.in.xhtml.XHTMLImporterImpl;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
public byte[] htmlToWord(String htmlContent) {
try {
// 1. 创建空的 Word 文档
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
// 2. 使用 XHTMLImporter 导入 HTML
XHTMLImporterImpl importer = new XHTMLImporterImpl(wordMLPackage);
// 如果 HTML 中带有 <img src="http://xxx">,importer 默认会自动去下载并嵌入
// 如果网络不通,可以用自定义的 ResourceResolver 拦截下载请求
// 将 HTML 转换为 Word 的段落集合,并插入到文档中
wordMLPackage.getMainDocumentPart().getContent().addAll(
importer.convert(htmlContent, null)
);
// 3. 保存为 byte 数组
ByteArrayOutputStream os = new ByteArrayOutputStream();
wordMLPackage.save(os);
return os.toByteArray();
} catch (Exception e) {
throw new RuntimeException("HTML 转 Word 失败", e);
}
}
步骤 5:上传新生成的 Word 到 MinIO
将上一步得到的 byte[] 传入 MinIO 的上传方法(对应你之前写的工具类):
java
public String saveWordToMinio(byte[] wordBytes, String fileName) {
try (ByteArrayInputStream bais = new ByteArrayInputStream(wordBytes)) {
minioClient.putObject(
config.getBucketName(),
fileName,
bais,
wordBytes.length,
"application/vnd.openxmlformats-officedocument.wordprocessingml.document"
);
return "https://your-minio/" + fileName;
} catch (Exception e) {
throw new RuntimeException("MinIO 上传失败", e);
}
}
三、 必须解决的 4 个“坑”
-
图片的“乾坤大挪移”
-
Word 转 HTML 时:Word 里的图片是二进制流。如果你的
docx4j没有配置图片提取,前端 HTML 里会直接显示data:image/png;base64,...(这会让 HTML 撑爆,浏览器直接卡死)。 -
正确做法:在
wordToHtml时,把图片提取出来上传到 MinIO,然后把 HTML 里的<img>替换成 MinIO 的公开 URL。 -
HTML 转 Word 时:
docx4j的XHTMLImporter遇到<img src="http://minio/xxx">,它底层会自动去下载。但如果你们是内网环境,可能下载失败。需要配置ResourceResolver。
-
-
表格样式降级
Word 中复杂的合并单元格(colspan, rowspan)在转成 HTML 再转回 Word 时,边框、底纹和宽度可能发生变化。建议在前端富文本编辑器中,限制用户使用复杂的表格操作。 -
字体的丢失
Word 特有很多专业字体(如方正小标宋、黑体)。转成 HTML 后,浏览器可能没有这些字体,只能显示为默认的微软雅黑。转回 Word 时,字体会被重新覆盖为默认字体。 -
分页符丢失
Word 有“分页符”,富文本没有这个概念。经过这套流程后,Word 会变成一坨长长的连续内容,如果需要严格分页,这套方案不适合。
💡 结论与替代方案
-
如果你的 Word 文档是纯文本、简单表格、图文混排的普通文章(如通知、新闻稿、简单的说明书),这套
docx4j的闭环方案是极其完美的,完全免费且效率极高。 -
如果你的 Word 是排版精美的合同、公文(包含红头、精准的页边距、骑缝章),请不要走这套流程。直接在前端用
docx-preview预览,只让用户填表(表单输入),后端用poi-tl(模板引擎)把数据填进去,直接吐出全新的 Word,这样排版100%精准。
本文介绍基于Java后端的Word与富文本双向转换方案:前端上传Word,后端用Apache POI或docx4j解析为HTML/JSON;前端在WangEditor等富文本编辑器中编辑,支持图片上传与URL替换;后端再将HTML通过Flying Saucer或docx4j渲染回嵌入图片的Word文档,并存入MinIO。重点解决图片嵌入、表格样式降级、字体丢失及分页符缺失四大技术难点。

被折叠的 条评论
为什么被折叠?



