Apache POI生成的pptx在office中打不开 兼容问题 wps中可以打卡问题 POI显示兼容问题

项目场景:

在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方法即可

相关推荐
墨菲安全1 小时前
Apache OFBiz Scrum 组件命令注入漏洞
apache·scrum·命令注入·apache ofbiz·scrum组件
lang2015092812 小时前
Apache Ignite的流处理(Streaming)示例程序
开发语言·apache·ignite
失因14 小时前
Linux systemd 服务管理与 Firewall 防火墙配置
linux·运维·服务器·centos·apache
SeaTunnel17 小时前
从《中国开源年度报告》看中国开源力量的十年变迁中,Apache SeaTunnel 的跃迁
开源·apache
xingzizhanlan17 小时前
apache-tomcat-11.0.9安装及环境变量配置
java·tomcat·apache
smileNicky19 小时前
从 LinkedIn 到 Apache:Kafka 的架构设计与应用场景
kafka·apache·linq
SelectDB技术团队2 天前
ApacheCon Asia 2025 中国开源年度报告:Apache Doris 国内第一
开源·apache·数据库开发·doris·实时分析
learning_tom2 天前
微信小程序重要知识点
前端·apache
超级小忍3 天前
深入解析 Apache Tomcat 配置文件
java·tomcat·apache
魏波.3 天前
Apache Shiro“全栈式安全框架”简述
apache·shiro