SpringBoot - 实现将Word文档转换为HTML教程(使用docx4j)
作者:hangge | 2025-11-28 08:31
我在之前的文章中演示了如何借助 docx4j 将 HTML 内容转换生成 DOCX 格式的 Word 文件(点击查看)。反之,有时我们需要 Word 文档转换成 HTML(包含图片、样式)方便在网页中浏览。这个同样借助 docx4j 可以实现,下面通过样例进行演示。
1,准备工作
首先我们需要在项目的 pom.xml 中添加 docx4j 以及相关的依赖。
<!-- docx4j核心依赖 --> <dependency> <groupId>org.docx4j</groupId> <artifactId>docx4j-core</artifactId> <version>11.4.8</version> </dependency> <!-- 如果需要用 JODConverter (LibreOffice) 做 .doc 转换,添加: --> <dependency> <groupId>org.jodconverter</groupId> <artifactId>jodconverter-local</artifactId> <version>4.4.6</version> </dependency> <!-- docx4j 的 JAXB 绑定(必须) --> <dependency> <groupId>org.docx4j</groupId> <artifactId>docx4j-JAXB-ReferenceImpl</artifactId> <version>11.4.8</version> <!-- 或最新 Jakarta 版本 --> </dependency> <!-- 添加 JAXB 依赖(JDK 11+) --> <dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId>jaxb-runtime</artifactId> <version>4.0.3</version> </dependency> <dependency> <groupId>jakarta.xml.bind</groupId> <artifactId>jakarta.xml.bind-api</artifactId> <version>4.0.0</version> </dependency>
2,样例代码(图片内联为 base64)
(1)首先我们创建一个 DocxToHtmlService,方便我们将上传的 .docx 转为 HTML 字符串,并把图片内联为 base64。
import org.docx4j.convert.out.HTMLSettings;
import org.docx4j.convert.out.html.AbstractHtmlExporter;
import org.docx4j.convert.out.html.HtmlExporterNG2;
import org.docx4j.model.images.AbstractWordXmlPicture;
import org.docx4j.model.images.ConversionImageHandler;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPart;
import org.docx4j.relationships.Relationship;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
@Service
public class DocxToHtmlService {
/**
* 将 docx 转 HTML,图片内联为 base64
*/
public String convertDocxToHtmlBase64(MultipartFile file) {
try {
// 1. 加载 docx
WordprocessingMLPackage wordMLPackage;
try (InputStream in = file.getInputStream()) {
wordMLPackage = WordprocessingMLPackage.load(in);
}
// 2. HTML 设置
HTMLSettings htmlSettings = new HTMLSettings();
htmlSettings.setWmlPackage(wordMLPackage);
// 3. 图片内联 Base64
htmlSettings.setImageHandler(new ConversionImageHandler() {
@Override
public String handleImage(AbstractWordXmlPicture pic, Relationship rel,
BinaryPart binaryPart) {
try {
byte[] imageBytes = binaryPart.getBytes();
String suggestedName = binaryPart.getPartName().getName();
String ext = "png";
int dotIndex = suggestedName.lastIndexOf('.');
if (dotIndex > 0) {
ext = suggestedName.substring(dotIndex + 1);
}
String base64 = Base64.getEncoder().encodeToString(imageBytes);
return "data:image/" + ext + ";base64," + base64;
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
});
// 4. 转 HTML
ByteArrayOutputStream out = new ByteArrayOutputStream();
StreamResult result = new StreamResult(out); // 必须用 StreamResult
AbstractHtmlExporter exporter = new HtmlExporterNG2();
exporter.html(wordMLPackage, result, htmlSettings);
return out.toString(StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
return "转换失败: " + e.getMessage();
}
}
}
(2)接着创建一个简单的 Controller,作用是接收上传的文件,然后调用 DocxToHtmlService 生成对应的 html 并返回。
import com.example.demo.service.DocxToHtmlService;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@RestController
public class ConvertController {
private final DocxToHtmlService docxToHtmlService;
public ConvertController(DocxToHtmlService docxToHtmlService) {
this.docxToHtmlService = docxToHtmlService;
}
@PostMapping(path = "/docx-to-html-base64", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<String> convertDocxToHtmlBase64(@RequestParam("file") MultipartFile file) {
try {
String html = docxToHtmlService.convertDocxToHtmlBase64(file);
return ResponseEntity.ok()
.contentType(MediaType.TEXT_HTML)
.body(html);
} catch (Exception e) {
return ResponseEntity.status(500).body("转换失败: " + e.getMessage());
}
}
}
3,运行测试
(1)假设我们准备了一个 docx 文件,内容如下:

(2)我们使用 Postman 测试这个 /docx-to-html-base64 接口,传入 docx 文件,可以看到成功返回生成的 html。

(3)其中图片也正常转换为内联 base64 数据。

附:将图片保存到文件夹中,并在 HTML 里用使用路径引用
1,需求说明
(1)上面样例生成的 HTML 里所有图片都是 base64 内联,但 base64 图片会让 HTML 文件变得非常大。
(2)因此在实际项目中,我们通常会将文档中的图片提取保存到指定的目录下,然后在 HTML 里用相对或绝对路径引用。
2,样例代码
(1)首先我们在 DocxToHtmlService 中添加一个新的方法,将上传的 .docx 转为 HTML 字符串,并把图片存到一个目录下。
import org.docx4j.Docx4J;
import org.docx4j.convert.out.HTMLSettings;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
@Service
public class DocxToHtmlService {
/**
* 将 docx 转为 HTML(图片放文件夹)
* @param file 上传的 docx 文件
* @param imageOutputDir 用于存放 html 相关图片的目录(会被创建)
* @return HTML 字符串(UTF-8)
*/
public String convertDocxToHtml(MultipartFile file, Path imageOutputDir) throws Exception {
// 保存临时文件(也可以直接用 InputStream)
Path tmp = Files.createTempFile("upload-", ".docx");
try (InputStream in = file.getInputStream()) {
Files.copy(in, tmp, java.nio.file.StandardCopyOption.REPLACE_EXISTING);
}
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(tmp.toFile());
// HTML 配置
HTMLSettings htmlSettings = Docx4J.createHTMLSettings();
htmlSettings.setWmlPackage(wordMLPackage);
// 指定图片保存路径与 HTML 中引用的 URI(相对或绝对都可以)
Files.createDirectories(imageOutputDir);
htmlSettings.setImageDirPath(imageOutputDir.toString());
// 在 HTML 中的路径前缀
htmlSettings.setImageTargetUri(imageOutputDir.getFileName().toString() + "/");
ByteArrayOutputStream out = new ByteArrayOutputStream();
// 将 docx 转为 HTML 输出到 out(Docx4J 提供的便捷方法)
Docx4J.toHTML(htmlSettings, out, Docx4J.FLAG_NONE);
return out.toString(StandardCharsets.UTF_8.name());
}
}
(2)然后 Controller 接收上传的文件,然后调用 DocxToHtmlService 的 convertDocxToHtml 方法,传入文件对象并指定图片存放目录,最后将生成的 html 并返回。
import com.example.demo.service.DocxToHtmlService;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.nio.file.Path;
import java.nio.file.Paths;
@RestController
public class ConvertController {
private final DocxToHtmlService docxToHtmlService;
public ConvertController(DocxToHtmlService docxToHtmlService) {
this.docxToHtmlService = docxToHtmlService;
}
@PostMapping(path = "/docx-to-html", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<String> convertDocxToHtml(@RequestParam("file") MultipartFile file) {
try {
// images 存放在服务本地 /tmp/docx-images-<timestamp>/ 下(根据需要修改)
Path imageDir = Paths.get(System.getProperty("java.io.tmpdir"),
"docx-images-" + System.currentTimeMillis());
String html = docxToHtmlService.convertDocxToHtml(file, imageDir);
// 返回 HTML 内容(Content-Type: text/html 可由客户端根据需要处理)
return ResponseEntity.ok()
.contentType(MediaType.TEXT_HTML)
.body(html);
} catch (Exception e) {
return ResponseEntity.status(500).body("转换失败: " + e.getMessage());
}
}
}
3,运行测试
(1)我们使用 Postman 测试这个 /docx-to-html 接口,传入 docx 文件,可以看到成功返回生成的 html,并且图片已经替换成具体的路径。

(2)打开该路径目录,可以看到图片确实已经存放在该目录下。

全部评论(0)