EasyExcel导入

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: EasyExcel导入

更多使用参考:easyExcel官网


业务需求:1、导入用户账号(手机号)进行修改用户名称,2、用户如果存在,判断用户姓名是否与库中一致,不一致修改库中用户姓名,3、记录导入失败数据(前端显示),以备修改后再次导入。


代码实现:


一、controller层:

/*** 修改名称导入* @return*/@ApiOperation(value="修改名称导入", notes="修改名称导入")
@PostMapping("/updateName")
publicRimportCustomerExcel(@RequestParam("file") MultipartFilefile) {
StringfileName=file.getOriginalFilename();
StringsuffixName="";
if (StrUtil.isNotBlank(fileName)) {
suffixName=fileName.substring(fileName.lastIndexOf("."));
   }
if (!".xlsx".equals(suffixName) &&!".xls".equals(suffixName)){
returnR.failed("文件格式不对,请导入excel文件!");
   }
cpCustomerService.importCustomerExcel(file);
// 导入失败的数据List<ImportCustomerExcelModel>failData=ImportCustomerExcelListener.failList();
returnR.ok(failData);
}


二、service:

/*** 用户名称修改导入* @param file* @return*/voidimportCustomerExcel(MultipartFilefile);
@OverridepublicvoidimportCustomerExcel(MultipartFilefile) {
try (InputStreaminputStream=file.getInputStream()){
EasyExcel.read(inputStream, CpCustomer.class, newImportCustomerExcelListener(cpCustomerService)).doReadAll();
   } catch (IOExceptione) {
LOGGER.error("读取文件出现错误,请重新导入!{}", file);
   }
}


EasyExcel.read()解释:


EasyExcel.read(inputStream, CpCustomer.class,new ImportCustomerExcelListener(cpCustomerService)).doReadAll();


1、inputStream:需要读取的文件流。


2、CpCustomer.class:excel导入的字段对应的实体。


3、ImportCustomerExcelListener(cpCustomerService):数据处理监听器,主要逻辑处理都在这里面;由于我需要service去查库判断,所以我这里传了一个cpCustomerService。


4、doReadAll():读取全部sheet。


三、ImportCustomerExcelListener监听器:

/*** 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去*/publicclassImportCustomerExcelListenerextendsAnalysisEventListener<CpCustomer> {
privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(ImportCustomerExcelListener.class);
/*** 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收*/privatestaticfinalintBATCH_COUNT=5;
List<CpCustomer>list=newArrayList<>();
/*** 错误数据*/privatestaticList<ImportCustomerExcelModel>errList=newArrayList<>();
/***添加失败集合数据*/publicstaticList<ImportCustomerExcelModel>failList(){
List<ImportCustomerExcelModel>listerror=newArrayList<>();
listerror.addAll(errList);
errList.clear();
returnlisterror;
   }
/*** 头信息*/Map<Integer, String>headMap=newHashMap<>();
/*** 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。*/privateCpCustomerServicecpCustomerService;
publicImportCustomerExcelListener() {
// 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数   }
/*** 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来** @param cpCustomerService*/publicImportCustomerExcelListener(CpCustomerServicecpCustomerService) {
this.cpCustomerService=cpCustomerService;
   }
/*** 这个每一条数据解析都会来调用** @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}* @param context*/@Overridepublicvoidinvoke(CpCustomerdata, AnalysisContextcontext) {
updateCustomerName(data);
   }
/*** 修改用户名称* @param data*/publicvoidupdateCustomerName(CpCustomerdata) {
if (!Validator.isMobile(data.getPhoneNum())){
failDataOperation(data, "手机号格式错误");
thrownewExcelAnalysisStopException(data.getCustomerName()+"的手机号格式错误,错误手机号:"+data.getPhoneNum());
      }
//    if (!LegalUtils.isNameLegal(data.getCustomerName())) {//       failDataOperation(data, "姓名格式错误(中文2-4位)");//       throw new ExcelAnalysisStopException(data.getCustomerName()+":姓名应该是中文2-4位,请重新输入!");//    }CpCustomercpCustomer=cpCustomerService.getOne(Wrappers.<CpCustomer>query().eq("phone_num", data.getPhoneNum()));
Optional.ofNullable(cpCustomer).ifPresent(customer-> {
LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data));
// 避免名字中间存在空格StringnewName="";
StringoldName="";
if (StrUtil.isNotBlank(data.getCustomerName())) {
newName=data.getCustomerName().replace(" ", "");
         }
if (StrUtil.isNotBlank(cpCustomer.getCustomerName())) {
oldName=cpCustomer.getCustomerName().replace(" ", "");
         }
if (!newName.equals(oldName)) {
data.setId(cpCustomer.getId());
list.add(data);
         }
LOGGER.info("需要修改的数据:{}", list);
      });
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOMif (list.size() >=BATCH_COUNT) {
// 添加到数据库//saveData();// 修改数据库数据updateData();
// 存储完成清理 listlist.clear();
      }
   }
