Spring?Boot项目如何优雅实现Excel导入与导出功能
目录
- 背景
- EasyExcel 问题
- 分析与解决
- Spring Boot Excel 导入与导出
- 依赖引入
- Excel 导入
- 基本导入功能
- 进阶导入功能
- Excel 导出
- Excel 导入参数校验
- 开启校验
- 校验规则定义
- Bean Validation 定义校验规则
- ExcelValidator 接口定义校验规则
- 校验结果接收
- 异常捕获接收校验结果
- controller 方法参数接收校验结果
- 总结
背景
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 定义的注解提供映射关系就可以了,适用于简单场景的导入导出。
项目代码已上传 github easyexcel-spring-boot-starter 仓库,点击链接即可查阅。下面就来看看怎样使用吧。
Spring Boot Excel 导入与导出
依赖引入
首先需要引入依赖,坐标如下。
?
| 1 2 3 4 5 |
|
不过很不幸的是目前还没传至中央仓库,需要的小伙伴可自行上传到私有仓库或直接把代码嵌入自己的项目。
Excel 导入
首先看下要导入的 Excel 内容吧。

为了接收 Excel 文件内容,我们需要定义一个对应的 Model 类。
?
| 1 2 3 4 5 6 7 8 9 10 11 |
|
基本导入功能
然后使用 List<T> 参数接收即可。
?
| 1 2 3 4 |
|
注意参数前添加了 @ExcelParam 注解,用来标识 Excel 文件参数。这样,一个导入功能实现了,是不是很简单呢?
默认情况下接收名称为 file 的表单字段作为 Excel 文件,如果不满足还可以修改。
?
| 1 |
|
进阶导入功能
有时候,我们可能比较关心对象对应 Excel 的元数据,例如这个对象是第几行记录产生的,这个对象的字段对应 Excel 第几列,这个时候我们可以使用 ReadRows<T> 参数接收 Excel。
?
| 1 2 3 4 |
|
ReadRows 使用两个字段记录行映射关系与列映射关系。
?
| 1 2 3 4 5 6 |
|
ExcelReadHeadProperty 是 EasyExcel 自带的类,表示列映射关系的元数据。ReadRow 是框架自定义的类,表示行映射关系的元数据。
看下 ReadRow 定义吧。
?
| 1 2 3 4 5 6 7 8 |
|
使用 ExcelReadHeadProperty 获取字段对应列索引的示例代码如下。
?
| 1 2 3 |
|
Excel 导出
这里对 Excel 的导出进行了简单的支持。将 List<T> 定义为 controller 方法返回值即可。
?
| 1 2 3 4 5 |
|
需要注意的是使用 @ExcelResponse 注解表示响应内容为 Excel 文件。默认情况,下载的文件名称为 default.xlxs,写入到名称为 Sheet1 的工作表中。如果不满足需求可以修改。
?
| 1 |
|
Excel 导入参数校验
参数校验是 Excel 导入常用的功能,这里进行了强有力的支持,使用体验如原生 spring boot 校验般顺滑。
开启校验
与 spring boot 原生使用方式一样,将 @Validated 或 @Valid 注解添加到 @ExcelParam 参数上即可。
?
| 1 2 3 4 |
|
校验规则定义
Bean Validation 定义校验规则
默认情况下框架使用 JSR-303 Bean Validation 规范定义的校验注解校验,需要手动引入 spring-boot-starter-validation,可通过设置环境变量 easyexcel.validator.default.enable=false 关闭。
?
| 1 2 3 4 5 6 7 8 9 |
|
另外还可以自定义注解对对象校验。
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
?
| 1 2 3 4 |
|
ExcelValidator 接口定义校验规则
Bean Validation 注解只能校验单个字段或对象,如果需要对所有的对象进行校验,可以实现框架定义的 ExcelValidator 接口,然后将实现定义为 Spring Bean。
这个接口定义如下。
?
| 1 2 3 |
|
ExcelValidErrors 用于接收校验的错误信息,分别使用接口 ExcelValidObjectError 和 ExcelValidFieldError 接口定义行错误信息和单元格错误信息。
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
例如,如果需要对所有的 DemoData 校验 integer 字段的值不能重复,可以使用如下的代码。
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
校验结果接收
与 Spring MVC 设计类似,这里也提供了两种接收校验结果的方式。
异常捕获接收校验结果
开启校验后,如果校验结果中包含错误,会将错误信息封装到 ExcelValidException,并抛出异常,可以通过全局异常捕获的方式收集错误信息。
?
| 1 2 3 4 5 6 7 8 |
|
controller 方法参数接收校验结果
如果不想通过异常捕获的方式接收校验的错误信息,还可以将错误信息添加到 @ExcelParam 参数的后面,示例代码如下。
?
| 1 2 3 4 5 6 7 8 |
|
总结
easyexcel-spring-boot-starter 综合应用了前面文章介绍的各种 Spring 知识,代码量并不大,对实现感兴趣的小伙伴可自行查阅代码。由于这个框架是把 Excel 中所有的行数据收集到内存,因此只适合一些比较简单的场景。
相关文章:
Spring?Boot项目如何优雅实现Excel导入与导出功能
目录 背景EasyExcel 问题分析与解决Spring Boot Excel 导入与导出 依赖引入Excel 导入 基本导入功能进阶导入功能Excel 导出 Excel 导入参数校验 开启校验 校验规则定义 Bean Validation 定义校验规则ExcelValidator 接口定义校验规则校验结果接收 异常捕获接收校验结果contro…...
lable 某个名称换行 \n /n /br axisLabel换行 文字换行 echarts
axisLabel: {interval: 0,textStyle: {color: #D9D9D9,fontSize: fontChart(0.2),lineHeight:12,},formatter: function (params) {// 交通运输、仓储和邮政业, 制造业, 科学研究和技术服务业if (params 交通运输、仓储和邮政业) { return 交通运输、\n仓储和邮政业 }else if …...
025 - max()函数
MAX() 函数: MAX 函数返回一列中的最大值。NULL 值不包括在计算中。 SQL MAX() 语法: SELECT MAX(column_name) FROM table_name; 注释:MAX 也可用于文本列,以获得按字母顺序排列的最高或最低值。 -- 实际操作(查询salary的最大值&#x…...
JDK 8.x 微服务启动JVM参数调优实战
微服务启动JVM参数调优实战 1.1 配置JVM启动参数1.2 解释1.3 JVM参数优化思路1.3.1 调整堆内存大小1.3.2 年轻代大小1.3.3 Metaspace 大小1.3.4 栈大小1.3.5 垃圾回收器选择1.3.6 垃圾回收参数1.3.7 预分配内存 1.3.8 禁用 ResizePLAB2. 常用JVM参数 1.1 配置JVM启动参数 服务…...
Web与HTTP
目录 DNS与域名 DNS解析的方式 过程 注册域名 html 名词解释 html的语法 web web2.0 静态页面特点 动态页面 动态页面特点 http协议 工作流程 http的请求方式 get post 状态码 常用状态码 通信套接字 套接字调用的端口 DNS与域名 网络是基于tcp/ip协议进…...
算法刷题Day 56两个字符串的删除操作+编辑距离
Day 56 动态规划 583. 两个字符串的删除操作 class Solution { public:int minDistance(string word1, string word2) {int m word1.size(), n word2.size();vector<vector<int>> dp(m 1, vector<int>(n 1, 0));for (int i 0; i < m; i){dp[i][0] …...
Flutter中Dart语言常用知识
目录 1. 变量和数据类型2. 函数3. 类4. 异常处理5. 泛型6. 变量声明和类型推断:7. 函数定义:8. 类定义和实例化:9. 接口定义:10. 抽象类定义:11. 混合类型列表:12. Flutter 中的 UI 组件:13.Dar…...
11万多英藏对照词典英藏翻译ACCESS\EXCEL数据库
今天继续发一个藏文藏语相关的翻译数据库,即英藏对照词典,加上《5万6千多藏文词典解释ACCESS数据库》以及昨天发的《近13万汉藏对照词典汉藏翻译ACCESS\EXCEL数据库》藏文类的数据就算较全了。 截图下方有显示“共有记录数”,截图包含了表的所…...
浅谈C语言分支循环语句
为什么需要循环控制? 因为在日常生活中或者在程序所处理的问题中常常遇见需要重复处理的问题,用循环语句可以提高代码的运行效率,更快的解决日常生活中遇到的问题。 循环嵌套 就是传说中的套娃,不同的循环语句都可以互相嵌套。 …...
Spring Boot Starter 剖析与实践 | 京东云技术团队
引言 对于 Java 开发人员来说,Spring 框架几乎是必不可少的。它是一个广泛用于开发企业应用程序的开源轻量级框架。近几年,Spring Boot 在传统 Spring 框架的基础上应运而生,不仅提供了 Spring 的全部功能,还使开发人员更加便捷地…...
技术能力提升-《系统架构设计师教程》
在最近的月度读书会上,国林哥分享了下对《系统架构设计教程》的一点见解,在技术管理摸爬滚打了多年,觉得这个认证还是有一定价值,希望对有兴趣了解这门认证考试的朋友有所帮助,起到抛砖引玉的作用。 国林哥从以下四个方…...
【LeetCode 热题 100】矩阵 专题(大多原地算法,需要一定思维)
解题思路 在 代码注释中! 文章目录 73. 矩阵置零54. 螺旋矩阵48. 旋转图像240. 搜索二维矩阵 II 73. 矩阵置零 class Solution { public:void setZeroes(vector<vector<int>>& matrix) {// 难点:原地算法// 直接复用 matrix 第一行 和 …...
Java 中为什么要把一个数模(10^9+7)
在计算机科学和编程中,经常会遇到需要对结果进行取模操作的情况。模运算是指将一个数除以另一个数,并取得余数的运算。 在 Java 中,常见的一个数取模的值是 (10^97),即 1000000007。这个特定的数值经常在算法和数学计算中被使用&…...
RPC与REST有什么区别?
原文:RPC与REST有什么区别? 背景 好多开发的同学在工作中,经常分不清RPC和REST的区别,导致经常沟通不在一个层次上。甚至有些同学把这两个当成同一个东西。 RPC与REST的区别? 对比名称 rpc rest 备注 架构风格 RP…...
时间复杂度介绍及其计算
时间复杂度 1.算法效率 如何衡量一个算法的好坏呢?看这段代码: long long Fib(int N) {if(N < 3)return 1;return Fib(N-1) Fib(N-2); }这是斐波那契数列的递归代码,非常简洁,那么这就一定说明它好吗?答案显而易…...
etcd实现大规模服务治理应用实战
导读:服务治理目前越来越被企业建设所重视,特别现在云原生,微服务等各种技术被更多的企业所应用,本文内容是百度小程序团队基于大模型服务治理实战经验的一些总结,同时结合当前较火的分布式开源kv产品etcd,…...
目标检测中 anchor base和anchor free
目标检测中两种不同anchor的生成 趋势:anchor free越来越受到实时性检测的青睐,,,...
TypeC拓展设计方案|TypeC转HDMI设计方案|CS5261/CS5265芯片设计参数对比
集睿智远CS5261/CS5265都可以用于设计TypeC转HDMI方案,低成本TypeC扩展坞设计方案,而两者也有些差异:1.CS5261支持DP1.4输入,一个HDMI1.4输出,即HDMI输出为4K30HZ ;CS5265DP1.4到HDMI2.0转换芯片,即HDMI输出…...
SQL Developer中的Active Data Guard
这篇文章 Display Data Guard configuration in SQL Developer 中,用SQL Developer展示了多种ADG的拓扑。 今天自己也试了一下,还蛮简单的,其实最麻烦的部分在于搭建一个ADG环境。 假设我已有一个ADG环境,即最典型的环境&#x…...
谈谈FFT到底有何用
谈谈FFT到底有何用 FFT快速傅里叶变换是数字信号处理的经典算法,学过DSP或者芯片设计的人大多知道这个算法;但是,大家是否想过,为什么数字信号处理会有那么多FFT呢有人会说,为了分析信号的频谱;那么下边的问题就是,分析频谱对我们的日常需求,比如手机打电话,雷达测量速度和方向…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...
深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
