【EasyExcel】封装一个分页写数据的通用方法,有效规避OOM

通过SQL查询出来一次性写,在大数据量时存在OOM的隐患
分页查询、分批次写数据,避免导出大数据量时内存消耗陡增
基于mybatis-puls分页查询

example

导出250万用户数据,代码看起来是不是很清爽呢?

@Test
public void pageWrite() {
   // build excel writer
   ExcelWriter excelWriter = EasyExcel.write("E:/easyexcel/testPageWrite.xlsx", PageWriteData.class).excelType(ExcelTypeEnum.XLSX).build();
   // page write
   EasyExcelUtils.pageWrite(excelWriter, "数据清单", 2_500_000L,
           (currentPage, pageSize) -> {
       			Page<User> page = new Page<>(currentPage, pageSize);
              	return userService.selectByPage(page).getRecords();
           });
}

源码实现

EasyExcelUtils.java

package com.itplh.common.util;

import com.itplh.base.service.MybatisPlusPageQueryService;
import com.itplh.common.constant.ExcelPageEnum;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.WriteSheet;

/**
 * @description:
 * @author: tanpeng
 * @date: 2020-02-28 10:46
 * @version: v1.0.0
 */
public class EasyExcelUtils extends EasyExcel {

    /**
     * @description: 分页查询、分批次写数据,避免导出大数据量时OOM
     * auto close resource
     * @author: tanpeng
     * @date : 2020-02-28 11:42
     * @version: v1.0.0
     * @param excelWriter
     * @param sheetName
     * @param totalCount 数据总数
     * @param pageQueryService
     */
    public static void pageWrite(ExcelWriter excelWriter,
                                  String sheetName,
                                  long totalCount,
                                  MybatisPlusPageQueryService pageQueryService) {

        // default export xlsx, page size 10000, sheet max row 1000000
        int pageSize = ExcelPageEnum.XLSX.getPageSize();
        int sheetMaxRow = ExcelPageEnum.XLSX.getSheetMaxRow();

        ExcelTypeEnum excelType = excelWriter.writeContext().writeWorkbookHolder().getExcelType();
        boolean isXls =  excelType != null && ExcelTypeEnum.XLS.getValue().equals(excelType.getValue());
        if (isXls) {
            pageSize = ExcelPageEnum.XLS.getPageSize();
            sheetMaxRow = ExcelPageEnum.XLS.getSheetMaxRow();
        }

        // compute page count, sheet count
        long pageCount = (totalCount - 1) / pageSize + 1;
        long sheetCount = (totalCount - 1) / sheetMaxRow + 1;
        int currentPage = 0;

        // page write data
        WriteSheet sheet = null;
        for (int i = 0; i < sheetCount; i++) {
            sheet = EasyExcel.writerSheet(i, sheetName + i).build();
            for (int j = 0; j < (sheetMaxRow / pageSize); j++) {
                // must use ++currentPage, mybatis-plus page query current page start 1
                excelWriter.write(pageQueryService.data(++currentPage, pageSize), sheet);
                if (currentPage >= pageCount) {
                    break;
                }
            }
        }

        // close source
        excelWriter.finish();
    }

}

MybatisPlusPageQueryService.java

package com.itplh.base.service;

import java.util.List;

/**
 * @description:
 * @author: tanpeng
 * @date: 2020-02-28 11:20
 * @version: v1.0.0
 */
@FunctionalInterface
public interface MybatisPlusPageQueryService<E> {

    /**
     * @description: 获取分页查询数据
     * 注意:mybatis-plus 的 current 参数是从 1 开始
     * @author: tanpeng
     * @date : 2020-02-28 12:08
     * @version: v1.0.0
     * @param current 当前页,从 1 开始
     * @param size
     */
    List<E> data(int current, int size);

}

ExcelPageEnum.java

package com.itplh.common.constant;

/**
 * @description: excel 分页参数枚举
 * @author: tanpeng
 * @date: 2020-02-28 11:29
 * @version: v1.0.0
 */
public enum ExcelPageEnum {

    XLS(10_000, 60_000),
    XLSX(10_000, 1_000_000);

    private int pageSize;
    private int sheetMaxRow;

    ExcelPageEnum(int pageSize, int sheetMaxRow) {
        this.pageSize = pageSize;
        this.sheetMaxRow = sheetMaxRow;
    }

    public int getPageSize() {
        return pageSize;
    }

    public int getSheetMaxRow() {
        return sheetMaxRow;
    }
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用EasyExcel可以轻松实现一个通用的导出功能。EasyExcel一个基于Java的开源工具,用于简化Excel操作。可以使用它来读取和Excel文件,支持多种数据格式,如List、Map等。 首先,我们需要引入EasyExcel依赖包。可以在maven中央仓库或者GitHub上找到,并添加到项目的pom.xml文件中。然后,我们可以开始编导出的代码。 首先,我们需要创建一个导出的模板,定义Excel的表头。可以使用EasyExcel提供的注解来定义表头的名称、样式等。接着,我们需要编导出的逻辑。 首先,创建一个导出的工具类,用于处理导出操作。在该工具类中,我们可以定义一个导出方法,该方法接收一个数据列表和一个输出流。 在导出方法中,我们可以使用EasyExcel提供的API来创建一个入器,并指定要入的输出流。然后,我们可以使用write方法数据Excel文件。在数据之前,可以使用sheet和row方法来创建工作表和行。可以使用cell方法来创建单元格,并使用setValue方法来设置单元格的值。 在导出方法中,我们还可以添加一些导出的配置,如设置自动列宽、设置样式等。可以使用EasyExcel提供的工具类来实现这些功能。 最后,我们可以在程序中调用导出方法,将数据列表和输出流作为参数传递给导出方法即可实现导出功能。 总结起来,使用EasyExcel可以轻松实现一个通用的导出功能。我们只需要定义导出的模板和数据,然后调用导出方法即可实现导出操作。这个功能可以应用于各种场景,满足不同需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值