利用EasyExcel导入导出多个sheet和多个table 您所在的位置:网站首页 一张表格拆分多个sheet 利用EasyExcel导入导出多个sheet和多个table

利用EasyExcel导入导出多个sheet和多个table

2024-06-11 11:19| 来源: 网络整理| 查看: 265

最近项目需要导入导出多个sheet,并且同一个sheet里面导入导出两个或者多个Table,实现过程如下:

Excel导出

导出某个sheet,指定sheet名:

WriteSheet writeSheet = EasyExcel.writerSheet(tableName).build();

指定sheet中的每个表(Table)的表头以及导出对应的实体类,序号0,1分别表示第几张表,head为指定表头以及表导出对应的实体类:

WriteTable writeTable = EasyExcel.writerTable(0).head(TableExcelData.class).needHead(true).build(); WriteTable writeTable2 = EasyExcel.writerTable(1).head(ItemExcelData.class).needHead(true).build();

这里我的TableExcelData.class和ItemExcelData.class分别是导出Excel的实体,其中一个定义如下。这里注意用EasyExcel导出时,@NoArgsConstructor是必须标注的,不然会报错;@ContentStyle(dataFormat = 49)主要指定导出时间时Excel单元格格式为文本格式,不然为常规格式的话,“yyyy-MM-dd HH:mm:ss"在excel中点击后会变成"yyyy/MM/dd HH:mm:ss”,不利于格式的统一。

@AllArgsConstructor @NoArgsConstructor @Data @ToString @Builder(toBuilder = true) @ApiModel(value = "Excel实体", description = "数据信息") public class InspectionTableExcelData { @ExcelProperty(value = "表名称") @NotNull private String tableName; @ExcelProperty(value = "类型名称") @NotNull private String typeName; @ExcelProperty(value = "创建人姓名") @NotNull private String creatorName; @ExcelProperty(value = "表建立时间", converter = InstantConverter.class) @NotNull @ContentStyle(dataFormat = 49) private Instant tableCreationTime; }

下面是对每个sheet的每个Table进行写入:

excelWriter.write(ImmutableList.of(inspectionTableExcelData), writeSheet, writeTable); excelWriter.write(inspectionItemExcelDataList, writeSheet, writeTable2); ExcelWriter excelWriter = null; try { excelWriter = EasyExcel.write(ExcelUtil.getOutputStream(fileName, response)).build(); for(Long id:idList) { WriteSheet writeSheet = EasyExcel.writerSheet(tableExcelData.getTableName()).build(); WriteTable writeTable = EasyExcel.writerTable(0).head(TableExcelData.class).needHead(true).build(); WriteTable writeTable2 = EasyExcel.writerTable(1).head(ItemExcelData.class).needHead(true).build(); excelWriter.write(ImmutableList.of(tableExcelData), writeSheet, writeTable); excelWriter.write(itemExcelDataList, writeSheet, writeTable2); } }catch(Exception e){ throw new MMSException(FAILED_TO_EXPORT.getCode(),"导出表失败",FAILED_TO_EXPORT.getMsg()); }finally { if (excelWriter!=null){ excelWriter.finish(); } } Excel导入

导入相对复杂些,需要实现如下同一个sheet导入两个Table,第一个Table只有一项,第一个Table有若干项,经过多番查阅和实验最终得到结果: 在这里插入图片描述 主要有以下几点: dest为需要读取的文件File,file为上传的MultiFile类文件,这里需要扩展AnalysisEventListener并对一些方法进行重写,特别是需要自己实现保存数据的方法,需要自己传入一些mapper或者converter之类。 以下是通过读取dest文件,从而获得我们上传文件的sheet的List;

List readSheetList = EasyExcel.read(dest).build().excelExecutor().sheetList();

对于List里面的每个ReadSheet也就是对于每个sheet,我们进行一一导入,如下,通过sheet(readSheet.getSheetName())读取某个sheet,通过指定java spring需要匹配的实体类(TableExcelData.class)以及我们的Listener。

EasyExcel.read(dest, TableExcelData.class, new TableExcelListener(tableMapper,tableConverter, tableExcelConverter)) .sheet(readSheet.getSheetName()) .doRead(); EasyExcel.read(dest, ItemExcelData.class, new TableExcelListener(ItemMapper, itemConverter,itemExcelConverter)) .sheet(readSheet.getSheetName()) .headRowNumber(3) .doRead();