/*** 所有数据解析完成了 都会来调用** @param context*/@OverridepublicvoiddoAfterAllAnalysed(AnalysisContextcontext) {
// 这里也要保存/修改数据,确保最后遗留的数据也存储到数据库//saveData();if (CollUtil.isNotEmpty(list)) {
// 修改数据updateData();
LOGGER.info("所有数据解析完成!");
      }else {
LOGGER.info("没有需要修改的数据");
      }
   }
/*** 加上存储数据库(判断数据库中是否存在该数据)*/privatevoidsaveData() {
LOGGER.info("{}条数据,开始存储数据库!", list.size());
cpCustomerService.saveBatch(list);
LOGGER.info("存储数据库成功!");
   }
@OverridepublicvoidonException(Exceptionexception, AnalysisContextcontext) {
LOGGER.error("解析失败:{}", exception.getMessage());
// 以下为导入内容格式转换检测:如:时间格式“yyyy-MM-dd HH:mm:ss”// 如果是某一个单元格的转换异常 能获取到具体行号;如果要获取头的信息 配合invokeHeadMap使用introw=0;
intcol=0;
Stringtitle="";
if (exceptioninstanceofExcelDataConvertException) {
ExcelDataConvertExceptionexcelDataConvertException= (ExcelDataConvertException)exception;
col=excelDataConvertException.getColumnIndex();
row=excelDataConvertException.getRowIndex();
LOGGER.error("第{}行,第{}列解析异常,数据为:{}", row, col , excelDataConvertException.getCellData());
title=this.headMap.get(col);
LOGGER.info("出错标题列名称:{}", title);
      }
// 此处抛出异常则--停止导入  不抛出异常则--继续往下导入//    throw new ExcelAnalysisStopException(exception.getMessage()+(row==0?"":", 出错行:"+row)+("".equals(title)?"": "出错列:"+title));   }
@OverridepublicvoidinvokeHeadMap(Map<Integer, String>headMap, AnalysisContextcontext) {
this.headMap=headMap;
   }
/*** 修改数据库*/publicvoidupdateData() {
LOGGER.info("{}条数据,开始修改数据库信息!", list.size());
try {
cpCustomerService.updateBatchById(list);
      }catch (Exceptione){
LOGGER.error("以下数据修改过程中出现错误,请重新导入:{}", list);
list.forEach(data->failDataOperation(data, "修改过程中出现错误,请重新导入!"));
thrownewExcelAnalysisStopException("以下数据修改过程中出现错误,请重新导入:"+list);
      }
LOGGER.info("修改数据库成功!");
   }
/*** 失败信息操作公共方法* @param data*/privatevoidfailDataOperation(CpCustomerdata, Stringmessage) {
ImportCustomerExcelModelmodel=newImportCustomerExcelModel();
BeanUtil.copyProperties(data, model);
model.setMessage(message);
errList.add(model);
   }
}


以上的监听器中有我业务处理的逻辑,官网的介绍请看这里:https://www.yuque.com/easyexcel/doc/read

目录
相关文章
|
5月前
|
前端开发 easyexcel Java
springboot使用EasyExcel导入数据(获取行号)
springboot使用EasyExcel导入数据(获取行号)
584 1
|
6月前
|
easyexcel Java 数据库
怎样用EasyExcel导出更多代码?
在处理大量数据导出时遇到Java OutOfMemoryError(OOM)。最初使用公司内部工具直接查询全量数据写入Excel,导致OOM。改用阿里EasyExcel后,虽偶发OOM,但问题依旧存在。为解决此问题,采用了分页查询并分批次写入Excel的方法,有效避免了OOM。为简化此过程,封装了一个EasyExcelExport抽象类,包含分批次导出和不分批次导出的方法。使用时需实现getData()和convertSourceData2ExportEntity()方法。通过示例展示了如何利用这个工具类进行分批导出,避免了内存溢出,并减少了重复代码。
|
6月前
|
easyexcel
EasyExcel导出工具类
EasyExcel导出工具类
121 0
fastadmin实现导出Excel和导入Excel数据
fastadmin实现导出Excel和导入Excel数据
359 0
|
6月前
|
存储 分布式计算 DataWorks
如何使用MaxComputer将csv表格文件上传到pycharm?
如何使用MaxComputer将csv表格文件上传到pycharm?
128 1
|
easyexcel
EasyExcel导出复杂表格到邮箱
自定义单元格合并策略、调用示例、工具类Bo、Excel 模板导出工具类、Vo配置、效果图、MailUtils、模板配置
306 0
 EasyExcel导出复杂表格到邮箱
|
Java easyexcel
Java——使用EasyExcel导出动态列的Excel
Java——使用EasyExcel导出动态列的Excel
|
JavaScript
laravel-导入EXCEL
laravel-导入EXCEL
146 0
php导入Excel表格接口
php导入Excel表格接口
73 0
|
easyexcel Java BI
SpringBoot 实现合并表头导出数据 - EasyExcel应用
EasyExcel是一款开源的Java处理Excel文件的工具库,它提供了简单易用的API,可以方便地读取、写入和操作Excel文件。下面是一些常见的EasyExcel应用场景: 读取Excel文件:使用EasyExcel可以轻松地读取Excel文件中的数据,并将其转换为Java对象或集合。你可以指定读取的起始行、列,还可以处理不同Sheet的数据。