spring boot导入导出excel,集成EasyExcel
一、安装依赖
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.2.0</version></dependency>
二、新建导出工具类
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.2.0</version></dependency>
三、新建实体类
package com.example.springbootclickhouse.Excel;import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.example.springbootclickhouse.ExcelValidTools.ExcelValid;
import com.example.springbootclickhouse.ExcelValidTools.NumberValid;
import com.example.springbootclickhouse.utils.GenderConverter;
import lombok.*;import java.io.Serializable;
import java.time.LocalDateTime;@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentExcel implements Serializable {private static final long serialVersionUID = 1L;@ExcelProperty("姓名")@ColumnWidth(20)@ExcelValid(message = "姓名列不能有空数据!")private String name;@ExcelProperty("年龄")@ColumnWidth(20)@NumberValid(message = "年龄不得小于0")private Integer age;@ExcelProperty(value = "性别",converter = GenderConverter.class)@ColumnWidth(20)private Integer gender;@ExcelProperty("日期")@ColumnWidth(20)private LocalDateTime date;}
@ExcelProperty: 核心注解,value属性可用来设置表头名称,converter属性可以用来设置类型转换器;
@ColumnWidth: 用于设置表格列的宽度;
@DateTimeFormat: 用于设置日期转换格式;
@NumberFormat: 用于设置数字转换格式。
四、如果需要有字段进行转换的,则为新建转换类,并在实体类上加注解
1、实体类上加如下
@ExcelProperty(value = "性别",converter = GenderConverter.class)
2、新建枚举类
package com.example.springbootclickhouse.ExcelEnum;import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;import java.util.stream.Stream;@AllArgsConstructor
@Getter
public enum GenderEnum {/*** 未知*/UNKNOWN(0, "未知"),/*** 男性*/MALE(1, "男性"),/*** 女性*/FEMALE(2, "女性");private final Integer value;@JsonFormatprivate final String description;public static GenderEnum convert(Integer value) {
// 用于为给定元素创建顺序流
// values:获取枚举类型的对象数组return Stream.of(values()).filter(bean -> bean.value.equals(value)).findAny().orElse(UNKNOWN);}public static GenderEnum convert(String description) {return Stream.of(values()).filter(bean -> bean.description.equals(description)).findAny().orElse(UNKNOWN);}
}
3、新建转换器类
package com.example.springbootclickhouse.utils;import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.ReadConverterContext;
import com.alibaba.excel.converters.WriteConverterContext;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.data.WriteCellData;import com.example.springbootclickhouse.ExcelEnum.GenderEnum;public class GenderConverter implements Converter<Integer> {@Overridepublic Class<?> supportJavaTypeKey() {// 实体类中对象属性类型return Integer.class;}@Overridepublic CellDataTypeEnum supportExcelTypeKey() {// Excel中对应的CellData(单元格数据)属性类型return CellDataTypeEnum.STRING;}/*** 将单元格里的数据转为java对象,也就是女转成2,男转成1,用于导入excel时对性别字段进行转换* */@Overridepublic Integer convertToJavaData(ReadConverterContext<?> context) throws Exception {// 从CellData中读取数据,判断Excel中的值,将其转换为预期的数值return GenderEnum.convert(context.getReadCellData().getStringValue()).getValue();}/*** 将java对象转为单元格数据,也就是2转成女,1转成男,用于导出excel时对性别字段进行转换* */@Overridepublic WriteCellData<?> convertToExcelData(WriteConverterContext<Integer> context) throws Exception {// 判断实体类中获取的值,转换为Excel预期的值,并封装为CellData对象return new WriteCellData<>(GenderEnum.convert(context.getValue()).getDescription());}
}
五、导入时,数据进行验证的话
1、新建注解
package com.example.springbootclickhouse.ExcelValidTools;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelValid {String message() default "导入有未填入的字段";
}
2、新建验证类
package com.example.springbootclickhouse.ExcelValidTools;import java.lang.reflect.Field;
import java.util.Objects;public class ExcelImportValid {/*** Excel导入字段校验* @param object 校验的JavaBean 其属性须有自定义注解*/public static void valid(Object object,Integer rowIndex) throws Exception {Field[] fields = object.getClass().getDeclaredFields();for (Field field : fields) {//设置可访问field.setAccessible(true);//属性的值Object fieldValue = null;try {fieldValue = field.get(object);} catch (IllegalAccessException e) {throw new Exception("第" + rowIndex + "行" + field.getAnnotation(ExcelValid.class).message(),e);}//是否包含必填校验注解boolean isExcelValid = field.isAnnotationPresent(ExcelValid.class);if (isExcelValid && Objects.isNull(fieldValue)) {throw new Exception("excel中第" + rowIndex + "行的" + field.getAnnotation(ExcelValid.class).message());}else if(isExcelValid && !(fieldValue instanceof Integer)){throw new Exception("excel中第" + rowIndex + "行的类型不正确" + field.getAnnotation(ExcelValid.class).message());}}}public static void validNumber(Object object,Integer rowIndex) throws Exception {Field[] fields = object.getClass().getDeclaredFields();for (Field field : fields) {//设置可访问field.setAccessible(true);//属性的值Object fieldValue = null;try {fieldValue = field.get(object);} catch (IllegalAccessException e) {throw new Exception("第" + rowIndex + "行" + field.getAnnotation(NumberValid.class).message(),e);}//是否包含必填校验注解boolean isExcelValid = field.isAnnotationPresent(NumberValid.class);if (isExcelValid && (Integer)fieldValue<=0) {throw new Exception("excel中第" + rowIndex + "行的" + field.getAnnotation(NumberValid.class).message());}}}
}
3、新建监听器类
package com.example.springbootclickhouse.ExcelValidTools;import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.example.springbootclickhouse.Excel.StudentExcel;
import lombok.Getter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;import static com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlFormatName.JSON;@Slf4j
public class StudentListener extends AnalysisEventListener<StudentExcel> {private static final int BATCH_COUNT = 500;@GetterList<StudentExcel> list=new ArrayList<>(BATCH_COUNT);@Override@SneakyThrowspublic void invoke(StudentExcel studentExcel, AnalysisContext analysisContext) {log.info("数据校验:"+studentExcel);ExcelImportValid.valid(studentExcel,analysisContext.readRowHolder().getRowIndex()+1);ExcelImportValid.validNumber(studentExcel,analysisContext.readRowHolder().getRowIndex()+1);//可不用
// list.add(studentExcel);
// if (list.size() >= BATCH_COUNT) {
// log.info("已经解析"+list.size()+"条数据");
// list.clear();
// }}@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {}}
4、在实体类上使用注解@ExcelValid(message = “姓名列不能有空数据!”),同时在导入时新增
.registerReadListener(new StudentListener())
五、如果要求导出的excel加下拉选项框的话
1、新建导出处理类
package com.example.springbootclickhouse.ExcelHandler;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class CustomSheetWriteHandler implements SheetWriteHandler {/*** 想实现Excel引用其他sheet页数据作为单元格下拉选项值,* 需要重写该方法** @param writeWorkbookHolder* @param writeSheetHolder*/@Overridepublic void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {// 构造样例数据,该数据可根据实际需要,换成业务数据// 实际数据可通过构造方法,get、set方法等由外界传入List<String> selectDataList = new ArrayList<>();for (int i = 0; i < 100; i++) {selectDataList.add("下拉选项" + i);}// 构造下拉选项单元格列的位置,以及下拉选项可选参数值的map集合// key:下拉选项要放到哪个单元格,比如A列的单元格那就是0,C列的单元格,那就是2// value:key对应的那个单元格下拉列表里的数据项,比如这里就是下拉选项1..100Map<Integer, List<String>> selectParamMap = new HashMap<>();selectParamMap.put(0, selectDataList);// 获取第一个sheet页Sheet sheet = writeSheetHolder.getCachedSheet();// 获取sheet页的数据校验对象DataValidationHelper helper = sheet.getDataValidationHelper();// 获取工作簿对象,用于创建存放下拉数据的字典sheet数据页Workbook workbook = writeWorkbookHolder.getWorkbook();// 迭代索引,用于存放下拉数据的字典sheet数据页命名int index = 1;for (Map.Entry<Integer, List<String>> entry : selectParamMap.entrySet()) {// 设置存放下拉数据的字典sheet,并把这些sheet隐藏掉,这样用户交互更友好String dictSheetName = "dict_hide_sheet" + index;Sheet dictSheet = workbook.createSheet(dictSheetName);// 隐藏字典sheet页workbook.setSheetHidden(index++, true);// 设置下拉列表覆盖的行数,从第一行开始到最后一行,这里注意,Excel行的// 索引是从0开始的,我这边第0行是标题行,第1行开始时数据化,可根据实// 际业务设置真正的数据开始行,如果要设置到最后一行,那么一定注意,// 最后一行的行索引是1048575,千万别写成1048576,不然会导致下拉列表// 失效,出不来CellRangeAddressList infoList = new CellRangeAddressList(1, 1048575, entry.getKey(), entry.getKey());int rowLen = entry.getValue().size();for (int i = 0; i < rowLen; i++) {// 向字典sheet写数据,从第一行开始写,此处可根据自己业务需要,自定// 义从第几行还是写,写的时候注意一下行索引是从0开始的即可dictSheet.createRow(i).createCell(0).setCellValue(entry.getValue().get(i));}// 设置关联数据公式,这个格式跟Excel设置有效性数据的表达式是一样的String refers = dictSheetName + "!$A$1:$A$" + entry.getValue().size();Name name = workbook.createName();name.setNameName(dictSheetName);// 将关联公式和sheet页做关联name.setRefersToFormula(refers);// 将上面设置好的下拉列表字典sheet页和目标sheet关联起来DataValidationConstraint constraint = helper.createFormulaListConstraint(dictSheetName);DataValidation dataValidation = helper.createValidation(constraint, infoList);sheet.addValidationData(dataValidation);}}
}
2、在导出代码注册
EasyExcel.write(response.getOutputStream()).registerWriteHandler(new CustomSheetWriteHandler()).head(StudentExcel.class).sheet("sheet1").doWrite(userList);
相关文章:
spring boot导入导出excel,集成EasyExcel
一、安装依赖 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.2.0</version></dependency>二、新建导出工具类 <dependency><groupId>com.alibaba</groupId>&…...
【错误解决方案】ModuleNotFoundError: No module named ‘zarr‘
1. 错误提示 在python程序,尝试导入一个名为zarr的模块,但Python提示找不到这个模块。 错误提示:ModuleNotFoundError: No module named ‘zarr‘ 2. 解决方案 这可能是因为你尚未安装这个模块或者安装过程中出现了问题。 zarr是一个用于存…...
什么是集成测试?
什么是集成测试 集成测试(Integration Testing),也叫组装测试或联合测试。在单元测试的基础上,将所有模块按照设计要求(如根据结构图)组装成为子系统或系统,进行集成测试。 集成测试ÿ…...
Linux———— 运算命令
Shell与其他编程语言一样,支持多种类型的运算符,包括: 算术运算符:用于执行数学运算,例如加法、减法、乘法和除法。 关系运算符:用于比较两个值之间的关系,例如相等、大于、小于等。 布尔运算…...
批量去除pdf每一页相同未知的同样的内容
例如我想去除每一页右下角的www.alevelcollege.com ①打开acrobat pro ②编辑文件和图像 ③ctrlF输入字符串www.alevelcollege.com替换为空 ④鼠标点击替换 ⑤回车键按下不放,会自动翻页,直到翻页到最后一页。...
HCIA数据通信——静态路由
之前的文章中我提到过静态路由: 数据通信——网络层(路由器以及数据转发流程)_路由器如何转发数据_咕噜跳的博客-CSDN博客这里只做一些简单描述。 路由器关注的是网络之间的通信。路由器以自身为中心,考虑的是如何将数据发送到目…...
Fourier分析导论——第2章——Fourier级数的基本属性(E.M. Stein R. Shakarchi)
第 2 章 Fourier级数的基本属性(Basic Properties of Fourier Series) Nearly fifty years had passed without any progress on the question of analytic representation of an arbitrary function, when an assertion of Fourier threw new light on the subject. Thus…...
redis实现分布式延时队列
文章目录 延时队列简介应用场景案例:考虑:实现:整体思路:具体实现生产者消费者 运行结果 redis分布式延时队列优势redis分布式延时队列劣势 延时队列简介 延时队列是一种特殊的消息队列,它允许将消息在一定的延迟时间…...
Spring AOP源码解读
今天我们来分析Spring中AOP的源码,主要是关于SpringAOP是如何发挥作用的。 前期准备 首先我们需要有一个Spring AOP项目,添加好了SpringAOP的依赖。 <dependency><groupId>org.springframework</groupId><artifactId>spring-co…...
JavaScript基础入门01
目录 1.初识 JavaScript 1.1JavaScript 是什么 1.2发展历史 1.3JavaScript 和 HTML 和 CSS 之间的关系 2.JavaScript 的组成 3.前置知识 3.1第一个程序 4.JavaScript 的书写形式 4.1 行内式 4.2. 内嵌式 4.3.外部式 5.注释 6.输入输出 6.1输入: prompt 6.2输出: …...
yum 命令
基本语法 yum [选项] [参数] 选项说明 -y 对所有提问都回答“yes” 参数说明 实操 yum list | grep firefox yum -y remove firefox yum -y install firefox...
Nginx 部署多个安全域名,多个服务【工作记录】
以下是本人通过Docker 部署的Nginx挂载出来的文件目录 先看下 nginx.conf 配置文件内容:如下 ps:当前文件就是安装后的初始内容,无修改。主要关注最后一行 include /etc/nginx/conf.d/*.conf;表示引入其他目录下的.conf配置文件;…...
性能测试QPS+TPS+事务基础知识分析
本篇文章是性能测试基础篇,主要介绍了性能测试中对QPSTPS事务的基础知识分析,有需要的朋友可以借鉴参考下,希望可以对广大读者有所帮助 事务 就是用户某一步或几步操作的集合。不过,我们要保证它有一个完整意义。比如用户对某一…...
PSP - 蛋白质复合物 AlphaFold2 Multimer MSA Pairing 逻辑与优化
欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/134144591 在蛋白质复合物结构预测中,当序列 (Sequence) 是异源多链时,无论是AB,还是AABB,都需要 …...
C++中vec.size()-1的坑
问题描述:如下代码, #include <iostream> #include <vector>using namespace std;int main() {vector<int> vec {};for (int i 0; i < vec.size() - 1; i) {cout << "i " << i << ", vec[i] …...
Flask Shell 操作 SQLite
一、前言 这段时间在玩Flask Web,发现用Flask Shell去操作SQLite还是比较方便的。今天简单地介绍一下。 二、SQLite SQLite是一种嵌入式数据库,它的数据库就是一个文件,处理速度快,经常被集成在各种应用程序中,在IO…...
Mybatis—XML配置文件、动态SQL
学习完Mybatis的基本操作之后,继续学习Mybatis—XML配置文件、动态SQL。 目录 Mybatis的XML配置文件XML配置文件规范XML配置文件实现MybatisX的使用 Mybatis动态SQL动态SQL-if条件查询 \<if\>与\<where\>更新员工 \<set\>小结 动态SQL-\<forea…...
excel求差公式怎么使用?
利用excel求差,可能有许多的小伙伴已经会了,不过还是存在一些不太熟悉的朋友们,所以这里有必要讲解一下。其实求差的实现主要就是一个公式,就是用一个单元格中的数字“减去”另一个单元格中的数字“等于”第三个单元格。此公式掌握…...
高效分割分段视频:提升您的视频剪辑能力
在数字媒体时代,视频剪辑已经成为一项重要的技能。无论是制作个人影片、广告还是其他类型的视频内容,掌握高效的视频剪辑技巧都是必不可少的。本文将介绍如何引用云炫AI智剪高效地分割和分段视频,以提升您的视频剪辑能力。以下是详细的操作步…...
【c++|opencv】二、灰度变换和空间滤波---2.直方图和均衡化
every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 图像直方图、直方图均衡化 1. 图像直方图 #include <iostream> #include <opencv2/opencv.hpp>using namespace cv; using namespace std;…...
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...
热烈祝贺埃文科技正式加入可信数据空间发展联盟
2025年4月29日,在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上,可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞,强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...
java高级——高阶函数、如何定义一个函数式接口类似stream流的filter
java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用(Math::max) 2 函数接口…...
【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)
旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据!该数据集源自2025年4月发表于《地理学报》的论文成果…...
