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 类自动生成表头。
  • 高效导入:逐行解析,内存占用低。
  • 类型安全:通过泛型和注解保证数据一致性。
  • 灵活扩展:支持自定义样式、转换器、校验逻辑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/42735.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++指针(五)完结篇

个人主页&#xff1a;PingdiGuo_guo 收录专栏&#xff1a;C干货专栏 前言 相关文章&#xff1a;C指针&#xff08;一&#xff09;、C指针&#xff08;二&#xff09;、C指针&#xff08;三&#xff09;、C指针&#xff08;四&#xff09;万字图文详解&#xff01; 本篇博客是介…

DataGear 企业版 1.4.0 发布,数据可视化分析平台

DataGear 企业版 1.4.0 已发布&#xff0c;欢迎体验&#xff01; http://datagear.tech/pro/ 企业版 1.4.0 看板可视编辑模式新增了插入看板表单/面板布局、编辑图表联动、复制/粘贴、撤销/恢复等功能&#xff0c;具体更新内容如下&#xff1a; 新增&#xff1a;看板可视编辑…

windows第十八章 菜单、工具栏、状态栏

文章目录 创建框架窗口菜单菜单的风格通过资源创建菜单菜单的各种使用通过代码创建菜单在鼠标位置右键弹出菜单 CMenu常用函数介绍工具栏方式一&#xff0c;从资源创建工具栏方式二&#xff0c;代码创建 状态栏状态栏基础创建状态栏 创建框架窗口 手动创建一个空项目&#xff…

局域网共享失败?打印机/文件夹共享工具

很多时候&#xff0c;在办公或家庭环境中&#xff0c;我们需要进行打印机和文件夹的共享&#xff0c;以便更高效地协作和处理文件。然而&#xff0c;寻找对应版本的共享设置或是不想花费太多时间去进行复杂的电脑设置&#xff0c;总是让人感到头疼。今天&#xff0c;我要向大家…

C++中使用CopyFromRecordset将记录集拷贝到excel中时,如果记录集为0个,函数崩溃,是什么原因

文章目录 原因分析解决方案1. 检查记录集是否为空2. 安全调用COM方法3.进行异常捕获4. 替代方案&#xff1a;手动处理空数据 总结 在C中使用CopyFromRecordset将空记录集&#xff08;0条记录&#xff09;复制到Excel时崩溃的原因及解决方法如下&#xff1a; 原因分析 空记录集…

torchvision中数据集的使用

1、torchvision及其数据集的介绍 1.1 torchvision介绍 torchvision 是 PyTorch 的一个官方库&#xff0c;专门用于计算机视觉任务。它提供了以下核心功能&#xff1a; 预训练模型&#xff1a;如 ResNet、VGG、EfficientNet 等。数据集&#xff1a;内置常用视觉数据集&#xf…

d2025328

一、sql-判断三角形 610. 判断三角形 - 力扣&#xff08;LeetCode&#xff09; 用一下if加上判断条件 select x,y,z,if(xy > z and xz > y and yz > x and x-y < z and x-z < y and y-z < x,Yes,No) as triangle from Triangle 二、按照分类统计薪水 190…

C++20新特性:std::assume_aligned详解

文章目录 一、概述二、函数定义与语法三、使用方法与注意事项1. 使用方法2. 注意事项 四、性能优化原理五、实际应用场景六、编译器支持情况七、总结 一、概述 C20引入了std::assume_aligned&#xff0c;这是一个非常实用的特性&#xff0c;用于告知编译器某个指针所指向的对象…

洛谷P1706 全排列题解

P1706 全排列问题 题目描述 按照字典序输出自然数 1 1 1 到 n n n 所有不重复的排列&#xff0c;即 n n n 的全排列&#xff0c;要求所产生的任一数字序列中不允许出现重复的数字。 输入格式 一个整数 n n n。 输出格式 由 1 ∼ n 1 \sim n 1∼n 组成的所有不重复的…

yum install 报错(CentOS换源):

yum instally yum utils device mapper persistent-data lvm2 报错&#xff1a; 排查错误原因&#xff1a;centos7 系统停止维护了 解决方案&#xff1a;换源&#xff08;更换操作系统&#xff09; //1.备份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-…

