使用函数作为参数 传递数据,封装阿里 easyexcel 导出,导入大数据量 excel
- 注意 数据是 从函数里面拿到,很多语言都支持 函数作为参数,java8 之后也支持
- 函数作为参数 有些不好理解,但是 很多写法 就是比较灵活了 如Scala 代码就十分优雅,鼓励用
/**
* 大数量导出
* @param fileName 生成文件地址
* @param head 表头
* @param pageSize 页大小
* @param pages 总页数
* @param function 获取数据函数
* @return
*/
public String exportBigData(String fileName, Class head, int pageSize, int pages, Function<Integer,List<?>> function) {
// 每个 sheet 数据量大小 固定最大1百万
int sheet = 1000000;
int sheetNum = sheet / pageSize;
int sheetIndex = 1;
com.alibaba.excel.ExcelWriter excelWriter = null;
try {
excelWriter = EasyExcel.write(fileName, head).build();
WriteSheet writeSheet = null;
for (int i = 1; i <= pages; i++) {
writeSheet = EasyExcel.writerSheet(sheetIndex, "Sheet"+sheetIndex).build();
// 分页去数据库查询数据
List list = function.apply(i);
excelWriter.write(list, writeSheet);
if(i % sheetNum == 0){
sheetIndex++;
}
}
} finally {
// 关闭流
if (excelWriter != null) {
excelWriter.finish();
}
}
return fileName;
}
调用
1.导出过 5000w 数据 但是很耗时,数据量大了 可能出现重复数据,因为导出的时候数据可能发生变化
2.分页数据量大,多线程分页加载提高效率 可能会出现内存溢出
@Test
public void testExport() throws Exception {
long start = System.currentTimeMillis();
String fileName = "F:\\"+ "repeatedWritetest" + System.currentTimeMillis() + ".xlsx";
int pageSize = 20000;
PageHelper.startPage(1,pageSize);
List<Map> maps = testUserMapper.listData();
PageInfo pageInfo = new PageInfo<Map>(maps);
int pages = pageInfo.getPages();
// 调用
exportBigData(fileName,DemoData01.class,pageSize, pages,(i)->{
PageHelper.startPage(i,pageSize,false);
List<Map> data = testUserMapper.listData();
return getDemoData01List(maps);
});
long end = System.currentTimeMillis();
System.out.println("耗时:"+(end-start)/1000 +"秒");
}
导入封装
/**
* easy-excel 导入
* @param inputStream
* @param clazz
*/
public static <T> void importEasyExcel(InputStream inputStream, Class clazz, Consumer consumer){
EasyExcel.read(inputStream, clazz, new ReadListener<T>() {
/**
* 单次缓存的数据量
*/
public static final int BATCH_COUNT = 250;
/**
*临时存储
*/
private List<T> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
@Override
public void invoke(T data, AnalysisContext context) {
cachedDataList.add(data);
if (cachedDataList.size() >= BATCH_COUNT) {
consumer.accept(cachedDataList);
// 存储完成清理 list
cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
if(CollectionUtil.isNotEmpty(cachedDataList)){
consumer.accept(cachedDataList);
}
}
}).sheet().doRead();;
}
使用
@PostMapping("/import")
public Rest importCard(@NotNull(message = "文件为空") MultipartFile file,
@NotNull(message = "规格id 不能为空") Integer specsId) throws IOException {
ExcelUtils.importEasyExcel(file.getInputStream(), AdminConversionCardExcelImportDTO.class,(data -> {
List<AdminConversionCardExcelImportDTO> cardExcelImportDTOList = (List<AdminConversionCardExcelImportDTO>) data;
// 处理数据
}));
return Rest.success();
}
elk