背景

Excel 导入与导出是项目中经常用到的功能,在 Java 中常用 poi 实现 Excel 的导入与导出。由于 poi 占用内存较大,在高并发下很容易发生 OOM 或者频繁 fullgc,阿里基于 poi 开源了 EasyExcel 项目。

除了节约内存,EasyExcel 还简化了 API,通过注解映射 Excel 单元格与对象字段之间的关系,简单的几行代码就能搞定复杂的导入导出功能了。

EasyExcel 问题

看似一切美好,不过经常做 Excel 导入与导出就会发现,EasyExcel 还是没那么完美的。

首先,导入与导出 Excel 本质是上将 Excel 文件内容与 Java 对象之间做一个映射,EasyExcel 做的只是在这两者之间转换。如果项目中的 Excel 导入与导出功能比较多,会产生大量的样板式代码,使用体验类似于 JDBC。

另外,导入往往还伴随着校验,这是 EasyExcel 没有支持的功能。如果需要校验,要么写代码手动判断,要么调用 Java Validation 规范 定义的 API 判断,这又会产生大量样板式代码。

而且,当前 spring boot 已经成了必备的 Java 开发框架,easyexcel 也没有进行整合。

分析与解决

导入与导出通常发生在 Web 环境,对于 Spring MVC 来说,可以将请求信息转换为任意类型的 contoller 方法参数,将 controller 方法返回值转换为客户端支持的内容。

如果能够使用自定义的 controller 方法参数接收 Excel 文件内容,将 controller 方法返回值转换为 Excel 文件响应,可以直接消除 Excel 导入与导出时的样板式代码。

另外在将请求内容转换为 controller 方法参数时还可以加入自定义的校验逻辑。

由于 Excel 导入与导出样板式代码、校验问题与具体的业务逻辑无关,可以单独抽象出来,我这里在 EasyExcel 的基础上封装了一个 easyexcel-spring-boot-starter 的项目,大大降低了 EasyExcel 上手的门槛,对用户来说只需要使用 EasyExcel 定义的注解提供映射关系就可以了,适用于简单场景的导入导出。

项目代码已上传:

https://github.com/zzuhkp/easyexcel-spring-boot-starter

下面就来看看怎样使用吧。

Spring Boot Excel 导入与导出

依赖引入

首先需要引入依赖,坐标如下。

<dependency><groupId>com.zzuhkp</groupId><artifactId>easyexcel-spring-boot-starter</artifactId><version>1.0-SNAPSHOT</version>
</dependency>

不过很不幸的是目前还没传至中央仓库,需要的小伙伴可自行上传到私有仓库或直接把代码嵌入自己的项目。

Excel 导入

首先看下要导入的 Excel 内容吧。

为了接收 Excel 文件内容,我们需要定义一个对应的 Model 类。

@Data
public class DemoData {@ExcelProperty(index = 0)private Integer integer;@ExcelProperty(index = 1)private String string;@ExcelProperty(index = 2)private Date date;
}

基本导入功能

然后使用 List<T> 参数接收即可。

@PostMapping("/list/obj")
public List<DemoData> listObj(@ExcelParam List<DemoData> list) {return list;
}

注意参数前添加了 @ExcelParam 注解,用来标识 Excel 文件参数。这样,一个导入功能实现了,是不是很简单呢?

默认情况下接收名称为 file 的表单字段作为 Excel 文件,如果不满足还可以修改。

@ExcelParam(value = "file", required = true)

进阶导入功能

有时候,我们可能比较关心对象对应 Excel 的元数据,例如这个对象是第几行记录产生的,这个对象的字段对应 Excel 第几列,这个时候我们可以使用 ReadRows<T> 参数接收 Excel。

@PostMapping("/list/rows")
public ReadRows<DemoData> readRows(@ExcelParam ReadRows<DemoData> readRows) {return readRows;
}

ReadRows 使用两个字段记录行映射关系与列映射关系。

public class ReadRows<T> {private ExcelReadHeadProperty excelReadHeadProperty;private List<ReadRow<T>> rows;
}

ExcelReadHeadProperty 是 EasyExcel 自带的类,表示列映射关系的元数据。ReadRow 是框架自定义的类,表示行映射关系的元数据。

看下 ReadRow 定义吧。

public class ReadRow<T> {// 行索引,从 0 开始private final Integer rowIndex;// 行记录对应对象private final T data;
}

使用 ExcelReadHeadProperty 获取字段对应列索引的示例代码如下。

// 对象字段名称 -> 从 0 开始的列索引
Map<String, Integer> fieldColumnIndexMap = readRows.getExcelReadHeadProperty().getHeadMap().values().stream().collect(Collectors.toMap(Head::getFieldName, Head::getColumnIndex));

Excel 导出

这里对 Excel 的导出进行了简单的支持。将 List<T> 定义为 controller 方法返回值即可。

