java EasyExcel 导出不同dto到多sheet,同时有固定字段和动态字段,分页写入方案,解决存在oom的问题...

思路 

1 将一次查询数据改成分页查询,比如一次2000条,

2 将每次查询的数据按业务分组计算每类业务 动态列追加的最大次数

// treeMap 追加列 2 在excel列表头则是追加2列,名称自定义,我这边是补数字,示例 追加列1,追加列2 

// 我的业务是按数据库存放的图片来确定最大追加列,需要将图片字段按 |||拆分 。然后将内容分别填充到追加列1,追加列2 等

 

  /**
     * 计算  图片值分割后的最大次数
     * @param dto
     * @param treeMap  key 列头中文名,  value  追加的最大次数
     * @param key   列头的key
     * @param filedName  对象 字段
     */
    private void getMaxCountImageField(Object dto, TreeMap<String, Integer> treeMap, String key, String filedName) {
        try {

            Object pictures = ReflectUtil.getFieldValue(dto, filedName);
            if (ObjUtil.isNotNull(pictures)) {
                String[] split = pictures.toString().split("\\|\\|\\|");
                //取最大值
                treeMap.put(key, Math.max(treeMap.getOrDefault(key, 0), split.length));
            }
        } catch (Exception e) {
            // 添加适当的日志记录
            log.error("计算动态列最大出现次数异常:", e);
        }
    }

3将分页数据暂时暂存redis ,key要唯一哦,  最好是  业务key+毫秒数+分页页码  示例: type1: 毫秒数:1    type2:毫秒数:1 

4 循环完毕,计算每个sheet的列表头如何确定

扫描dto的注解 如@Excel  @ExcelProperty  或者自定义注解,需要注意的是,该注解一定是固定列,最好有序

按上计算动态列追加次数,继续计算 sheet的列表头。代码如下:

    /**
     * 获取导出sheet里的所有列头   固定+动态
     *
     * @param c    模板类
     * @param initTreeMap 动态列头集合 有序
     * @param workPlanType   工单类型
     * @return //返回  编号,姓名,。。   处理前1,处理前2.。。处理后1.。。。。等动态列头
     */
    private List<List<String>>  getFaultCellHeads(Class c, Map<Integer,TreeMap<String,Integer>> initTreeMap,Integer workPlanType) {
        //固定列
        List<List<String>> excelAnnotations = ExcelFileNameUtils.getExcelAnnotations(c);


        //固定列 +动态列    适用其他工单
        for (Map.Entry<String, Integer> entry : treeMap.entrySet()) {
            String name = entry.getKey();
            Integer count = entry.getValue();
            //初始化1    ,map  value次数等于0 的时候,不追加
            int init = 1;
            //可以改成stream写法
            while (init <= count) {
                String prefix = name + init;
                List<String> list=new ArrayList<>();
                list.add(prefix);
                excelAnnotations.add(list);
                init++;
            }
        }
        //返回  编号,姓名,。。   处理前1,处理前2.。。处理后1.。。。。等动态列头
        return excelAnnotations;
    }

开始写入数据到excel  ,分分页循环,挨个类型去获取缓存数据写入

需要初始化多个sheet

 获取头

 动态填充数据

 填充方法

/**
     * excel 行数据写入,  即 表头  固定列+动态列
     *
     * 本方法支持 
     * @param dataVoList   数据
     * @param treeMap  动态列
     * @param <T>
     * @return
     */
    public <T> List<List<Object>> getCommonDataExcelList(List<T> dataVoList, TreeMap<String, Integer> treeMap) {
        List<List<Object>> dataLists = new ArrayList<>();
        for (T dataVo : dataVoList) {
            // 第一行导出数据,按序赋值
            List<Object> objects = new ArrayList<>();
            // 赋值
            Field[] declaredFields = dataVo.getClass().getDeclaredFields();
            Field beforePictureField = null;
            Field afterPictureField = null;
            Field picturesField = null;
            // 处理固定列数据,代码属性不要错位写,有序声明
            for (Field field : declaredFields) {
                Excel excel = field.getAnnotation(Excel.class);
                if (excel != null) {
                    // 铺开列,获取属性的值,属性格式化还未处理 TODO
                    field.setAccessible(true);
                    Object value = null;
                    try {
                        value = field.get(dataVo);
                    } catch (Exception e) {
                        // 出取值异常,写入空
                    }
                    objects.add(value);
                }
                if ("beforePicture".equals(field.getName())) {
                    beforePictureField = field;
                    field.setAccessible(true);
                }
                if ("afterPicture".equals(field.getName())) {
                    afterPictureField = field;
                    field.setAccessible(true);
                }
                if ("pictures".equals(field.getName())) {
                    picturesField = field;
                    field.setAccessible(true);
                }
            }
            try {
                //处理前动态列
                if (ObjUtil.isNotNull(beforePictureField)) {
                    Object beforePicture = beforePictureField.get(dataVo);
                    if (ObjUtil.isNotNull(beforePicture)) {
                        Integer integer = treeMap.get(ExcelDynamicHeadConstants.BEFORE_PROCESSING);
                        spreadImageColumns(beforePicture.toString(), integer, objects);
                    }
                }
                //处理后动态列
                if (ObjUtil.isNotNull(afterPictureField)) {
                    Object afterPicture = afterPictureField.get(dataVo);
                    if (ObjUtil.isNotNull(afterPicture)) {
                        Integer integer = treeMap.get(ExcelDynamicHeadConstants.AFTER_PROCESSING);
                        spreadImageColumns(afterPicture.toString(), integer, objects);
                    }
                }
                //处理图片动态列
                if (ObjUtil.isNotNull(picturesField)) {
                    Object pictures = picturesField.get(dataVo);
                    if (ObjUtil.isNotNull(pictures)) {
                        Integer integer = treeMap.get(ExcelDynamicHeadConstants.IMAGE_PROCESSING);
                        spreadImageColumns(pictures.toString(), integer, objects);
                    }
                }
            } catch (Exception e) {
                log.error("写入excel行数据,包含动态头报错:", e);
            }
            dataLists.add(objects);
        }
        return dataLists;
    }

注意需要处理无任务数据需要写个空白页

最后

excelWriter.finish();

以上是核心逻辑代码,有不懂可以留言

 这是我的excel导出样式,有多个sheet,每个sheet固定列和动态追加列,都根据查询条件变动

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值