C语言学习笔记(抱佛脚版)

毕业一年&#xff0c;发现记性是真的差&#xff0c;每次想起之前的知识总是想不全&#xff0c;看别人写的资料也懵懵懂懂。于是我索性自己再学一遍&#xff0c;并且记录一下。希望对你们也有所帮助。 正片开始&#xff01; 前面的什么if for都不难理解&#xff0c;嵌套的话也…

攻破tensorflow,勇创最佳agent(2)---损失(loss) 准确率(accuracy)问题

实战播: 怎么判定一个模型好不好,你设置的值对不对? 需要再看几个值: 例如: model Sequential()for units in model_structure:model.add(Dense(units, activationrelu))model.add(Dropout(train_config.get(dropout_rate, 0.3)))model.add(Dense(1, activationsigmoid)) 他…

Docker-Volume数据卷详讲

Docker数据卷-Volume 一&#xff1a;Volume是什么&#xff0c;用来做什么的 当删除docker容器时&#xff0c;容器内部的文件就会跟随容器所销毁&#xff0c;在生产环境中我们需要将数据持久化保存&#xff0c;就催生了将容器内部的数据保存在宿主机的需求&#xff0c;volume …

使用Selenium和lxml库搜房网爬取某地区房屋信息(python、pycharm爬虫)

一、地址&#xff1a; url "https://zb.newhouse.fang.com/house/s/b91" # 第一页的 URL 但是这个爬虫我不知道为啥总是翻不了页数&#xff0c;请帮忙修改一下~ 二、用到的知识点以及代码详解&#xff1a; 这段代码是一个使用Selenium和lxml库实现的网页爬虫&a…

ai画图comfyUI 精准定位gligen。允许指定图像中多个对象的位置和大小

基础功能下&#xff0c;outpainting是内容填充&#xff0c;拉近拉远镜头&#xff0c;自动填充旁边物体。嵌入模型也需要单独下载&#xff0c;演示完示例后推荐模型站有更直观效果介绍和用法。选中精确定位。看一眼坐标&#xff0c;直接默认出一张图。然后修改定位&#xff0c;和…

如何自动化同义词并使用我们的 Synonyms API 进行上传

作者&#xff1a;来自 Elastic Andre Luiz 了解如何使用 LLM 来自动识别和生成同义词&#xff0c; 使术语可以通过程序方式加载到 Elasticsearch 同义词 API 中。 提高搜索结果的质量对于提供高效的用户体验至关重要。优化搜索的一种方法是通过同义词自动扩展查询词。这样可以更…

boost.asio

as&#xff08;async&#xff09;:异步 同步io&#xff1a; reactor (非阻塞)&#xff08;需要注册一次&#xff0c;在等待消息时可以干别的事&#xff09; 阻塞io网络模型 接口&#xff1a;read\accept\connect\write 接口返回时&#xff0c;io完成 异步…

数据库后续

-- 添加作者字段 alter table t_hero add author varchar(100); -- 更新数据 update t_hero set author "曹雪芹" where id 1; update t_hero set author "曹雪芹" where id 2; update t_hero set author "曹雪芹" where id 3; upd…

计算机网络基础:网络流量工程与优化策略

计算机网络基础:网络流量工程与优化策略 一、前言二、网络流量工程基础2.1 网络流量工程的定义与目标2.2 网络流量的测量与分析2.2.1 常用的流量测量方法2.2.2 流量数据分析三、网络流量工程的优化策略3.1 链路负载均衡策略3.1.1 基于目的地址的负载均衡3.1.2 基于流量权重的负…

H5DS编辑器教程——H5页面触发动画实战指南

在 H5 页面设计中&#xff0c;触发动画通过动态交互提升用户体验&#xff0c;成为吸引注意力的关键手段。H5DS 编辑器作为一款高效的可视化工具&#xff0c;提供了丰富的动画制作功能&#xff0c;即使是零基础用户也能轻松实现专业级效果。 使用工具&#xff1a;H5DS编辑器 触…