SXSSFWorkbook实现分页查询导出

本文介绍了使用SXSSFWorkbook进行分页查询数据并在Excel中追加写入的优化方法,避免频繁关闭流引发的问题,并强调了内存缓存的重要性,最后进行了性能对比测试。
摘要由CSDN通过智能技术生成

继上一篇性能爆炸!SXSSFWorkbook原文件上追加写入&分页导出_sxssfworkbook 模板写入-CSDN博客

那篇其实还没有完全爆炸,但为啥不删除那一篇呢,因为那篇也算是一种思路。这篇文章是属于另外一种思路的玩法。上一篇是读取一个已有的excel再进行追加写,但实际过程中我们分页查询时都是在一个for中进行实现的,所以压根没必要搞那么复杂,复制然后转模式进行写。

先给一段代码,里面注释是保姆级教学了。

String filePath ="";//你的文件路径
FileOutputStream outputStream = null;
//内存缓存1024行
SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(1024);
SXSSFSheet sxssfSheet = sxssfWorkbook.createSheet("Sheet1");
//样式,最好在循环外创建
CellStyle cellStyle = sxssfWorkbook.createCellStyle();
cellStyle.setAlignment(HorizontalAlignment.RIGHT);
cellStyle.setWrapText(true);
//这里每个export实现不同业务,清晰一点,而不在业务代码中追加表头和数据
ReportChannelSellExport export = new ReportChannelSellExport();
//创建表头
export.bulidTitle(sxssfSheet);

 try {
       //先把流给开起来,这样不要每次for写完关闭又打开,就for完才关
       outputStream = new FileOutputStream(filePath);
                        for (int i = 0; i < batches; i++) {
                            //这里是分批次逻辑
                            int offset = i * splitValue;
                            input.setLimit(splitValue);
                            input.setOffset(offset);
                            input.setIsPage(true);
                            //分页查询
                            DataResult<List<ChannelSellReportOrderDTO>> sellReportDataResult = buyVoucherOrderFacade.querySellReportOrder(input);
                            DataResult.checkSucc(sellReportDataResult);
                            List<ChannelSellReportOrderDTO> sellReportList = sellReportDataResult.getData();

                            //此处------------------------分割线--------------
                            export.setExportList(sellReportList);
                            //这里是写数据的开始行,因为标题已经占了第0行 所以+1
                            int tmp =  offset+1;
                               //数据开始行
                               for (List<String> objectList : export.bulidData()) {
                                   Row row = sxssfSheet.createRow(tmp++);
                                   for (int j =0;j<objectList.size();j++) {
                                       Cell cell = row.createCell(j);
                                      
                                       cell.setCellStyle(cellStyle);
                                       
                                       if (objectList.get(j) == null) {
                                           cell.setCellValue("");
                                       } else {
                                           cell.setCellValue(objectList.get(j));
                                       }
                                   }
                               }
                            //sheet先刷新到硬盘
                            sxssfSheet.flushRows();
                        }
                        //写入数据,注意在for外
                        sxssfWorkbook.write(outputStream);
                        outputStream.flush();
                    } catch (IOException e) {
                        log.error("分页导出异常", e);
                        new File(filePath).delete();
                        throw new ErrorCodeException(OpenApiSvcError.FILE_SAVE_ERROR, "分页导出异常");
                    }finally {
                        //记得关流,不是try-with-resources模式不会自动关闭资源 
                        try {
                            sxssfWorkbook.close();
                            outputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

以上代码谁用谁爽,不过有一个点需要注意的,这个我也搞了蛮久。就是不要想着一个for就调用write方法写一次,这个思路看上去是没错。但你执行会第一个for之后,再调用

Row row = sxssfSheet.createRow(tmp++);

就会报错了,报java.lang.RuntimeException: java.io.IOException: Stream closed at org.apache.poi.xssf.streaming.SXSSFSheet.createRow(SXSSFSheet.java:148) ~[poi-ooxml-4.0.1.jar:4.0.1]

这时你就会疑惑,我都没自己关闭过流,怎么流就没了呢。

根源在于以下这个方法,会自己关闭_out对象。

sxssfWorkbook.write(outputStream);

最后就是对比测试下性能,搞点大数据量测测吧。问题都不大。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值