基于EasyExcel二开支持导入合并的单元格解析二

目录

对EasyExcel的调研

在经历了EasyPoi的坑后决定后面放弃使用这个工具(垃圾玩意对不起GVP徽章)。偶然间看到了阿里开源的EasyExcel工具,在看了其api和实现思路后发现是一个很好的工具,随后调研了特性发现并不支持自动合并含有合并单元格的数据,需要自行在ReadListener中处理。如果每一个需求都要自行处理一遍那么效率实在是有点低下,随后便开始研究EasyExcel的处理原理。
github地址:https://github.com/zhaoqiang1024/easyexcel
分支:

  • dev-1.0基于3.0.5版本开发
  • dev-2.0基于3.1.1版本开发

几个关键的类

  • ExcelHeadProperty

该类是用于解析Excel的Head配置,主要有字段所对应的列索引、行的Class类型、需要忽略的字段、标题头的起行号。该类还有最重要的功能,通过Class对象来解析出对的字段Field并转换成Head对象

  • Head

存储了一个字段的配置,例如:所在列索引、字段的Field对象、字段的FieldName、该字段的自定义格式等

  • ModelBuildEventListener

一个实现了ReadListener接口的对象接收转换类,该类将提供了将原始数据转换成指定的Object对象功能;

  • DefaultAnalysisEventProcessor

一个默认的解析处理器,用于解析Head和Excel的数据,循环调用ReadListener监听器等;

理清原生的处理逻辑后决定将ModelBuildEventListener替换掉,开发一个可支持合并的监听器。
主要的思路有几点:

  • 尽量不要破坏原生的逻辑减少侵入

尽大可能保证原生代码,以便于后续的升级

  • 扩展Head对象

1、扩展type类型字段。用于存储该字段的类型:普通orList
2、扩展nextHead Map字段。当该Head的type类型为List时,nextHead字段存储了List范型所解析出来的Head集合
3、扩展collectionClass字段。用于存储List集合所对应的范型类型

  • 扩展注解

扩展@ExcelCollection注解。仅用于标注该字段为一个List类型,需要进行合并

  • 自定义监听器AbstractReadMergeListener

该监听器的大致思想为2次数据读取:
1、将解析后的Map<Integer, ReadCellData<?>> 数据和Map<Integer,CellExtra>数据在内存中进行存储。

private TreeMap<Integer, Map<Integer, ReadCellData<?>>> dataMaps = new TreeMap<>();
private TreeMap<Integer, Map<Integer,CellExtra>> extraMap =new TreeMap<>();
@Override
public void invoke(Map<Integer, ReadCellData<?>> cellDataMap, AnalysisContext context) {
    dataMaps.put(context.readSheetHolder().getRowIndex(),cellDataMap);
}
@Override
public void extra(CellExtra extra, AnalysisContext context) {
    Integer rowHeadNumber = context.readSheetHolder().getHeadRowNumber();
    if (extra.getRowIndex() <= rowHeadNumber-1) {
        return;
    }
    Map<Integer, CellExtra> cellMap = new TreeMap<>();
    if(extraMap.containsKey(extra.getRowIndex())){
        cellMap = extraMap.get(extra.getRowIndex());
    }
    cellMap.put(extra.getFirstColumnIndex(), extra);
    extraMap.put(extra.getRowIndex(), cellMap);
}

2、待Excel解析完毕后在doAfterAllAnalysed方法中处理单元格合并问题,通过行号与extraMap中存储的合并信息进行匹配,如果匹配到相应的合并规则后进行解析,按照规则所对应的行进行合并,主要采用的递归方式进行

@Override
public void doAfterAllAnalysed(AnalysisContext context) {
    int lastIndex = -1;
    for (Integer index : dataMaps.keySet()) {
        if (index <= lastIndex) {
            continue;
        }
        Map<Integer, ReadCellData<?>> data = dataMaps.get(index);
        Map<Integer, CellExtra> extra = extraMap.get(index);
        Object obj = null;
        if (extra!=null) {
            MergeData mergeData = this.merge(data, context, index, extra);
            //删除处理完成的
            extraMap.pollFirstEntry();
            obj = mergeData.getData();
            lastIndex = mergeData.getLastIndex();
        } else {
            obj= this.convertBean(data, context.readSheetHolder(), index, context);
        }
        this.doInvoke((T) obj);
    }
    this.doAfter();
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值