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

相关推荐
神秘的土鸡20 分钟前
Apache 高级配置实战:从连接保持到日志分析的完整指南
linux·运维·apache
GLAB-Mary4 小时前
如何在 Ubuntu 24.04 服务器上安装 Apache Solr
ubuntu·apache·solr
Clownseven21 小时前
网站缓存入门与实战:浏览器与Nginx/Apache服务器端缓存,让网站速度起飞!(2025)
nginx·缓存·apache
IT成长日记1 天前
【Doris基础】Apache Doris中FE和BE的职责详解
apache·doris·be·fe·职责
Clownseven2 天前
HTTP/2与HTTP/3特性详解:为你的Nginx/Apache服务器开启下一代Web协议
nginx·http·apache
Kookoos2 天前
ABP VNext + Apache Flink 实时流计算:打造高可用“交易风控”系统
大数据·flink·.net·apache·abp vnext
枷锁—sha3 天前
【HW系列】—web组件漏洞(Strtus2和Apache Log4j2)
前端·安全·web安全·网络安全·log4j·apache
兔子蟹子3 天前
JAVA Apache POI实战:从基础Excel导出入门到高级功能拓展
java·apache·excel
cui_win3 天前
每天掌握一个Linux命令 - ab(Apache Benchmark)
linux·运维·apache·性能测试·ab