当前位置: 首页 > article >正文

Spring项目中使用EasyExcel实现Excel 多 Sheet 导入导出功能(完整版)


Excel 多 Sheet 导入导出功能完整实现指南


一、环境依赖
1. Maven 依赖
<!-- EasyExcel -->
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.3.2</version>
</dependency><!-- Spring Boot Web -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>

二、核心工具类封装
1. Excel 导出工具类
public class ExcelExportUtils {/*** 动态导出多 Sheet Excel(无需模板)* @param sheetDataMap key: Sheet名称, value: 数据列表(需保证列表元素类型一致)*/public static void exportDynamicMultiSheet(Map<String, List<Object>> sheetDataMap,String filename,HttpServletResponse response) throws IOException {// 设置响应头response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8"));try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build()) {WriteCellStyle headerStyle = createHeaderStyle();for (Map.Entry<String, List<Object>> entry : sheetDataMap.entrySet()) {String sheetName = entry.getKey();List<Object> dataList = entry.getValue();if (CollectionUtils.isEmpty(dataList)) {throw new IllegalArgumentException("Sheet [" + sheetName + "] 数据不能为空");}Class<?> dtoClass = dataList.get(0).getClass();WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).head(dtoClass).headStyle(headerStyle).build();excelWriter.write(dataList, writeSheet);}}}private static WriteCellStyle createHeaderStyle() {WriteCellStyle style = new WriteCellStyle();style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());style.setHorizontalAlignment(HorizontalAlignment.CENTER);WriteFont font = new WriteFont();font.setBold(true);font.setFontHeightInPoints((short) 12);style.setWriteFont(font);return style;}
}
2. Excel 导入工具类
public class ExcelImportUtils {/*** 导入多 Sheet Excel* @param file      上传的文件* @param sheetMap  key: Sheet名称, value: 该Sheet对应的DTO类*/public static Map<String, List<?>> importMultiSheet(MultipartFile file,Map<String, Class<?>> sheetMap) throws IOException {Map<String, List<?>> resultMap = new LinkedHashMap<>();try (ExcelReader excelReader = EasyExcel.read(file.getInputStream()).build()) {for (Map.Entry<String, Class<?>> entry : sheetMap.entrySet()) {String sheetName = entry.getKey();Class<?> dtoClass = entry.getValue();GenericSheetListener<Object> listener = new GenericSheetListener<>();ReadSheet readSheet = EasyExcel.readSheet(sheetName).head(dtoClass).registerReadListener(listener).build();excelReader.read(readSheet);resultMap.put(sheetName, listener.getDataList());}}return resultMap;}/** 通用数据监听器 */private static class GenericSheetListener<T> implements ReadListener<T> {private final List<T> dataList = new ArrayList<>();@Overridepublic void invoke(T data, AnalysisContext context) {dataList.add(data);}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 可添加日志或后处理逻辑}public List<T> getDataList() {return dataList;}}
}

三、DTO 类定义
1. 用户信息 DTO(对应 Sheet1)
public class UserDTO {@ExcelProperty(value = "姓名", index = 0)private String name;@ExcelProperty(value = "年龄", index = 1)private Integer age;// 必须有无参构造方法public UserDTO() {}// Getters & Setters
}
2. 产品信息 DTO(对应 Sheet2)
public class ProductDTO {@ExcelProperty(value = "产品ID", index = 0)private Long id;@ExcelProperty(value = "产品名称", index = 1)private String name;// 必须有无参构造方法public ProductDTO() {}// Getters & Setters
}

