You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Java将VSDX文件嵌入DOCX文件并生成可编辑字节数组

Java实现将VSDX文件嵌入DOCX并返回可编辑的byte[]

核心思路

要让VSDX在DOCX中保持可编辑性,不能将其转为图片插入,而是要以OLE嵌入对象的形式添加到DOCX中。这样用户下载DOCX后,双击嵌入的Visio对象就能打开Visio进行编辑。我们使用Apache POI库来操作DOCX文档,它支持OLE对象的嵌入。

依赖准备

需要引入Apache POI的相关依赖(Maven示例):

<dependencies>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>5.2.5</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>5.2.5</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-scratchpad</artifactId>
        <version>5.2.5</version>
    </dependency>
</dependencies>

实现代码

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.xwpf.usermodel.*;

import java.io.*;

public class VisioToDocxEmbedder {

    public static byte[] embedVsdxIntoDocx(InputStream vsdxInputStream) throws IOException, InvalidFormatException {
        // 创建空的DOCX文档
        try (XWPFDocument doc = new XWPFDocument()) {
            // 创建段落和运行对象,用于放置嵌入对象
            XWPFParagraph paragraph = doc.createParagraph();
            XWPFRun run = paragraph.createRun();

            // Visio Drawing的ProgID,对应VSDX格式(Visio 2013+)
            String visioProgId = "Visio.Drawing.15";
            String visioFileName = "embedded_visio.vsdx";

            // 将VSDX输入流转为字节数组
            byte[] vsdxBytes = readInputStreamToByteArray(vsdxInputStream);

            // 创建OLE包并设置属性
            try (ByteArrayOutputStream oleOut = new ByteArrayOutputStream()) {
                POIFSFileSystem poifs = new POIFSFileSystem();
                // 添加VSDX内容到POIFS
                poifs.createDocument(new ByteArrayInputStream(vsdxBytes), "Contents");
                // 设置OLE对象的ProgID属性
                poifs.createDocument(new ByteArrayInputStream(visioProgId.getBytes()), "\001Ole10Native");
                poifs.writeFilesystem(oleOut);
                poifs.close();

                // 将OLE对象插入到DOCX的Run中
                run.setEmbeddedPicture(oleOut.toByteArray(), Document.PICTURE_TYPE_OLE, visioFileName, Units.toEMU(400), Units.toEMU(300));
            }

            // 将DOCX文档转为byte[]
            try (ByteArrayOutputStream docOut = new ByteArrayOutputStream()) {
                doc.write(docOut);
                return docOut.toByteArray();
            }
        }
    }

    // 辅助方法:将输入流转为字节数组
    private static byte[] readInputStreamToByteArray(InputStream inputStream) throws IOException {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        int bytesRead;
        byte[] data = new byte[1024];
        while ((bytesRead = inputStream.read(data, 0, data.length)) != -1) {
            buffer.write(data, 0, bytesRead);
        }
        buffer.flush();
        return buffer.toByteArray();
    }

    // 测试示例
    public static void main(String[] args) throws IOException, InvalidFormatException {
        try (FileInputStream vsdxIn = new FileInputStream("input.vsdx")) {
            byte[] docxBytes = embedVsdxIntoDocx(vsdxIn);
            try (FileOutputStream docxOut = new FileOutputStream("output.docx")) {
                docxOut.write(docxBytes);
            }
        }
    }
}

关键说明

  • OLE嵌入而非图片:代码中使用Document.PICTURE_TYPE_OLE类型插入对象,而非图片类型,这是保持VSDX可编辑性的核心。
  • ProgID正确性:Visio.Drawing.15对应Visio 2013及以后版本的VSDX格式,确保双击嵌入对象时能正确唤起Visio程序。
  • 资源管理:所有流和文档对象都使用try-with-resources自动关闭,避免资源泄漏。
  • 返回byte[]:最终生成的DOCX字节数组可以直接作为HTTP响应返回,用户下载后打开DOCX,双击嵌入的Visio对象即可编辑原VSDX内容。

内容的提问来源于stack exchange,提问作者Avinash Thakur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 04:43:20