前一段时间在写一个灌溉系统的项目,项目要求有数据导入导出,这一块正好分配给我去完成了,所以我上网学了一下EasyExcel的使用。
pom导入:
1 2 3 4 5
| <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>最新版本</version> </dependency>
|
实体类:
@ColumnWidth:定义列宽
@ExcelProperty:value:用于匹配excel中的头,必须全匹配,如果有多行头,会匹配最后一行头
@ExcelIgnore:加了该注解的字段会被忽略
@DateTimeFormat:日期转换
@NumberFormat:数字转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @Data @NoArgsConstructor @AllArgsConstructor @ColumnWidth(20) public class Field { @ExcelProperty({"地块编号"}) private String fieldId; @ExcelProperty({"冠层温度"}) private BigDecimal canopyTemp; @ExcelProperty({"土壤含水量"}) private BigDecimal soilMoisture; @ExcelProperty({"灌溉决策结果"}) private Integer result; @ExcelProperty({"灌溉情况"}) private String irrigationInfo; @ExcelProperty({"其他情况"}) private String other; }
|
导入:
监听器:
如果想在抛出异常时跳过异常的地方继续读接下来的数据,可以查看官方文档,在监听器中配置一个异常的方法。因为我写的时候想的是导入数据错误的话让他导入失败,所以没有进行配置这一项。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| @Slf4j public class ExcelDataListener implements ReadListener<Field> {
private static final int BATCH_COUNT = 100;
private List<Field> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
private FieldService fieldService;
public ExcelDataListener() { fieldService = new FieldServiceImpl(); }
public ExcelDataListener(FieldService fieldService) { this.fieldService = fieldService; }
@Override public void invoke(Field data, AnalysisContext context) { log.info("解析到一条数据:{}", JSON.toJSONString(data)); cachedDataList.add(data); if (cachedDataList.size() >= BATCH_COUNT) { saveData(); cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); } }
@Override public void doAfterAllAnalysed(AnalysisContext context) { saveData(); log.info("所有数据解析完成!"); }
private void saveData() { log.info("{}条数据,开始存储数据库!", cachedDataList.size()); fieldService.saveData(cachedDataList); log.info("存储数据库成功!"); } }
|
service:
importData:调用接口传入文件,然后调用这个方法。
saveData:监听器存数据库时调用的方法,可以自定义。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Override public ReturnUtil<String> importData(MultipartFile file) { try { EasyExcel.read(file.getInputStream(), Field.class, new ExcelDataListener(this)).sheet().doRead(); } catch (Exception e) { e.printStackTrace(); return ReturnUtil.error("导入数据错误"); } return ReturnUtil.success("导入数据完成"); }
@Override @Transactional(rollbackFor = Exception.class) public void saveData(List<Field> fieldList) { for (Field field : fieldList) { System.out.println(field); } fieldDao.insertMore(fieldList); }
|
导出数据:
因为我是导出为一个文件,所以将官方文档中的导出数据和下载文件结合到了一起。
按下面那个代码导出的文件名为”田间实时数据.xlsx”,然后表格头是在实体类中定义的。
这里我用了重复多次写入,因为我看官方文档中写的不能一次写入太多数据,否则会出错,所以我用分页的操作进行了多次写入,防止写入时出错。
注意:在测试的时候不能用swagger测试,不然下载的文件名是乱码,要把后缀名修改后才能查看。建议用postman或者在网页上直接测试。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| @Override public ReturnUtil<String> exportData(HttpServletResponse response) { response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), Field.class).build()) { String fileName = URLEncoder.encode("田间实时数据", "UTF-8").replaceAll("\\+", "%20"); response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); WriteSheet writeSheet = EasyExcel.writerSheet("田间实时数据").build(); long total = fieldDao.selectCount(null); long num = total / 50; if (total % 50 != 0) { num++; } for (int i = 1; i <= num; i++) { IPage<Field> page = new Page<>(i, 50); List<Field> data = fieldDao.selectPage(page, null).getRecords(); excelWriter.write(data, writeSheet); } if(num==0){ List<Field> data = new ArrayList<>(); excelWriter.write(data,writeSheet); } } catch (IOException e) { log.error("导出数据错误"); return ReturnUtil.error("导出数据错误"); } return ReturnUtil.success("导出数据完成"); }
|