四、Service 层实现
@Service
public class ExcelService {/*** 导出 Excel*/public void exportExcel(HttpServletResponse response) {Map<String, List<Object>> sheetDataMap = new LinkedHashMap<>();// Sheet1: 用户数据List<Object> users = Arrays.asList(new UserDTO("张三", 25),new UserDTO("李四", 30));sheetDataMap.put("用户信息", users);// Sheet2: 产品数据List<Object> products = Arrays.asList(new ProductDTO(1L, "笔记本电脑"),new ProductDTO(2L, "智能手机"));sheetDataMap.put("产品信息", products);// 调用工具类ExcelExportUtils.exportDynamicMultiSheet(sheetDataMap, "export_data.xlsx", response);}/*** 导入 Excel*/public void importExcel(MultipartFile file) {// 定义 Sheet 映射关系Map<String, Class<?>> sheetMap = new LinkedHashMap<>();sheetMap.put("用户信息", UserDTO.class);sheetMap.put("产品信息", ProductDTO.class);// 解析数据Map<String, List<?>> dataMap = ExcelImportUtils.importMultiSheet(file, sheetMap);// 处理业务逻辑List<UserDTO> users = (List<UserDTO>) dataMap.get("用户信息");List<ProductDTO> products = (List<ProductDTO>) dataMap.get("产品信息");// 保存到数据库...}
}

五、Controller 层实现
@RestController
@RequestMapping("/api/excel")
public class ExcelController {@Autowiredprivate ExcelService excelService;/*** 导出 Excel*/@GetMapping("/export")public void exportExcel(HttpServletResponse response) {excelService.exportExcel(response);}/*** 导入 Excel*/@PostMapping("/import")public ResponseEntity<String> importExcel(@RequestParam("file") MultipartFile file) {try {excelService.importExcel(file);return ResponseEntity.ok("文件导入成功");} catch (Exception e) {return ResponseEntity.status(500).body("导入失败: " + e.getMessage());}}
}

六、关键概念解释
1. 监听器(ReadListener
  • 作用
    在 Excel 导入过程中,逐行读取数据并处理,避免一次性加载全量数据到内存。
  • 核心方法
    • invoke(T data, AnalysisContext context):每读取一行数据时触发。
    • doAfterAllAnalysed(AnalysisContext context):当前 Sheet 解析完成后触发。
  • 使用场景
    • 数据收集(存储到 List)。
    • 数据校验(如字段非空检查)。
    • 批量插入数据库(累积一定数量后批量操作)。
2. @ExcelProperty 注解
  • 功能:定义 Java 字段与 Excel 列的映射关系。
  • 参数
    • value:对应 Excel 列名。
    • index:指定列位置(从 0 开始)。
  • 示例
    @ExcelProperty(value = "姓名", index = 0)
    private String name;
    
3. 样式配置(WriteCellStyle
  • 用途:控制单元格样式(如字体、颜色、对齐方式)。
  • 常用配置项
    • setFillForegroundColor: 背景色。
    • setHorizontalAlignment: 水平对齐。
    • setWriteFont: 字体配置(加粗、字号)。

七、常见问题
1. 类型转换异常
  • 表现ClassCastException
  • 原因:DTO 类字段类型与 Excel 单元格数据类型不匹配。
  • 解决:使用 @DateTimeFormat 或自定义转换器。
2. 表头不匹配
  • 表现:数据未正确映射到字段。
  • 原因@ExcelPropertyvalueindex 配置错误。
  • 解决:检查 DTO 类注解与 Excel 列名是否一致。
3. 内存溢出
  • 表现:大文件解析时内存占用过高。
  • 解决:确保使用监听器模式,避免一次性加载全部数据。

八、扩展功能
1. 自定义数据转换器
public class CustomConverter implements Converter<LocalDate> {@Overridepublic LocalDate convertToJavaData(ReadConverterContext<?> context) {return LocalDate.parse(context.getReadCellData().getStringValue(), DateTimeFormatter.ISO_DATE);}
}// 注册转换器
EasyExcel.read(inputStream).registerConverter(new CustomConverter()).build();
2. 复杂表头合并
WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1").head(Collections.singletonList(Arrays.asList("主标题", "子标题1", "子标题2"))).build();

九、总结

通过本方案可实现:

  • 动态导出:无需模板,根据 DTO 类自动生成表头。
  • 高效导入:逐行解析,内存占用低。
  • 类型安全:通过泛型和注解保证数据一致性。
  • 灵活扩展:支持自定义样式、转换器、校验逻辑。

相关文章:

Spring项目中使用EasyExcel实现Excel 多 Sheet 导入导出功能(完整版)

Excel 多 Sheet 导入导出功能完整实现指南 一、环境依赖 1. Maven 依赖 <!-- EasyExcel --> <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.3.2</version> </dependency>…...

OkHttp的拦截器是如何工作的?

OkHttp 的拦截器是其核心特性之一,它允许开发者在请求和响应的处理过程中插入自定义逻辑。下面为你详细介绍 OkHttp 拦截器的工作原理、分类及执行流程。 拦截器工作原理概述 OkHttp 中的拦截器本质上是实现了Interceptor接口的类。该接口定义了一个intercept方法,在这个方…...

CentOS 7 安装 EMQX (MQTT)

CentOS 7 安装 EMQX 通过 Yum 源安装 EMQX 支持通过 Yum 源安装&#xff0c;您可通过以下 Yum 命令从中自动下载和安装 EMQX。 通过以下命令配置 EMQX Yum 源&#xff1a; curl -s https://assets.emqx.com/scripts/install-emqx-rpm.sh | sudo bash安装以下依赖项&#xff…...

重试机制之指针退避策略算法

一、目的&#xff1a;随着重试次数增加&#xff0c;逐步延长重连等待时间&#xff0c;避免加重服务器负担。 二、计算公式&#xff1a; 每次重试的延迟时间 初始间隔 (退避基数 ^ 重试次数) 通常设置上限防止等待时间过长。 const delay Math.min(initialDelay * Math.pow…...

spring security的过滤器链

Spring Security 的安全功能通过一系列过滤器&#xff08;Filter&#xff09;组成的链式结构实现&#xff0c;每个过滤器负责处理特定的安全任务。这些过滤器按特定顺序执行&#xff0c;形成过滤器链&#xff08;Security Filter Chain&#xff09;。以下是其核心过滤器及工作原…...

人工智能:officeAI软件,如何调整AI对话界面的字体?

1、首先&#xff0c;随便打开一个excel&#xff08;使用wps&#xff09; 依次点击上方的【OfficeAI】—【右侧面板】 2、在弹出的面板中&#xff0c;输入&#xff1a;助手设置 &#xff0c; 然后按【回车】发送出去 3、之后会弹出界面&#xff0c;在【样式设定】中&#xff…...

Qt之共享内存类QSharedMemory的使用及实现原理(全)

目录 1.简介 2.使用 3.实现原理 3.1.Windows内存映射 3.2.POSIX 共享内存 3.3.System V 共享内存 3.4.QSharedMemory的实现原理 4.总结 1.简介 QSharedMemory 是 Qt 框架提供的一个类&#xff0c;用于在不同进程或线程之间实现共享内存的管理。借助共享内存&#xff0c…...

dockerfile构建镜像方式

在 Docker 中&#xff0c;可使用 docker build 命令依据 Dockerfile 构建镜像。下面为你详细介绍构建镜像的具体方式。 基本构建命令 若要构建镜像&#xff0c;需在包含 Dockerfile 的目录下执行 docker build 命令。基本语法如下&#xff1a; bash docker build -t <镜像…...

Problem A: 接口使用

1.题目问题 2.样例 3.代码实现 补充&#xff1a;注意空格 // 定义Vehicle接口 interface Vehicle {void start();void stop(); }// 实现Vehicle接口的Bike类 class Bike implements Vehicle {Overridepublic void start() {System.out.println("i am bike,i am running&…...

用Python插入Excel表格到Word文档

在日常办公场景中&#xff0c;通过Python脚本自动化整合Excel数据与Word文档&#xff0c;能够实现表格的智能迁移&#xff0c;满足不同场景下数据呈现的专业性要求。直接提取表格内容插入Word适用于需要快速传递核心数据的场景&#xff0c;确保信息精准直达&#xff1b;完整复制…...

合合信息TextIn大模型加速器 2.0来了:智能文档解析和图表解析能力全面升级

合合信息“TextIn大模型加速器 2.0”版本来了&#xff1a;文档解析和图表解析能力全面升级 背景 在日常工作中&#xff0c;我们常常遇到无法直接复制的文档内容或图片内容&#xff0c;这些内容通常需要进行识别和解析。一个典型的例子是&#xff0c;当我们需要将折线图转化为…...

笔记:代码随想录算法训练营day62:108.冗余连接、109.冗余连接II

学习资料&#xff1a;代码随想录 108. 冗余连接 卡码网题目链接&#xff08;ACM模式&#xff09; 判断是否有环的依据为&#xff0c;利用并查集&#xff0c;isSame函数&#xff0c;判断当下这条边的两个节点入集前是否为同根&#xff0c;如果是的话&#xff0c;该边就是会构…...

刚刚整理实测可用的股票数据API接口集合推荐:同花顺、雅虎API、智兔数服、聚合数据等Python量化分析各项数据全面丰富

在金融科技高速发展的今天&#xff0c;股票API接口已成为开发者、量化交易者和金融从业者的核心工具之一。它通过标准化的数据接口&#xff0c;帮助用户快速获取实时或历史市场数据&#xff0c;为投资决策、策略回测和金融应用开发提供支持。本文将深入解析股票API的核心功能、…...

消息队列Message Queue

前面&#xff0c;我们在黑点点评中秒杀场景中&#xff0c;首次了解到消息队列MQ&#xff0c;它主要解决了秒杀场景中异步场景&#xff0c;提升了并发性&#xff0c;吞吐量。可是还是对消息队列又很多的疑惑&#xff1f; 消息队列是什么 消息队列是一种通信协议或中间件&#…...

Day 25:股票的最大利润 + 1到n求和

数组 prices 记录了某芯片近期的交易价格&#xff0c;其中 prices[i] 表示的 i 天该芯片的价格。你只能选择 某一天 买入芯片&#xff0c;并选择在 未来的某一个不同的日子 卖出该芯片。请设计一个算法计算并返回你从这笔交易中能获取的最大利润。 如果你不能获取任何利润&…...

如何利用AI智能生成PPT提升工作效率

如何利用AI智能生成PPT提升工作效率&#xff1f;PPT制作曾经是每个人办公生活中的一大痛点。你有多久没有在制作PPT时感到焦头烂额&#xff0c;选模板、调整格式、插入图片&#xff0c;每一项都得花费大量的时间和精力&#xff0c;最后还未必能做出一份令人满意的效果。随着人工…...

WIN11 企业版 部署Dify+Docker

Dify&#xff08;Do it for you&#xff09;是一款开源的大语言模型应用开发平台&#xff0c;旨在简化AI应用的创建、部署和管理过程&#xff0c;使开发者能够更快速、更轻松地构建和运营基于GPT等模型的AI应用。 Dify平台创建和运营一个AI chatbot应用&#xff0c;涉及到登录…...

理解CMakeLists.txt文件

CMakeLists.txt(主入口) │ ├── 项目元信息(project, cmake_minimum_required) ├── 编译选项设置(option) ├── 编译标志设置(set(CMAKE_...)) ├── 查找依赖库(find_package, include_directories) ├── 注册插件、扩展(register_extension, add_subdi…...

1.25-20GHz/500ns超快跳频!盛铂SWFA300国产捷变频频率综合器模块赋能雷达/5G/电子战高频精密控制 本振/频综模块

盛铂SWFA300捷变频频率综合器模块简述&#xff1a; 盛铂科技国产SWFA300捷变频频率综合器是一款在频率范围内任意两点频率的跳频时间在500nS以内的高速跳频源&#xff0c;其输出频率范围为1.25GHz至20GHz&#xff0c;频率的最小步进为10kHz。同时它拥有优秀的相位噪声特性&…...

MySql修改全部表和字段编码

修改全部表 SELECT CONCAT(ALTER TABLE , TABLE_NAME, CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;) AS sql_statements FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA 数据库名称 返回的下面这种SQL,然后批量执行即可 ALTER TABLE gen_table CO…...

elementUI el-image图片加载失败解决

是不是&#xff0c;在网上找了一些&#xff0c;都不行&#xff0c;这里一行代码&#xff0c;解决&#xff0c;后端返回图片路径&#xff0c;el-image图片加载失败的问题 解决办法&#xff0c; vue项目里&#xff0c;index.html文件里加一行代码就可 <meta name"refe…...

代理IP协议详解HTTP、HTTPS、SOCKS5分别适用于哪些场景

“代理IP协议在现代网络通信中扮演着至关重要的角色。它们通过提供中间层服务&#xff0c;帮助用户匿名访问网络、绕过地理限制、提高安全性和加速数据传输。HTTP、HTTPS和SOCKS5是三种最常见的代理IP协议&#xff0c;每种协议都有其特定的用途和适用场景。” HTTP代理及其适用…...

UniApp开发多端应用——流式语音交互场景优化

一、问题背景&#xff1a;UniApp默认方案的局限性 在流式语音交互场景&#xff08;如AI语音助手、实时字幕生成&#xff09;中&#xff0c;UniApp默认的uni.getRecorderManager 和uni.createInnerAudioContext 存在以下瓶颈&#xff1a; 录音端&#xff1a; 延迟高&#xff1…...

AIGC工具平台-通用抠图换背景

本模块采用先进的大模型智能算法&#xff0c;精准识别并分割图像中的人物或物品主体&#xff0c;实现高效、精准、智能化的抠图处理。无论是人物肖像、产品展示&#xff0c;还是复杂场景&#xff0c;该工具均能准确提取主体&#xff0c;并自动适配至背景图像&#xff0c;实现自…...

word快速创建虚拟文字

创建虚拟文字的作用&#xff1a;如培训新员工使用 Word&#xff0c;用虚拟文字演示如何设置段落格式。不需要你随便乱敲文字或者去复制一段文字过来。帮你节约了时间&#xff01; 两个函数的使用必须在段落的开头&#xff01;&#xff01;&#xff01; rand函数 在 Word 中…...

win10下python脚本运行缺失ccache的问题处理

问题 python脚本运行时&#xff0c;会提醒参考 https://github.com/ccache/ccache/blob/master/doc/INSTALL.md 处理缺失ccache的问题。 下载编译 下载ccache主干版本&#xff0c; 例如 https://github.com/ccache/ccache/archive/refs/heads/master.zip 按照说明编译 mkd…...

大模型在支气管扩张预测及治疗方案制定中的应用研究

目录 一、引言 1.1 研究背景与意义 1.2 研究目的与方法 1.3 国内外研究现状 二、大模型技术概述 2.1 大模型的基本原理与架构 2.2 适用于支气管扩张预测的大模型类型及特点 2.3 大模型在医疗领域的应用现状与优势 三、支气管扩张的相关医学知识 3.1 支气管扩张的病因…...

开发复合组件TLabel + TwwDBLookupCombo

老鸟跳过。。。。。。。。本文只是为小白准备的 -------------- TwwDBLookupCombo 组件是老牌控件包的 Inofpower 中的一个组件。Inofpower 很久也没有更新了&#xff0c;只是作了新版DELPHI的适配&#xff0c;组件的功能从D2007那些开始到现在&#xff0c;可以说几乎没有任何…...

ch05 课堂参考代码及部分题目思路

ch05 字典树 字典树&#xff08;Trie&#xff09;是一种用于实现字符串快速查找的多叉树结构&#xff0c;查找原理类似于我们在英文词典上查找单词。 字典树用边来代表字母&#xff0c;从根结点到树上某一结点的路径就代表了一个字符串。 字典树的表示 以字符集为小写字母的…...

0328-内存图2

是否正确待定&#xff1a; Perso类 package com.qc.内存图2;public class Perso {public int age;public String name;public static int flag;public void m1() {}public static void m2() {}Overridepublic String toString() {return "Perso [age" age "…...