java web POI批量导出excel到zip包出错处理

2023-11-12

好久不见,最近在做一个导出批量excel的功能,因为不希望通过先写出单个excel到本地,然后再压缩成zip后导出。

因此随手百度,找到倒流进ZipOutputStream,然后变成zip导出。
demo代码如下

		    @RequestMapping(value = "/poizip")
		    public void poizip(HttpServletResponse response) throws IOException {
		        //response 输出流
		        ServletOutputStream out = response.getOutputStream();
		        //压缩输出流---将response输出流填入压缩输出流
		        ZipOutputStream zipOutputStream = new ZipOutputStream(out);
		        try {
		            for (int i = 0; i < 6; i++) {
		                //创建工作簿
		                HSSFWorkbook wb = new HSSFWorkbook();
		                HSSFSheet sheet = wb.createSheet("sheet" + i);
		                HSSFRow row = sheet.createRow(0);
		                HSSFCell cell = row.createCell(0);
		                cell.setCellValue("内容" + i);
		                response.setContentType("application/octet-stream; charset=utf-8");
		                response.setHeader("Content-Disposition", "attachment; filename=test.zip");
		                //重点开始,创建压缩文件,并进行打包
		                ZipEntry z = new ZipEntry(i + ".xls");
		                zipOutputStream.putNextEntry(z);
		                //写入一个压缩文件---最后写文件
		                wb.write(zipOutputStream);
		            }
		            zipOutputStream.flush();
		        } catch (IOException e) {
		            e.printStackTrace();
		        } finally {
		            //注意关闭顺序,否则可能文件错误,先开后关
		            if (zipOutputStream != null) {
		                zipOutputStream.close();
		            }
		            if (out != null) {
		                out.close();
		            }
		        }
		    }

这个方法在导入poi的前提下可直接使用,但是用到我的环境内的时候,它每次在处理第一个excel后就直接导出了。

百思不得其解,仔细观察代码后,发现我们的区别是:

我是使用 XSSFWorkbook
而参考的博主代码是 HSSFWorkbook

两者的区别是
在这里插入图片描述
那问题到这里就很明显,肯定是这两个封装的方法出了问题。
那我们直接进入源码查看问题

  • XSSFWorkbook
public void saveImpl(OutputStream outputStream) {
        this.throwExceptionIfReadOnly();

        try {
            ZipOutputStream zos;
            if (!(outputStream instanceof ZipOutputStream)) {
                zos = new ZipOutputStream(outputStream);
            } else {
                zos = (ZipOutputStream)outputStream;
            }

            if (this.getPartsByRelationshipType("http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties").size() == 0 && this.getPartsByRelationshipType("http://schemas.openxmlformats.org/officedocument/2006/relationships/metadata/core-properties").size() == 0) {
                logger.log(1, new Object[]{"Save core properties part"});
                this.getPackageProperties();
                this.addPackagePart(this.packageProperties);
                this.relationships.addRelationship(this.packageProperties.getPartName().getURI(), TargetMode.INTERNAL, "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties", (String)null);
                if (!this.contentTypeManager.isContentTypeRegister("application/vnd.openxmlformats-package.core-properties+xml")) {
                    this.contentTypeManager.addContentType(this.packageProperties.getPartName(), "application/vnd.openxmlformats-package.core-properties+xml");
                }
            }

            logger.log(1, new Object[]{"Save package relationships"});
            ZipPartMarshaller.marshallRelationshipPart(this.getRelationships(), PackagingURIHelper.PACKAGE_RELATIONSHIPS_ROOT_PART_NAME, zos);
            logger.log(1, new Object[]{"Save content types part"});
            this.contentTypeManager.save(zos);
            Iterator i$ = this.getParts().iterator();

            while(i$.hasNext()) {
                PackagePart part = (PackagePart)i$.next();
                if (!part.isRelationshipPart()) {
                    logger.log(1, new Object[]{"Save part '" + ZipHelper.getZipItemNameFromOPCName(part.getPartName().getName()) + "'"});
                    PartMarshaller marshaller = (PartMarshaller)this.partMarshallers.get(part._contentType);
                    if (marshaller != null) {
                        if (!marshaller.marshall(part, zos)) {
                            throw new OpenXML4JException("The part " + part.getPartName().getURI() + " fail to be saved in the stream with marshaller " + marshaller);
                        }
                    } else if (!this.defaultPartMarshaller.marshall(part, zos)) {
                        throw new OpenXML4JException("The part " + part.getPartName().getURI() + " fail to be saved in the stream with marshaller " + this.defaultPartMarshaller);
                    }
                }
            }

            zos.close();
        } catch (OpenXML4JRuntimeException var6) {
            throw var6;
        } catch (Exception var7) {
            throw new OpenXML4JRuntimeException("Fail to save: an error occurs while saving the package : " + var7.getMessage(), var7);
        }
    }

如下图,他会在写出的时候,判断是否是zip压缩流,如果是的话,会直接转换
在这里插入图片描述
很快,找到问题的根源,影响我需要的功能操作的是
在代码的最后它会关闭zip压缩流,导致无法后续的excel流继续写入到zip压缩流中
在这里插入图片描述

而HSSFWorkbook 是没有做close操作的。因此后续的excel在这里插入代码片流可以继续往zip中写入。

找到问题后,就是XSSFWorkbook写入zip流后,会直接输出然后关闭zip流,那么我们只要将XSSFWorkbook流写入到别的流内,然后再写入到zip中即可,这样XSSFWorkbook.write关闭流就不会影响到zip了。

如下

bos = new ByteArrayOutputStream();
wb.write(bos);
bos.writeTo(zipOutputStream);

