日常工作中,我们经常会遇到使用 Excel 批量导入的需求,正常情况下,我们会在 Controller 中接收前端传过来的文件流,并进行解析
@RequestMapping("importExcel") public ResultDTO> importExcel(@RequestParam("file") MultipartFile file) { try (InputStream in = file.getInputStream()) { // TODO 解析 Excel List
EasyExcel.read(in)... } catch (IOException e) { e.printStackTrace(); } return null; }
这样做看起来也挺好的,常规也是这样做的。
但是在团队中,会遇到这些问题
- 对 EasyExcel 的 API 不熟悉,容易出错解析 Excel 放在 Controller 层?还是 Service 层?支持 Excel 导入,又要支持在页面上的批量 *** 作,如何复用?
做过多次类似需求的同学会发现,导入其实是一种 批量 *** 作 的手段,而 Excel 是一种数据交互格式,就像 JSON 和 XML 一样。若直接在前端进行Excel解析成 JSON,对于后端来说,就只要提供一个批量 *** 作的接口就可以完成批量 *** 作和 Excel 导入两个需求了。
话外音:前端的很多限制,请不要在前端做 Excel 解析
因此,我们可以得出一个洞察:Excel 导入本质上是一种通过 Excel 这种数据交互格式进行批量 *** 作的手段
有了这个认识,我们比较容易想到,
应该在 Controller 层将 Excel 解析成批量 *** 作所使用的数据对象然后复用批量 *** 作的 Service 方法即可
然而,很多人在先接到了一个 Excel 导入的需求时,没多想,把很多业务逻辑与 EasyExcel 耦合在一起,结果再来一个批量 *** 作的需求,因为难以解耦(可能也不是同一个人做),就重起一个方法,把相同的业务逻辑再写了一遍,增加开发和维护成本。
那么,如何优雅地实现 Excel 导入呢?
既然是一种协议,那就应该像 JSON 那样,我们在写后端代码时是不需要感知到 JSON 解析的过程的
所以要看一下在 SpringMVC 中 JSON 是如何被解析的?
解决方案经过研究,SpringMVC 是通过一系列实现 HttpMessageConverter 接口的类来支持不同三方包来解析 JSON 请求体的。
我们要实现批量 *** 作,要接收一个 List
模仿 AbstractJsonHttpMessageConverter 的写法,我们实现 canRead 和 read 两个方法:
@Component // 让 Spring 扫描可以扫到 public class ExcelHttpMessageConverter implements GenericHttpMessageConverter
因为 Excel 解析需要指定一些配置参数,我们约定 用于接收 Excel 的类必须打上 ExcelBody 这个注解。
@Inherited @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface ExcelBody { String sheetName() default ""; int sheetNo() default -1; int headRowNumber() default 1; }用一下试试
首先,我们写一个批量更新的接口,注意在参数前加上 @RequestBody 像普通接收 JSON 格式数据的接口一样
@PostMapping("batchUpdateUser") public ListbatchUpdateUser(@RequestBody List user) { return user; }
然后在请求体的定义中加上 ExcelBody 注解即可
@Data @ExcelBody public class UpdateUserByIdDTO { @ExcelProperty("id") private Long id; @ExcelProperty("用户名") private String username; @ExcelProperty("地址") private String address; }
我们建一个 Excel 文件,根据 UpdateUserByIdDTO 定义的字段名称,造几条测试数据
使用 PostMan 调用一下,看看效果
可以看见,Excel 的解析对于业务代码就完全透明了
看起来这个接口跟普通的接口一样,那我完全不改代码,可以像常规的接口那样用 JSON 格式数据调用吗?试试就知道了
答案是,可以!!
通过这个办法,我们就可以用一个接口,即实现页面上普通的批量 *** 作,又支持 Excel 导入进行批量 *** 作了!
待优化本文提供的演示代码只实现了最简单的解析,若要完善起来还有很多可以做的。例如:
- 数据格式校验(Excel 是用户直接上传的,无法要求他们一定按模板提交,内容填错会读取失败,生成程序抛异常,应支持数据验证并提供友好的提示给用户)多 Sheet 读取。目前我们直接限定接收对象只能是 List,其实可以支持一个普通类,拥有多个 List 字段,每个 List 代表一个 Sheet自定义转换器,以应对复杂的模板解析
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)