封装读excel监听器:主打不创建对象的读
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Resource;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 封装读excel监听器:主打不创建对象的读
*
* @author wzh
* @description 继承AnalysisEventListener<Map < Integer, String>>
* @date 2021/4/20 13:30
**/
public class CustomListener extends AnalysisEventListener<Map<Integer, String>> {
private final static Logger logger = LoggerFactory.getLogger(CustomListener.class);
/**
* 定义每多少条数据进行数据库保存,目前不确定
*/
private static final int BATCH_COUNT = 1500;
@Resource
private final CustomExcelService customExcelService;
@Resource
private String fileVersionNo;
/**
* 用list集合保存解析到的结果
*/
private List<Map<Integer, Map<Integer, String>>> list;
public List<Map<Integer, Map<Integer, String>>> getList() {
return list;
}
public void setList(List<Map<Integer, Map<Integer, String>>> list) {
this.list = list;
}
/**
* 重构,把传来的值赋给对应的属性
*
* @param customExcelService 自定义excel接口类
*/
public CustomListener(CustomExcelService customExcelService, String fileVersionNo) {
this.customExcelService = customExcelService;
this.fileVersionNo = fileVersionNo;
list = new ArrayList<>();
}
/**
* 重写invokeHeadMap方法,获去表头,如果有需要获取第一行表头就重写这个方法,不需要则不需要重写
*
* @param headMap Excel每行解析的数据为Map<Integer, String>类型,Integer是Excel的列索引,String为Excel的单元格值
* @param context context能获取一些东西,比如context.readRowHolder().getRowIndex()为Excel的行索引,表头的行索引为0,0之后的都解析成数据
*/
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
logger.info("解析到一条头数据:{}, currentRowHolder: {}", headMap.toString(), context.readRowHolder().getRowIndex());
Map<Integer, Map<Integer, String>> map = new HashMap<>();
map.put(context.readRowHolder().getRowIndex(), headMap);
list.add(map);
}
/**
* 重写invoke方法获得除Excel第一行表头之后的数据,
* 如果Excel第二行也是表头,那么也会解析到这里,如果不需要就通过判断context.readRowHolder().getRowIndex()跳过
*
* @param data 除了第一行表头外,数据都会解析到这个方法
* @param context 和上面解释一样
*/
@SneakyThrows
@Override
public void invoke(Map<Integer, String> data, AnalysisContext context) {
logger.info("解析到一条数据:{}, currentRowIndex: {}----", data.toString(), context.readRowHolder().getRowIndex());
Map<Integer, Map<Integer, String>> map = new HashMap<>();
map.put(context.readRowHolder().getRowIndex(), data);
list.add(map);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
list.clear();
}
}
/**
* 解析到最后会进入这个方法,需要重写这个doAfterAllAnalysed方法,然后里面调用自己定义好保存方法
*
* @param context 解析上下文
*/
@SneakyThrows
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
logger.info("所有数据解析完成!");
}
/**
* 加上存储数据库
*/
private void saveData() throws ParseException {
logger.info("{}条数据,开始存储数据库!", list.size());
customExcelService.doSaveForExcel(list, fileVersionNo);
list.clear();
}
}