思路
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();
以上是核心逻辑代码,有不懂可以留言
标签:dto,isNotNull,oom,EasyExcel,treeMap,param,field,key,动态 From: https://www.cnblogs.com/woshuaile/p/18168390