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;…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...
uniapp 小程序 学习(一)
利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 :开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置,将微信开发者工具放入到Hbuilder中, 打开后出现 如下 bug 解…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
Sklearn 机器学习 缺失值处理 获取填充失值的统计值
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 使用 Scikit-learn 处理缺失值并提取填充统计信息的完整指南 在机器学习项目中,数据清…...
跨平台商品数据接口的标准化与规范化发展路径:淘宝京东拼多多的最新实践
在电商行业蓬勃发展的当下,多平台运营已成为众多商家的必然选择。然而,不同电商平台在商品数据接口方面存在差异,导致商家在跨平台运营时面临诸多挑战,如数据对接困难、运营效率低下、用户体验不一致等。跨平台商品数据接口的标准…...
