一款阿里开源解析excel框架"easy-excel"

·  阅读 3362
一款阿里开源解析excel框架"easy-excel"

微信公众号:程序猿小奕

前言

又写bug呢?当我们线上遇到bug的时候,可能需要修复数据,那么这时候怎么办呢?你很慌了,打开离线表一顿猛之后,得到了一份要修复的数据,然后写了一段修复脚本,准备发布修复一下时候,这时候问题来了,怎么解析数据呢,加载这份数据到内存里,然后依次读取修复吗?太慢啦。

这里介绍一款阿里开源解析excel框架 easy-excel

是什么

这里引用下官方的介绍

Java解析、生成Excel比较有名的框架有Apachepoijxl。但他们都存在一个严重的问题就是非常的耗内存poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi07Excel的解析,能够原本一个3MexcelPOI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POIsax模式。在上层做了模型转换的封装,让使用者更加简单方便。

能做什么

  • 数据的批量处理、解析
  • 支持自定义模型类字段映射 excel 表列
  • 极度化降低内存使用,使用简单

快速实践

我们先写个脚本轻轻感受模拟一下,被处理的数据需要的逻辑。假设是一个修复脚本。

你辛辛苦苦从几张离线表中一顿猛操作捞出了需要修复的问题数据,假设如下:

image.png

ok,数据有了,那就开始写修复脚本,我们先定义一个修复数据接口 FlushDataService
/**
 * @创建时间 2021/7/11
 */
public interface FlushDataService {
    /**
     * 刷数据接口
     * @param index 为了扩展,定义刷数据文件索引
     */
    void flush(Integer index);
}
复制代码
再定义Excel表头,修复表格数据需要的模型 ItemChannelExcel。注意这里的@ExcelProperty注解一定要标上,注解index属性则是你的excel表的列的索引。
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.BaseRowModel;
import lombok.Data;

/**
 * @创建时间 2021/7/11
 */
@Data
public class ItemChannelExcel extends BaseRowModel {

    @ExcelProperty(index = 0)
    private Long itemNo;

    @ExcelProperty(index = 1)
    private Long itemName;
}
复制代码
这里需要写监听器ItemChannelExcelListener 继承 AnalysisEventListener 泛型类,写你的业务数据处理逻辑。
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @创建时间 2021/7/11
 */
@Service
public class ItemChannelExcelListener extends AnalysisEventListener<ItemChannelExcel> {

    private AtomicInteger totalHandleCount = new AtomicInteger(0);
    private AtomicInteger sucHandleCount = new AtomicInteger(0);
    private AtomicInteger failHandleCount = new AtomicInteger(0);

    @Override
    public void invoke(ItemChannelExcel channelExcel, AnalysisContext analysisContext) {
        System.out.println("正在处理的行row=="+channelExcel.getItemNo()+"==="+channelExcel.getItemName());

        //invoke rpc interface 这里mock
        try{
            //Result<Xxx> listItemRes = xxxService.listItems(Long shopId);
            //if(listItemRes.isSuccess()) {
            //    sucHandleCount.incrementAndGet();
            //}else{
            //    failHandleCount.incrementAndGet();
            //}
            sucHandleCount.incrementAndGet();
        }catch(Exception ex){
            failHandleCount.incrementAndGet();
        }final {
            totalHandleCount.incrementAndGet();
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        //全部处理完成的回调函数
        System.out.println("本次一共处理的数据有"+ totalHandleCount+"条");
        System.out.println("本次成功处理的数据有" + sucHandleCount + "条");
        System.out.println("本次失败处理的数据有" + failHandleCount + "条");
    }
复制代码
修复逻辑和模型都搞定了,接下来就该写实现类了 FlushDataServiceImpl,注意这里需要注入解析Excel监听器绑定起来,读取Excel指定文件源位置,以及解析模型和业务处理监听器
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.metadata.Sheet;

import java.io.InputStream;

/**
 * @创建时间 2021/7/11
 */
@service
public class FlushDataServiceImpl implements FlushDataService {
    
    @Resource
    private ItemChannelExcelListener itemChannelExcelListener;

    @Override
    public void flush(Integer index) {
        Class<? extends FlushDataServiceImpl> clazz = this.getClass();
        InputStream resourceAsStream = clazz.getResourceAsStream("/flush.xlsx");
        //这里创建Sheet对象 传1 主要是排查表头,因为excel第一行不需解析,读者按需要指定
        EasyExcelFactory.readBySax(resourceAsStream,new Sheet(1,1, ItemChannelExcel.class), itemChannelExcelListener);
    }
}
复制代码

测试一下

image.png

是不是效果还行,赶紧也试试吧,不过还是祈祷你们平时少出问题,毕竟你们都是专业的,BUG在所难免,重点是我们要有出现问题快速解决问题的能力。好了,我们下期见~

"我爱你" 三个字,讲出来只要三秒,解释要三小时,证明却要一辈子。
"bug" 三个字母,发现只要三秒,找到需要三小时,debug却要一辈子。

8c5ca209f75ccfe5ac0992eb229c3cc.png

最后

  • 文章均原创,原创不易,感谢掘金平台,觉得有收获,帮忙三连,笔芯
  • 文章涉及的所有代码、时序图、架构图均共享,可通过公众号留言获取
  • 文章若有错误,欢迎评论留言指出,也欢迎转载,麻烦标注下出处就好
分类:
后端
标签:
分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改