大批量导出excel逻辑(支持异步和同步配置)

需求:需要从数据库查询出几十上百万的数据并导出成excel文件

问题:

1、传统导出方式在几万条数据时还可以胜任,但是数量一旦有几十万甚至上百万的话就会出现内存不够用,内存溢出等问题。

2、大批量导出一般会和业务结合比较紧密,如何抽象出通用工具类

技术关键点:

1、解决大批量导出内存消耗问题

2、通用类的抽象

实现思路:

1、因为大部分内存问题发生在查询数据库和生成excel两个地方,所以针对这两个地方进行改造,

第一点,查询时使用分页方式进行查询

第二点,每生成1W条数据时生成一个excel文件到硬盘中,最后将多个excel打包成一个zip文件并导出。同时在使用POI插件进行处理时进行刷盘控制(详细看后边的代码示例,或者参考POI官方文档)

2、抽象工具类中需要实现业务上的分页查询逻辑,然后还要实现异步导出逻辑,可以考虑使用抽象类实现,在关键业务对象上交给子类实现(模板模式)

核心代码(注意代码可能不全,主要是核心的代码类和方法,辅助的代码类比如http上传之类的没有加入,自己实现就好了)

 

public abstract class BaseExportService<I, O, TI, TO, AM> {
    private static final String EVENT_NAME = "大批量导出抽象服务";
    private static final int ACT_GOODS_EXPORT_LIMIT_DEFAULT = 100;
    private static final int IS_SYNC_EXPORT_MAX_NUM_DEFAULT = 100;
    private static final int ACT_GOODS_EXPORT_DIVIDE_PAGE_DEFAULT = 100;
    private static final int ACT_GOODS_EXPORT_LIMIT_EXCEL_DEFAULT = 100;

    /**
     * <b>描述:</b> 导出方法<br/>
     * <b>作者:</b>jeff.meng<br/>
     * <b>版本:</b>V1.0 <br/>
     *
     * @param params
     * @return O
     */
    public O export(I params) throws Exception {

        // 获取活动id对应活动信息的map
        TI query = getQuery(params);
        // 查询总条数
        int count = getExportExcelCount(params, query);
        if (count == 0) {
            throw new ExportBatchException(GlobalErrorCode.DATA_NULL_ERROR);
        }
        // 查询配置的导出上限
        int exportDataLimit = getExportDataLimit();
        if (count > exportDataLimit) {
            throw new ExportBatchException(GlobalErrorCode.DATA_MAX_LIMIT_ERROR);
        }
        // 导出逻辑
        FileFidModel fileFidModel = coreExportHandle(params, count, query);
        return assembleResult(params, fileFidModel, query);
    }

    /**
     * <b>描述:</b> 获取查询条件<br/>
     * <b>作者:</b>jeff.meng<br/>
     * <b>版本:</b>V1.0 <br/>
     *
     * @param params
     * @return TI
     */
    protected abstract TI getQuery(I params);

    /**
     * <b>描述:</b> 获取导出的总条数<br/>
     * <b>作者:</b>jeff.meng<br/>
     * <b>版本:</b>V1.0 <br/>
     *
     * @param params
     * @param query
     * @return int
     */
    protected abstract int getExportExcelCount(I params, TI query);

    /**
     * <b>描述:</b> 获取生成文件名称的前置名称<br/>
     * <b>作者:</b>jeff.meng<br/>
     * <b>版本:</b>V1.0 <br/>
     *
     * @param
     * @return java.lang.String
     */
    protected abstract String getPrefixName(I params);

    /**
     * <b>描述:</b> 获取sheet名称<br/>
     * <b>作者:</b>jeff.meng<br/>
     * <b>版本:</b>V1.0 <br/>
     *
     * @param
     * @return java.lang.String
     */
    protected abstract String getSheetName(I params);

    /**
     * <b>描述:</b> 写入其他信息到最终的列表中<br/>
     * <b>作者:</b>jeff.meng<br/>
     * <b>版本:</b>V1.0 <br/>
     *
     * @param selectedGoodsList
     * @return java.util.List<AM>
     */
    protected abstract List<AM> assembleOtherInfos(List<TO> selectedGoodsList);

    /**
     * <b>描述:</b> 分页查询数据信息<br/>
     * <b>作者:</b>jeff.meng<br/>
     * <b>版本:</b>V1.0 <br/>
     *
     * @param query
     * @param pager
     * @return java.util.List<TO>
     */
    protected abstract List<TO> getInfoListByPager(TI query, Pager pager) throws Exception;

    /**
     * <b>描述:</b> 获取导出excel的标题行<br/>
     * <b>作者:</b>jeff.meng<br/>
     * <b>版本:</b>V1.0 <br/>
     *
     * @param params
     * @return java.lang.String[][]
     */
    protected abstract String[][] getExportTitle(I params);

    /**
     * <b>描述:</b> 组装为返回的数据<br/>
     * <b>作者:</b>jeff.meng<br/>
     * <b>版本:</b>V1.0 <br/>
     *
     * @param params
     * @param fileFidModel
     * @param query
     * @return O
     */
    protected abstract O assembleResult(I params, FileFidModel fileFidModel, TI query);

    private List<String> asyncExportExcelNew(I params, TI query) throws Exception {
        ActExportHelper actExportHelper = new ActExportHelper();
        int pageSize = getExportDividePage();
        int divideExcelNum = getExportExcelDataLimit();
        int t
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值