前提:引入 EasyExcel 依赖
1 2 3 4 5 6
| <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.1.3</version> </dependency>
|
1. 导出Excel
1.1 导出的实体类
在该类中定义需要导出的内容,其中
@HeadRowHeight
:指定导出行高
@ExcelProperty(value='标题名称', index=0)
:指定导出列的名称以及顺序
@ColumnWidth
: 指定导出列的宽度
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
|
@TableName(value ="staff_info") @HeadRowHeight(value = 30) @Data public class StaffInfo implements Serializable {
@ExcelProperty(value = "员工ID", index = 0) @ColumnWidth(value = 20) private String staffId;
@ExcelProperty(value = "员工姓名", index = 1) @ColumnWidth(value = 20) private String staffName;
@ExcelProperty(value = "员工年龄", index = 2) @ColumnWidth(value = 20) private Integer staffAge;
@ExcelProperty(value = "员工性别", index = 3) @ColumnWidth(value = 20) private String staffSex; }
|
1.2 按模板导出Excel
支持多sheet
页导出,在获取 sheet
对象时指定 sheet
页的顺序及名称即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public void easyExcelExport(HttpServletResponse response) { response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); try { String fileName = URLEncoder.encode("导出xlsx测试", "UTF-8"); response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx"); ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build(); WriteSheet sheet0 = EasyExcel.writerSheet(0, "员工信息-1").head(StaffInfo.class).build(); List<StaffInfo> staffInfos = staffInfoMapperl.selectAllByStaffAge(24); excelWriter.write(staffInfos, mainSheet); WriteSheet sheet1 = EasyExcel.writerSheet(1, "员工信息-2").head(StaffInfo.class).build(); List<StaffInfo> staffInfos1 = staffInfoMapperl.selectAllByStaffAge(24); excelWriter.write(staffInfos1, secondSheet); excelWriter.finish(); } catch (Exception e) { logger.error("导出异常{}", e.getMessage()); } }
|
在浏览器中测试导出接口,获取导出的Excel文件如下
2. 导入Excel
2.1 导入的实体类
导入实体类可参考导出实体类,核心注解为
@ExcelProperty(value=”标题名称”)
其中标题名称需要与导入的标题名称对应,才能正确解析
2.2 ExcelListener 监视器类
继承自EasyExcel
的AnalysisEventListener
类,用于解析Excel
数据,其中datas
为解析内容的List
。
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 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
|
@Slf4j public class ExcelListener<T> extends AnalysisEventListener<T> {
private static int dataCount = 0;
List<String> errors = new ArrayList<>();
List<T> data = new ArrayList<>();
@Override public void invoke(T o, AnalysisContext analysisContext) { log.info("成功解析到一条数据:{}", JSONObject.toJSONString(o)); dataCount++; data.add(o); }
@Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { log.info(("成功读取共" + dataCount + "条数据")); }
public List<T> getData() { return data; }
public void setData(List<T> data) { this.data = data; }
public List<String> validate(List<T> data, int offset) { Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); for (int i = 0; i < data.size(); i++) { Set<ConstraintViolation<T>> validate = validator.validate(data.get(i)); if (!CollectionUtils.isEmpty(validate)) { String errorMessage = "第" + (i + offset) + "行数据校验有误:" + validate.stream().map(ConstraintViolation::getMessage) .collect(Collectors.joining(",")) + ";"; errors.add(errorMessage); } } return errors; }
public List<String> checkDuplicate(List<T> data, int offset) { for (int i = 0; i < data.size(); i++) { T itemA = data.get(i); List<Integer> duplicateRows = new ArrayList<>(); duplicateRows.add(i + offset); for (int j = i + 1; j < data.size(); j++) { T itemB = data.get(j); if (itemA.equals(itemB)) { duplicateRows.add(j + offset); } } if (duplicateRows.size() >= 1) { String errorMessage = "第" + duplicateRows.stream().map(Object::toString) .collect(Collectors.joining("、")) + "行数据重复;"; errors.add(errorMessage); } } return errors; } public List<String> validateAndCheckDuplicate(List<T> data, int offset){ List<String> validate = validate(data, offset); List<String> duplicate = checkDuplicate(data, offset); validate.addAll(duplicate); return validate; } }
|
2.3 导入解析Excel
支持导入多 sheet
页的数据,示例中 staffinfos
为拿到的解析内容。
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
| @RequestMapping("/import") public RetDataBean easyExcelImport(@RequestParam("xlsxFile") MultipartFile multipartFile){ RetDataBean<Object> retDataBean = new RetDataBean<>(RetcodeEnum.SUCCESS.getCode(), RetcodeEnum.SUCCESS.getMsg()); try { InputStream inputStream = multipartFile.getInputStream(); ExcelListener listener = new ExcelListener(); ExcelReader excelReader = EasyExcel.read(inputStream, listener).build(); ReadSheet readSheet1 = EasyExcel.readSheet(0).head(StaffInfo.class).build(); excelReader.read(readSheet1); List<Object> list = listener.getDatas(); List<StaffInfo> staffInfos = new ArrayList<>(); for (Object o : list) { StaffInfo staffInfo = (StaffInfo) o; staffInfos.add(staffInfo); } listener.getDatas().clear(); ReadSheet readSheet2 = EasyExcel.readSheet(1).head(StaffInfo.class).build(); excelReader.read(readSheet2); excelReader.close(); } catch (Exception e) { logger.error("导入异常",e); retDataBean.setRetCode(RetcodeEnum.Fail.getCode()); retDataBean.setRetMsg(RetcodeEnum.Fail.getMsg()); }; return retDataBean; }
|