Java解析、生成Excel比较有名的框架有Apache、poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度地解决一些内存溢出的问题
前言
又写bug呢?当我们线上遇到bug的时候,可能需要修复数据,那么这时候怎么办呢?你很慌了,打开离线表一顿猛之后,得到了一份要修复的数据,然后写了一段修复脚本,准备发布修复一下时候,这时候问题来了,怎么解析数据呢,加载这份数据到内存里,然后依次读取修复吗?太慢啦。
这里介绍一款阿里开源解析excel框架 easy-excel。
是什么
这里引用下官方的介绍
Java解析、生成Excel比较有名的框架有Apache、poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度地解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便。
能做什么
- 数据的批量处理、解析
- 支持自定义模型类字段映射 excel 表列
- 极度化降低内存使用,使用简单
快速实践
我们先写个脚本轻轻感受模拟一下,被处理的数据需要的逻辑。假设是一个修复脚本。
你辛辛苦苦从几张离线表中一顿猛操作捞出了需要修复的问题数据,假设如下:
ok,数据有了,那就开始写修复脚本,我们先定义一个修复数据接口 FlushDataService 。
/**
* @创建人 : 掘金账号 "橘松Java"
* @创建时间 2021/7/11
* @描述 : 需要源码加QQ群[693961584]免费索取
*/
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;
/**
* @创建人 : 掘金账号 "橘松Java"
* @创建时间 2021/7/11
* @描述 : 需要源码加QQ群[693961584]免费索取
*/
@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;
/**
* @创建人 : 掘金账号 "橘松Java"
* @创建时间 2021/7/11
* @描述 : 需要源码加QQ群[693961584]免费索取
*/
@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;
/**
* @创建人 : 掘金账号 "橘松Java"
* @创建时间 2021/7/11
* @描述 : 需要源码加QQ群[693961584]免费索取
*/
@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);
}
}
测试一下
是不是效果还行,赶紧也试试吧,不过还是祈祷你们平时少出问题,毕竟你们都是专业的,BUG在所难免,重点是我们要有出现问题快速解决问题的能力。好了,我们下期见~
内容出处:,
声明:本网站所收集的部分公开资料来源于互联网,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。如果您发现网站上有侵犯您的知识产权的作品,请与我们取得联系,我们会及时修改或删除。文章链接:http://www.yixao.com/share/25159.html