easyExcel实现导入,关于每行数据的处理异常信息返回到前端
文章目录前言一、EasyExcel二、背景及解决主要问题导入excel校验返回文件导出总结前言JAVA解析Excel工具EasyExcel的初次使用easyExcel git地址:https://github.com/alibaba/easyexcel一、EasyExcelJava解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有
前言
JAVA解析Excel工具EasyExcel的初次使用
easyExcel git地址:https://github.com/alibaba/easyexcel
一、EasyExcel
Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,一个3M的excel用POI sax解析依然需要100M左右内存,改用easyexcel可以降低到几M,并且再大的excel也不会出现内存溢出;03版依赖POI的sax模式,在上层做了模型转换的封装,让使用者更加简单方便
二、背景及解决
本公司一个相对时间较长的一个SpringBoot项目,系统原有导入Excel偶尔会发生OOM,原有导入功能对导入excel大小限制进行规避。
业务新需求中,涉及到了excel的导入,趁此机会使用easyExcel,为调整原有导入发生OOM做好准备。
由于原项目中使用的POI版本未3.16,此次升级POI 3.17(不升级easyExcel异常)
升级方法调整借鉴:https://www.csdn.net/tags/OtDacg4sNzM2NTUtYmxvZwO0O0OO0O0O.html
主要问题
系统使用人员将excel导入后,需要立即知道结果;若数据落库过程中出现了异常,使用人员需要通过系统反馈进行excel内容调整后再次操作。
但是重写easyExcel是未对异常进行处理的, 同时本次导入Excel及其简单且每次导入数据量有限,所以将excel中所有的数据取出后,统一验证,若有问题再进行抛出。
导入excel校验返回
代码如下:
public Map importData(@RequestParam(value = "filename") MultipartFile file) {
ExcelReader excelReader = null;
List<InteractiveUploadDto> deleteList = new ArrayList<>();
List<InteractiveUploadDto> addList = new ArrayList<>();
// 数据读取异常统一抛出
try {
excelReader = EasyExcelFactory.read(file.getInputStream(), InteractiveUploadDto.class,
new InteractiveUploadListener( deleteList,addList)).build();
ReadSheet readSheet = EasyExcelFactory.readSheet(0).build();
excelReader.read(readSheet);
} catch (MyException e) {
throw new MyException("导入Excel识别异常"+e.getMessage());
}finally {
if (excelReader != null){
excelReader.finish();
}
}
// 异常放在了interactiveRemindInfoService捕捉处理
// 将excel中所有的数据读取到了list内, 然后在service层处理时,如果有异常会throw到页面
int save = interactiveRemindInfoService.excelDataSave(addList);
int delete = interactiveRemindInfoService.excelDataDelete(deleteList);
return getSuccessMap("数据处理成功,保存成功记录数:"+save+" 条后删除成功记录数:"+delete+" 条,请仔细核对!");
}
public class InteractiveUploadListener extends AnalysisEventListener<InteractiveUploadDto> {
private static final Logger LOGGER = LoggerFactory.getLogger(InteractiveUploadListener.class);
private List<InteractiveUploadDto> deleteList ;
private List<InteractiveUploadDto> addList ;
// 通过构造参数,将excel中的数据通过业务区分,并返回到相应的service。
//业务也可以在此类中进行处理。异常沟通构造参数传回service层,然后再抛出
public InteractiveUploadListener(List<InteractiveUploadDto> deleteList, List<InteractiveUploadDto> addList){
this.deleteList = deleteList;
this.addList = addList;
}
@Override
public void invoke(InteractiveUploadDto vo, AnalysisContext analysisContext) {
LOGGER.info("收数据导入,解析第{}行数据:{}" , analysisContext.readRowHolder().getRowIndex() , vo);
// 由于本功能导入数据量肯定不大,所以这里就不在进行分批处理了。 (不建议如此处理 OOM)
this.buildEntity(vo);
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
LOGGER.info("数据处理完成");
}
/**
* @desc 将每行数据,通过业务类型进行区分放入不同的集合中
* @param dto : excel内的每行数据信息
*/
private void buildEntity(InteractiveUploadDto dto) {
// 将每行数据进行区分, 删除操作放入deleteList集合内, 新增放入addList集合内
if (dto.getDeleteOrNot().equals("Y")){
deleteList.add(dto);
}else {
addList.add(dto);
}
}
}
/**
* @desc
* ExcelProperty与导入的Excel一一对应
*/
public class InteractiveUploadDto {
@ExcelProperty(value = "合同号")
@NotBlank(message = "不能为空")
private String applicationNumber;
@ExcelProperty(value = "待分配用户")
private String username;
@ExcelProperty(value = "是否删除")
@NotBlank(message = "是否删除列不能为空")
private String deleteOrNot;
private Long userId;
}
由于本次功能较为简单,数据未进行批次处理,同时我是将业务处理在excel数据解析后,返回了service处理, 在数据处理过程中或校验时,有异常会直接抛到前端。
文件导出
待补充
总结
更多推荐
所有评论(0)