@ExcelResponse
@GetMapping("/list/download")
public List<DemoData> downloadList() {return Arrays.asList(new DemoData(1, "hello", new Date()), new DemoData(2, "excel", new Date()));
}

需要注意的是使用 @ExcelResponse 注解表示响应内容为 Excel 文件。默认情况,下载的文件名称为 default.xlxs,写入到名称为 Sheet1 的工作表中。如果不满足需求可以修改。

@ExcelResponse(fileName = "测试文件", sheetName = "工作表1")

Excel 导入参数校验

参数校验是 Excel 导入常用的功能,这里进行了强有力的支持,使用体验如原生 spring boot 校验般顺滑。

开启校验

与 spring boot 原生使用方式一样,将 @Validated 或 @Valid 注解添加到 @ExcelParam 参数上即可。

@PostMapping("/list/obj")
public List<DemoData> listObj(@ExcelParam @Validated List<DemoData> list) {return list;
}

校验规则定义

Bean Validation 定义校验规则

默认情况下框架使用 JSR-303 Bean Validation 规范定义的校验注解校验,需要手动引入 spring-boot-starter-validation,可通过设置环境变量 easyexcel.validator.default.enable=false 关闭。

@Data
public class DemoData {@NotNull(message = "参数不能为空")private Integer integer;private String string;private Date date;
}

另外还可以自定义注解对对象校验。

... 省略其他元注解
@Constraint(validatedBy = {DemoDataValid.DemoDataValidator.class})
public @interface DemoDataValid {... 省略注解属性class DemoDataValidator implements ConstraintValidator<DemoDataValid, DemoData> {@Overridepublic boolean isValid(DemoData value, ConstraintValidatorContext context) {context.disableDefaultConstraintViolation();context.buildConstraintViolationWithTemplate("测试对象校验").addConstraintViolation();return false;}}}
@DemoDataValid
public class DemoData {... 省略属性
}

ExcelValidator 接口定义校验规则

Bean Validation 注解只能校验单个字段或对象,如果需要对所有的对象进行校验,可以实现框架定义的 ExcelValidator 接口,然后将实现定义为 Spring Bean。

这个接口定义如下。

public interface ExcelValidator<T> {ExcelValidErrors validate(ReadRows<T> readRows);
}

ExcelValidErrors 用于接收校验的错误信息,分别使用接口 ExcelValidObjectError 和 ExcelValidFieldError 接口定义行错误信息和单元格错误信息。

public class ExcelValidErrors {// 行错误信息或单元格错误信息列表private final List<ExcelValidObjectError> errors;
}public interface ExcelValidObjectError {// 获取行号,从 1 开始Integer getRow();// 获取错误消息String getMessage();
}public interface ExcelValidFieldError extends ExcelValidObjectError {// 获取列,从 1 开始Integer getColumn();
}

例如,如果需要对所有的 DemoData 校验 integer 字段的值不能重复,可以使用如下的代码。

@Component
public class CustomExcelValidator implements ExcelValidator<DemoData> {@Overridepublic ExcelValidErrors validate(ReadRows<DemoData> readRows) {ExcelValidErrors errors = new ExcelValidErrors();Map<Integer, List<ReadRow<DemoData>>> group = readRows.getRows().stream().collect(Collectors.groupingBy(item -> item.getData().getInteger()));for (Map.Entry<Integer, List<ReadRow<DemoData>>> entry : group.entrySet()) {if (entry.getValue().size() > 1) {for (ReadRow<DemoData> readRow : entry.getValue()) {errors.addError(new DefaultExcelObjectError(readRow.getRowIndex() + 1, "参数重复"));}}}return errors;}
}

校验结果接收

与 Spring MVC 设计类似,这里也提供了两种接收校验结果的方式。

异常捕获接收校验结果

开启校验后,如果校验结果中包含错误,会将错误信息封装到 ExcelValidException,并抛出异常,可以通过全局异常捕获的方式收集错误信息。

@RestControllerAdvice
public class GlobalExceptionControllerAdvice {@ExceptionHandler(ExcelValidException.class)public String handleException(ExcelValidException e) {ExcelValidErrors errors = e.getErrors();return JSON.toJSONString(errors);}
}

controller 方法参数接收校验结果

如果不想通过异常捕获的方式接收校验的错误信息,还可以将错误信息添加到 @ExcelParam 参数的后面,示例代码如下。

@PostMapping("/list/obj")
public List<DemoData> listObj(@ExcelParam @Validated List<DemoData> list, ExcelValidErrors errors) {if (errors.hasErrors()) {String messages = errors.getAllErrors().stream().map(ExcelValidObjectError::getMessage).collect(Collectors.joining(" | "));throw new RuntimeException("发现异常:" + messages);}return list;
}

总结

easyexcel-spring-boot-starter 综合应用了前面文章介绍的各种 Spring 知识,代码量并不大,对实现感兴趣的小伙伴可自行查阅代码。由于这个框架是把 Excel 中所有的行数据收集到内存,因此只适合一些比较简单的场景。