headRowNumber(3)表示我们第一个Table从Excel的第3行为表头开始读,这里有个问题,就是我们在读取sheet的时候,EasyExcel默认是读取全部的,因此在读第一个Table的同时也会将第二个Table包括表头和内容都读入,并且用第一个表的class进行匹配,显而易见,这样会出错。因此我们需要指定第一个Table的停止读取的逻辑,由于我第一个Table只需要读一项,因此当读取到第一项就需要停止读取。网上查阅资料并没有发现EasyExcel怎么能够实现这个功能,通过去读EasyExcel的源码中 ReadListener发现其有个hasNext方法,其方法解释为,我们可以通过返回false从而让EasyExcel停止读取。这里因为我们第一个Table只读取一项就停止了。因此我们可以在继承的Listener上实现hasNext()方法,这里通过判断我们用于临时存储我们实体的一个list,如果list的size等于1了,就令hasNext返回false。

/** * Verify that there is another piece of data.You can stop the read by returning false * * @param context * @return */ boolean hasNext(AnalysisContext context); }

Listener完整代码如下:

@Component public class TableExcelListener extends AnalysisEventListener { private static final Logger LOGGER = LoggerFactory.getLogger(TableExcelListener.class); private static final int BATCH_COUNT = 5; List list = new ArrayList(); private TableMapper tableMapper; private TableConverter tableConverter; private TableExcelConverter tableExcelConverter; public TableExcelListener(TableMapper tableMapper, TableConverter tableConverter, TableExcelConverter tableExcelConverter){ this.tableMapper = tableMapper; this.tableConverter = tableConverter; this.tableExcelConverter = tableExcelConverter; } // 一条一条数据解析 invoke()方法 @Override public void invoke(TableExcelData tableExcelData, AnalysisContext analysisContext){ list.add(tableExcelData); if(list.size()>=BATCH_COUNT){ saveData(); list.clear(); } } @Override public void onException(Exception exception, AnalysisContext context) { LOGGER.error("解析失败,但是继续解析下一行:{}", exception.getMessage()); // 如果是某一个单元格的转换异常 能获取到具体行号 // 如果要获取头的信息 配合invokeHeadMap使用 if (exception instanceof ExcelDataConvertException) { ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception; LOGGER.error("第{}行,第{}列解析异常", excelDataConvertException.getRowIndex(), excelDataConvertException.getColumnIndex()); // ASException为自定义异常 exception.printStackTrace; } } // 所有数据解析完, doAfterAllAnalysed()方法,里面写的有保存数据方法 @Override public void doAfterAllAnalysed(AnalysisContext analysisContext){ saveData(); LOGGER.info("所有数据解析完成!"); } // 业务逻辑,实现保存数据的方法 private void saveData(){ for(TableExcelData tableExcelData:list){ try{ TableDTO tableDTO = tableExcelConverter.toDTO(tableExcelData); TableDO tableDO = tableConverter.toDO(tableDTO); this.tableMapper.addTable(tableDO); }catch(Exception e){ e.printStackTrace; } LOGGER.info("{}条数据,开始存储数据库!",list.size()); LOGGER.info("存储数据库成功!"); } } // 停止条件,如果list元素为1个时,停止读取数据 @Override public boolean hasNext(AnalysisContext analysisContext){ if(list.size()>=1){ return false; } return true; } }

最后贴一下实现上传的代码:

public int uploadTableExcel(MultipartFile file) { String fileName = file.getOriginalFilename(); // TODO 怎么处理路径 不生成临时文件 String tmpPath = System.getProperty("user.dir") + "/tmpPath/"; File dest = new File(tmpPath+fileName); if(!dest.getParentFile().exists()){ dest.getParentFile().mkdirs(); } try{ // 用来把 MultipartFile 转换成 File file.transferTo(dest); } catch (Exception e) { e.printStackTrace; } try { List readSheetList = EasyExcel.read(dest).build().excelExecutor().sheetList(); for(ReadSheet readSheet:readSheetList) { EasyExcel.read(dest, TableExcelData.class, new TableExcelListener(tableMapper,tableConverter, tableExcelConverter)) .sheet(readSheet.getSheetName()) .doRead(); EasyExcel.read(dest, ItemExcelData.class, new TableExcelListener(ItemMapper, itemConverter,itemExcelConverter)) .sheet(readSheet.getSheetName()) .headRowNumber(3) .doRead(); } } catch (Exception e) { e.printStackTrace; } }

参考文章: easyexcel 使用table写入 easyexcel源码 急!请问EasyExcel如何获取sheetname? EasyExcel从指定位置开始读数据 EasyExceld读取流程图 官方文档 Easyexcel github



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有