项目场景:
在java服务中使用了apache.poi后生成的pptx在wps中打开是没有问题,但在office中打开显示如下XXX内容问题,修复(R)等问题
我是用的依赖版本如下
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version>
</dependency>
原因分析:
提示:可以把适配的解压看里面的slide,有部分格式是不同的,为此直接用下面的服务层即可,我使用的纯流方式,没有文件夹,输入输出都是可以让AI帮你修改下的,主流程逻辑不要动
解决方案:
package com.project.zcustom.service.converter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.*;
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import java.io.*;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
@Slf4j
@Service
public class PptXmlFormateService {
@Autowired
private Executor threadPoolTaskExecutor;
public byte[] xmlFormate(byte[] pptxBytes, String useFont) {
useFont = StringUtils.isBlank(useFont) ? "宋体" : useFont;
ByteArrayOutputStream resultStream = new ByteArrayOutputStream();
try (ByteArrayInputStream bis = new ByteArrayInputStream(pptxBytes);
ZipInputStream zis = new ZipInputStream(bis);
ZipOutputStream zos = new ZipOutputStream(resultStream)) {
Map<String, ByteArrayOutputStream> updatedFiles = new HashMap<>();
// 遍历PPTX文件中的每个条目
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
String entryName = entry.getName();
ByteArrayOutputStream entryData = new ByteArrayOutputStream();
// 读取条目内容
byte[] buffer = new byte[1024];
int len;
while ((len = zis.read(buffer)) > 0) {
entryData.write(buffer, 0, len);
}
// 仅处理幻灯片XML文件
if (entryName.startsWith("ppt/slides/slide") && entryName.endsWith(".xml")) {
try (ByteArrayInputStream xmlBais = new ByteArrayInputStream(entryData.toByteArray());
ByteArrayOutputStream updatedXml = new ByteArrayOutputStream()) {
// 解析XML
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(xmlBais);
// 异步任务处理XML
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
// 删除标签
String custDataLstXpath = "//*[local-name()='custDataLst']";
removeNodesUsingXPath(document, custDataLstXpath);
}, threadPoolTaskExecutor);
// 等待任务完成并处理异常
future.exceptionally(ex -> {
log.error("处理XML异步任务时发生错误: {}", ex.getMessage(), ex);
return null;
}).join();
// 写入修改后的XML内容
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(updatedXml);
transformer.transform(source, result);
updatedFiles.put(entryName, updatedXml);
} catch (Exception e) {
log.error("处理XML文件时发生错误: {}", e.getMessage(), e);
// 发生错误时保留原文件内容
updatedFiles.put(entryName, entryData);
}
} else {
// 对于其他条目,保持原样
updatedFiles.put(entryName, entryData);
}
}
// 写入更新后的PPTX文件
for (Map.Entry<String, ByteArrayOutputStream> fileEntry : updatedFiles.entrySet()) {
String entryName = fileEntry.getKey();
ByteArrayOutputStream fileData = fileEntry.getValue();
zos.putNextEntry(new ZipEntry(entryName));
fileData.writeTo(zos);
zos.closeEntry();
}
} catch (Exception e) {
log.error("处理PPTX字节数组时发生错误: {}", e.getMessage(), e);
throw new RuntimeException("PPTX处理失败", e);
}
return resultStream.toByteArray();
}
// 保持原有的XML节点移除方法不变
public void removeNodesUsingXPath(Document document, String xpathExpression) {
// 方法实现与原代码相同...
XPath xPath = XPathFactory.newInstance().newXPath();
// 设置命名空间前缀和 URI
NamespaceContext nsContext = new NamespaceContext() {
public String getNamespaceURI(String prefix) {
switch (prefix) {
case "a":
return "http://schemas.openxmlformats.org/drawingml/2006/main";
case "p":
return "http://schemas.openxmlformats.org/presentationml/2006/main";
default:
return XMLConstants.NULL_NS_URI;
}
}
public String getPrefix(String namespaceURI) {
return null;
}
public Iterator getPrefixes(String namespaceURI) {
return null;
}
};
xPath.setNamespaceContext(nsContext);
try {
NodeList nodes = (NodeList) xPath.evaluate(xpathExpression, document, XPathConstants.NODESET);
for (int i = nodes.getLength() - 1; i >= 0; i--) { // 从后向前遍历
Node node = nodes.item(i);
Node parentNode = node.getParentNode();
if (parentNode != null) {
parentNode.removeChild(node);
}
}
} catch (Exception e) {
log.error("Error removing nodes using XPath: {}", e.getMessage());
}
}
}
这里换上你自己的项目的Executor或者默认的即可,调用xmlFormate方法即可