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

相关推荐
SeaTunnel6 小时前
AI 让 SeaTunnel 读源码和调试过时了吗?
大数据·数据库·人工智能·apache·seatunnel·数据同步
http阿拉丁神猫18 小时前
ansible脚本解读
服务器·ansible·apache
小羊Yveesss19 小时前
商家小程序外卖订单打印方案:云打印机对接、分单逻辑与模板配置实战
小程序·apache
@insist12320 小时前
信息安全工程师-Apache/IIS安全增强与OWASP漏洞防护
安全·apache·软考·信息安全工程师·软件水平考试
Geek_Vison2 天前
如何借助小程序容器技术实现跨端APP的敏捷开发
小程序·apache·敏捷流程
Apache RocketMQ2 天前
Apache RocketMQ 5.0 架构解析:如何基于云原生架构支撑多元化场景
云原生·架构·apache·rocketmq·java-rocketmq
RingWu3 天前
微服务架构-全链路追踪:Apache SkyWalking
微服务·架构·apache
Donk_673 天前
高可用-Keepalived 解析
运维·服务器·apache
小羊Yveesss5 天前
门店小程序外卖配送搭建实战:配送对接、运费策略与多门店调度方案
小程序·apache
qq_411262426 天前
四博AI双目智能音箱方案:四路触控、震动马达、0.71/1.28双目光屏、三轴姿态感应,一键语音克隆和专属知识库
人工智能·apache·智能音箱