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

相关推荐
wei_shuo1 天前
Apache IoTDB 架构特性与 Prometheus+Grafana 监控体系部署实践
架构·apache·iotdb
熊文豪1 天前
Windows安装Apache Kafka保姆级教程(图文详解+可视化管理工具)
windows·kafka·apache
左师佑图3 天前
Apache POI SXSSFWorkbook 报错“没有那个文件或目录”问题排查与解决方案
java·apache·excel
华阙之梦3 天前
【在 Windows 上运行 Apache Hadoop 或 Spark/GeoTrellis 涉及 HDFS 】
hadoop·windows·apache
SelectDB技术团队3 天前
Apache Doris 与 ClickHouse:运维与开源闭源对比
运维·clickhouse·apache
西京刀客3 天前
开源 ETL(Extract,Transform,Load)工具之Apache Hop
开源·apache·etl·hop
FIavor.4 天前
Cannot resolve plugin org.apache.maven.plugins:maven-jar-plugin:3.2.2 这怎么办
maven·apache·jar
低音钢琴4 天前
【从零开始构建性能测试体系-02】 Apache JMeter 取样器指南:从入门到精通
学习·jmeter·apache
SelectDB技术团队4 天前
Apache Doris 内部数据裁剪与过滤机制的实现原理 | Deep Dive
大数据·数据库·apache·数据库系统·数据裁剪
Le_ee4 天前
Apache2
服务器·网络安全·apache·web