来源:zzuhkp.blog.csdn.net/article/details/125097026

300多本程序员经典技术书籍高清PDF
加我微信,备注:资料扫码备注:资料,自动获取

SpringBoot 项目优雅实现 Excel 导入导出功能相关推荐

  1. SpringBoot中使用Easyexcel实现Excel导入导出功能(三)

    导出的数据包含有图片 导出excel表格的数据包含有图片,这种场景比较少.通Easyexcel实现这样的需求,我认为最简便的方法就是使用前面提到的自定义转换器(com.alibaba.excel.co ...

  2. SpringBoot中使用Easyexcel实现Excel导入导出功能(一)

    目录 前言 1.常规导入 2.读取到指定的列 3.读取全部的sheet页 4.日期.数字及其他自定义格式的转换 5.表头有多行的表格读取 6.表头数据的读取 7.单元格内的备注内容读取 前言 exce ...

  3. SpringBoot 项目实现 Excel 导入导出功能

    背景 Excel 导入与导出是项目中经常用到的功能,在 Java 中常用 poi 实现 Excel 的导入与导出.由于 poi 占用内存较大,在高并发下很容易发生 OOM 或者频繁 fullgc,阿里 ...

  4. VUE的Excel导入导出功能

    在做人力资源管理的后台项目时,实现了excel表的导入导出功能.用到了vue-element-admin提供的框架(链接地址 ),我们只需要在自己的项目中封装改造即可. 项目中实现excel表的导入与 ...

  5. SpringBoot集成EasyPoi实现Excel导入导出

    作者介绍: 本人Java特工,代号:Cris Li : 中文名:克瑞斯理 简书地址: 消失的码农 - 简书 CSDN地址: https://blog.csdn.net/jianli95 个人纯洁版博客 ...

  6. 【飞秋】ASP.NET 之 常用类、方法的超级总结,并包含动态的EXCEL导入导出功能,奉上类库源码

    最近闲了,花点几天时间将项目中常用的一些类.方法做了一下总结,希望对大家有用. 实用类:UtilityClass 包含如下方法 判断对象是否为空或NULL,如果是空或NULL返回true,否则返回fa ...

  7. tiptop使用java的poi包实现EXCEL导入导出功能

    4gl可以调用java的poi包实现EXCEL的导入导出,今天分享一个EXCEL导入的功能!  一:环境搭建  1:poi文件导入  首先下载POI文件(找不到的可以私信我),解压后上传到ERP的服务 ...

  8. 前端 - excel导入 / 导出功能

    1. 导入功能 1.1 前端主导(工作大量在前端) 上传excel文件,把excel文件的内容读出来,还原成最基本的行列结构,按后端的接口要求回传过去. 前端读excel文件,调接口 1.2 后端主导 ...

  9. vue中实现Excel导入导出功能

    导入Excel功能 前置条件: 依赖包xlsx npm install xlsx -S 这里提供一个现成的在vue中导入Excel的功能(原作者-花裤衩),代码在最下面,可直接复制. 创建一个文件夹, ...

最新文章

  1. 通过Appium获取Android app中webview
  2. java 对象 php对象_java对象是什么?
  3. 多master mysql_使用 Rotate Master 实现MySQL 多主复制
  4. Redis 内存压缩实战,学习了!
  5. shell 解析 json
  6. python连数据库课程设计_python 连接操作 各类数据库
  7. myeclipse中的classpath .
  8. 成都理工大学工程技术学院计算机专业收分线,2019年成都理工大学工程技术学院美术类专业录取分数线...
  9. 【LeetCode 剑指offer刷题】树题4:104 Maximum Depth of Binary Tree
  10. Python源码深度解析—float空闲对象缓存池
  11. WPF Demo20 模板
  12. 【MySQL】MySQL中的死锁
  13. 隐藏水滴屏的软件_手机隐藏水滴屏的APP
  14. 基于R实现统计中的检验方法---方差分析
  15. 性能测试详解(三)Tomcat性能调优
  16. 基于cnn的人脸识别_人脸识别技术:从传统方法到深度学习
  17. 利用python做一个超简单的抽签器
  18. Delphi调用IE打开网页
  19. 爱测未来安全-浅淡流量劫持及应对措施
  20. 洛谷P3387 【模板】缩点 题解

热门文章

  1. linux 安装 vundle
  2. 使用pinyin4j获取汉字的拼音和全角半角转换
  3. 环境噪声监测环保数采仪
  4. 网络安全应急响应----4、DDoS攻击应急响应
  5. LAN8720A网络模块的使用问题
  6. linux tra 网络,linux命令之tr命令用法总结
  7. XML代码的编写(一)
  8. 实验六 : java nio 写文件速度
  9. 电脑游戏的上帝:约翰·卡马克和id
  10. Windows Vista中如何重置Winsock设置_Windows Vista_www.knowsky.com