返回 导航

SpringBoot / Cloud

hangge.com

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 接收上传的文件,然后调用 DocxToHtmlServiceconvertDocxToHtml 方法,传入文件对象并指定图片存放目录,最后将生成的 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)

回到顶部