如何使用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
相关产品推荐
相关产品推荐