参考:
https://blog.csdn.net/qq_26576683/article/details/89736528
https://blog.csdn.net/qq_36168749/article/details/86289293
https://blog.csdn.net/cs373616511/article/details/80325458

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java web POI批量导出excel到zip包出错处理 的相关文章

  • 易失性变量的读-修改-写操作如何保证线程安全

    我正在阅读 JCIP 但无法理解 3 3 1 中的以下声明 只要您可以确保仅从单个线程写入易失性变量 对共享易失性变量执行读取 修改 写入操作就是安全的 在这种情况下 您将修改限制在单个线程中以防止竞争条件 并且易失性变量的可见性保证可确保
  • 最好的 Java 集合线程安全锁定机制?

    在 Java 中控制对集合的多次访问的最慢的线程安全机制是什么 我正在将对象添加到集合的顶部 但我非常不确定什么是性能最佳的集合 它是一个向量还是一个队列 我最初认为 ArrayList 会很快 但我进行了一些实验 发现它非常慢 编辑 在我
  • 将文件从内部存储复制到外部存储

    我尝试使用 Adob e reader 读取从服务器下载的 pdf 文件 问题是当我将其存储在内部存储中时 其他应用程序无法读取该文件 现在我想知道我怎样才能Copy this 外部存储中的文件 sdcard 这样它就可以被pdf查看器查看
  • Spring Boot - 在部署时启动后台线程的最佳方式

    我在 Tomcat 8 中部署了一个 Spring Boot 应用程序 当应用程序启动时 我想在后台启动一个工作线程 Spring Autowires 具有一些依赖项 目前我有这个 SpringBootApplication EnableA
  • PSQLException 没有被捕获

    我正在使用 Tomcat 6 和 Postgresql 8 4 我的代码如下所示 try Prepared statement inserting something catch final PSQLException e LOG log
  • onchange 使用 radioChoice 获取当前值

    我尝试使用 radioChoice onChange 从无线电表单中获取选定的值 但似乎无法真正找到解决方案 onEvent 函数被调用 但从这里我不太确定如何获取该值 Code RadioChoice
  • Java中如何保存DOM文档?

    我在用DOM解析器和XPATH解析我的XML文件 我改变了一个节点的值Document Object 然而当我打开我的XML文件 它没有向我显示任何反射 我的DOM解析器代码如下 private void setPortNumber int
  • PHP Socket Java 消息交换

    我正在尝试在 PHP 页面和正在运行的 Java 服务器之间进行通信 只是通过套接字进行简单的字符串交换 这是我处理连接的线程的 Java 代码 InputStream in clientSocket getInputStream Buff
  • gradlew:appengineEnhance 失败

    我正在使用 Java 创建移动后端Google App Engine with Android Studio 为了启动公开我的 API 的本地服务器 我使用gradlew module name appengineRun 然而 当我去htt
  • 使用 Powermock 测试 Spring 控制器

    我有一个测试特定控制器的类 它工作正常 RunWith SpringJUnit4ClassRunner class ContextConfiguration locations classpath config test applicati
  • 在 pom 中添加 selenium 依赖项后,AWS Lambda Jar 无法压缩

    这是一个奇怪的错误 将 selenium 依赖项添加到我的 maven 项目的 pom 并将其上传到 lambda 后 它说无法解压缩文件 然而 在删除依赖项之后 lambda 能够很好地解压缩文件 但是它会出现一个随后找不到的类 我尝试一
  • 将自定义方法映射器映射到 Mapstruct

    我正在创建一个 poc 以便在我未来的项目中使用 Mapstruct 现在我有一个问题如何将自定义方法映射到特殊目标 例如我有以下接口映射器 Mapper public interface ItemMapper static ItemMap
  • 将 OraclePreparedStatement 与 DBCP 连接结合使用

    我正在尝试使用 dbcp 框架为我的 oracle 服务器创建一个连接池 我用过这个tutorial http web archive org web 20120615100115 http www freshblurbs com 80 j
  • 将 s:element 和 s:complexType 命名为相同的名称

    将 s element 和 s complexType 命名为相同名称是否合法 可以看到下面的代码 element和complextype具有完全相同的名称 这是 wsdl 文件的一大块
  • Android:上下文是否影响用于取消警报的filterEquals()?

    要取消闹钟 我使用alarmManager cancel pendingIntent 根据 Android 开发者的说法Removes any alarms with a matching Intent Any alarm of any t
  • 如何压缩和解压文件?

    如何压缩和解压 DDMS 中已有的文件 data data mypackage files 我需要一个简单的例子 我已经搜索过与 zip 和 unzip 相关的内容 但是 没有一个例子可供我参考 谁能举个例子 提前谢谢 查看 zip 功能的
  • JPA:如何在不加载延迟加载集的情况下计算子记录数

    我正在编写一个 J2EE JPA Spring 3 应用程序 试图保持纯粹的 JPA 2 0 我想获得子对象的计数而不必加载它们 因为这显然是一个昂贵的操作 例如 这是一个简化的示例 Organisation OrgID OrgName E
  • 没有 WindowManager.LayoutParams.TYPE_PHONE 的粘性覆盖

    我所说的粘性是指一个不会通过调用启动器意图而关闭的窗口 intent addCategory Intent CATEGORY HOME 以前这是用完成的WindowManager LayoutParams TYPE PHONE 但此类型现已
  • 逆变方法参数类型

    wiki 逆变方法参数类型 https en wikipedia org wiki Covariance and contravariance 28computer science 29 Contravariant method argum
  • JsonNode findValue 不搜索子节点

    我有一个结构如下的资源 activity activity type Like activity id 123456 object id product id reference activity activity type Rating

随机推荐