EasyExcel导出导入excel工具类
接上一篇EasyExcel导出导入excel的文章,附上一份完整的工具类代码。对于字体颜色名称,请参考这篇文章。
POI字体颜色
小技巧
- 类转换用属性拷贝
- 不同类如果有相同属性,则使用反射验证,减少代码量
private List<Person> validateAndSetTypeThenReturn(List<Long> list, List<?> objects, String key) {Consumer<Object> validator = item -> {try {Method setType = item.getClass().getMethod("setType", String.class);Method getId = item.getClass().getMethod("getId");// 设置类型setType.invoke(item, key);// 校验ID必填if (!list.contains((Long) getId.invoke(item))) {throw new ServiceException("无效的ID" + getId.invoke(item));}} catch (ServiceException ex) {throw new ServiceException(ex.getMessage());} catch (Exception e) {throw new ServiceException("数据验证失败");}};objects.forEach(validator);return BeanUtil.copyToList(objects, Person.class);}
- 遍历List不如遍历枚举
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.handler.WorkbookWriteHandler;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.yfld.common.core.convert.ExcelBigNumberConvert;
import com.yfld.common.core.exception.ServiceException;
import lombok.Data;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;/*** @ClassName : ExcelUtilAdvance* @Description : excel高级工具*/
@Slf4j
public class ExcelUtilAdvance {/*** 导出多 Sheet 版本的 Excel 文件(动态生成,无需模板)** @param sheetDataMap Sheet 数据映射,key 为 Sheet 名称,value 为数据列表(列表元素需为同一 DTO 类型)* @param filename 导出的 Excel 文件名* @param response HttpServletResponse* @throws IOException 文件操作异常*/public static void exportDynamicMultiSheet(LinkedHashMap<String, List<?>> sheetDataMap, String filename, HttpServletResponse response) {try {// 1. 设置 HTTP 响应头(文件类型和编码)setResponse(filename, response);// 2. 创建写入处理器-指定样式HorizontalCellStyleStrategy styleStrategy = new HorizontalCellStyleStrategy(createHeaderStyle(), createContentStyle());// 3. 创建 ExcelWriter 对象(自动关闭流)try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).autoCloseStream(true).registerConverter(new ExcelBigNumberConvert()).registerWriteHandler(styleStrategy) // 样式处理器.registerWriteHandler(new AutoColumnWidthStyleStrategy()) // 自动列宽适配.registerWriteHandler(new ZoomScaleHandler(150)) // 缩放比例
// .registerWriteHandler(new FirstRedStarHeaderHandler()) // 表头着色器,将*号标记为红色.build()) {// 4. 遍历所有 Sheet 数据for (Map.Entry<String, List<?>> entry : sheetDataMap.entrySet()) {String sheetName = entry.getKey();List<?> dataList = entry.getValue();// 4.1 动态推断 DTO 类型(通过列表第一个元素)if (CollUtil.isEmpty(dataList)) {throw new IllegalArgumentException("Sheet [" + sheetName + "] 数据列表不能为空");}Class<?> dtoClass = dataList.get(0).getClass();// 4.2 创建 WriteSheet(动态绑定表头和样式)WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).head(dtoClass) // 根据 DTO 类自动生成表头.needHead(Boolean.TRUE) // 强制生成表头.build();// 4.3 写入数据(自动跳过空列表)excelWriter.write(dataList, writeSheet);}}} catch (IOException e) {throw new ServiceException("导出 Excel 失败:" + e.getMessage(), e);}}/*** 导入多 Sheet 版本的 Excel 文件,自动将每个 Sheet 映射到指定实体类** @param file 上传的 Excel 文件* @param sheetNameMap Sheet 配置信息,key 为 Sheet 名称,value 为对应实体类的 Class 对象* @return 解析后的数据 Map,key 为 Sheet 名称,value 为对应实体对象列表*/public static Map<String, List<?>> importDynamicMultiSheet(MultipartFile file, Map<String, Class<?>> sheetNameMap) {try {// 1. 创建 ExcelReader 对象(自动关闭流)try (ExcelReader excelReader = EasyExcel.read(file.getInputStream()).registerConverter(new ExcelBigNumberConvert()).autoCloseStream(true) // 确保流自动关闭.build()) {// 2. 初始化数据容器,存储每个 Sheet 的解析结果Map<String, List<?>> dataMap = new LinkedHashMap<>(); // 保持插入顺序// 3. 遍历 Sheet 配置信息for (Map.Entry<String, Class<?>> entry : sheetNameMap.entrySet()) {String sheetName = entry.getKey();Class<?> clazz = entry.getValue();// 4. 创建数据监听器(泛型安全)GenericSheetListener<Object> listener = new GenericSheetListener<>();// 5. 构建 ReadSheet(指定 Sheet 名称和表头类)ReadSheet readSheet = EasyExcel.readSheet(sheetName).head(clazz).registerReadListener(listener).headRowNumber(1) // 表头行数.build();try {// 6. 读取当前 Sheet 数据excelReader.read(readSheet);} catch (Exception e) {throw new RuntimeException("解析 Sheet [" + sheetName + "] 失败: " + e.getMessage(), e);}// 7. 将解析结果存入 Map(类型安全转换)dataMap.put(sheetName, convertToTypedList(listener.getDataList(), clazz));}return dataMap;}} catch (Exception e) {throw new RuntimeException("导入 Excel 失败:" + e.getMessage(), e);}}private static <T> List<T> convertToTypedList(List<Object> dataList, Class<T> clazz) {return dataList.stream().map(clazz::cast).collect(Collectors.toList());}/*** 创建统一的表头样式(灰色背景、居中、加粗)** @return WriteCellStyle*/private static WriteCellStyle createHeaderStyle() {WriteCellStyle style = new WriteCellStyle();// 表头背景色-青绿色style.setFillForegroundColor(IndexedColors.AQUA.getIndex());style.setWrapped(false);// 水平剧中style.setHorizontalAlignment(HorizontalAlignment.CENTER);// 自动调整列宽// 字体WriteFont font = new WriteFont();font.setBold(true);font.setFontName("宋体");font.setFontHeightInPoints((short) 11);
// font.setColor(IndexedColors.BLACK.getIndex());style.setWriteFont(font);return style;}/*** 创建内容样式(中对齐、黑色字体)*/private static WriteCellStyle createContentStyle() {WriteCellStyle style = new WriteCellStyle();style.setHorizontalAlignment(HorizontalAlignment.CENTER);WriteFont font = new WriteFont();font.setFontName("宋体");font.setFontHeightInPoints((short) 10);style.setWriteFont(font);return style;}private static void setResponse(String filename, HttpServletResponse response) throws UnsupportedEncodingException {// 设置响应头-excel文件类型和文件名response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8"));}/*** 通用 Sheet 数据监听器(泛型类)** @param <T> 实体类型*/@Getterprivate static class GenericSheetListener<T> implements ReadListener<T> {private final List<T> dataList = new ArrayList<>();@Overridepublic void invoke(T data, AnalysisContext context) {if (StrUtil.isEmpty(data.toString())) {throw new ExcelAnalysisException("第 " + context.readRowHolder().getRowIndex() + " 行数据错误:不能为空");}dataList.add(data); // 收集每行数据}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 可在此添加后处理逻辑(如校验、日志)log.info("解析完成,共处理 {} 行数据", dataList.size());}}/*** 自动调整列宽,用于在写入完成后动态设置列宽*/public static class AutoColumnWidthStyleStrategy implements WorkbookWriteHandler {@Overridepublic void afterWorkbookDispose(WriteWorkbookHolder writeWorkbookHolder) {SXSSFWorkbook workbook = (SXSSFWorkbook) writeWorkbookHolder.getWorkbook();// 遍历所有Sheetfor (int i = 0; i < workbook.getNumberOfSheets(); i++) {SXSSFSheet sheet = workbook.getSheetAt(i);adjustColumnWidth(sheet);}}private void adjustColumnWidth(SXSSFSheet sheet) {sheet.trackAllColumnsForAutoSizing();// 获取第一行(表头)Row headerRow = sheet.getRow(0);if (headerRow == null) {log.error("表头行不存在,无法调整列宽");return;}int columnCount = headerRow.getLastCellNum();for (int i = 0; i < columnCount; i++) {// 自动调整列宽sheet.autoSizeColumn(i);// 解决自动设置列宽中文失效的问题
// sheet.setColumnWidth(i, sheet.getColumnWidth(i) * 17 / 10);// 设置列宽范围(示例:10到50字符)int currentWidth = sheet.getColumnWidth(i);int minWidth = 10 * 256; // 10字符int maxWidth = 50 * 256; // 50字符if (currentWidth < minWidth) {sheet.setColumnWidth(i, minWidth);} else if (currentWidth > maxWidth) {sheet.setColumnWidth(i, maxWidth);}}}}/*** 自定义缩放比例处理器,用于在写入完成后设置 Sheet 的显示比例*/@Datapublic static class ZoomScaleHandler implements SheetWriteHandler {private final int zoomScale; // 缩放比例(如 150 表示 150%)@Overridepublic void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {Sheet sheet = writeSheetHolder.getSheet();// 设置缩放比例(POI 的 setZoom 方法直接接受百分比值)sheet.setZoom(zoomScale); // 例如 150 表示 150%}}/*** 表头着色器*/public static class FirstRedStarHeaderHandler implements CellWriteHandler {@Overridepublic void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList,Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {if (isHead && cell.getRow().getRowNum() == 0) { // 仅处理第一行表头// 1. 检查单元格类型和内容if (cell.getCellType() != CellType.STRING || cell.getStringCellValue() == null) {return;}String cellValue = cell.getStringCellValue();if (!cellValue.startsWith("*")) {return;}// 2. 获取工作簿和原始样式Workbook workbook = cell.getSheet().getWorkbook();CellStyle originalStyle = cell.getCellStyle();// 3. 创建红色字体(继承默认属性)Font defaultFont = workbook.getFontAt(originalStyle.getFontIndexAsInt());Font redFont = workbook.createFont();redFont.setFontName(defaultFont.getFontName());redFont.setFontHeightInPoints(defaultFont.getFontHeightInPoints());redFont.setBold(defaultFont.getBold());redFont.setColor(IndexedColors.RED.getIndex()); // 红色// 4. 构建富文本XSSFRichTextString richText = new XSSFRichTextString(cellValue);richText.applyFont(0, 1, redFont); // 第一个字符(*)为红色if (cellValue.length() > 1) {// 剩余字符保留默认样式richText.applyFont(1, cellValue.length(), defaultFont);}// 5. 应用富文本到单元格cell.setCellValue(richText);}}}
}
相关文章:
EasyExcel导出导入excel工具类
接上一篇EasyExcel导出导入excel的文章,附上一份完整的工具类代码。对于字体颜色名称,请参考这篇文章。 POI字体颜色 小技巧 类转换用属性拷贝不同类如果有相同属性,则使用反射验证,减少代码量 private List<Person> vali…...
终端SSH连接工具SecureCRT安装和连接Linux
SecureCRT 9.5是一款集终端仿真与加密功能于一身的专业软件,其坚如磐石的安全性、高效的信息传输能力以及高度可定制的会话管理,使得它成为众多用户的首选。该软件不仅支持SSH2、SSH1、Telnet等多种协议,还提供了Relogin、Serial、TAPI、RAW等…...
赛逸展2025“创新引擎”启动:限量席位,点亮科技绿色新征程
当今时代,科技革新与绿色发展已然成为推动社会进步的双引擎。2025第七届亚洲消费电子技术贸易展(赛逸展)敏锐捕捉这一趋势,重磅打造“科技创新专区”,并面向科技、绿色企业吹响限量招募号角。 这个独具特色的专区紧扣…...
Spring的 init-method, @PostConstruct, InitializingBean 对比
Spring的 init-method, PostConstruct, InitializingBean 对比 在Spring框架中,init-method、PostConstruct和InitializingBean都是用于定义Bean初始化后执行逻辑的机制,但它们在实现方式、耦合度、执行顺序及适用场景上有所不同。以下是它们的对比总结…...
Gogs 精简备份与恢复方案(仅SQLite数据库和配置)
一、备份方案设计 1. 备份内容 SQLite数据库文件:/home/git/gogs/data/gogs.db 配置和附件:/home/git/gogs/custom 整个目录 2. 备份策略 每周日凌晨2点执行完整备份 保留最近4周的备份文件 备份存储在独立分区 /backup(使用永久化挂载…...
FPGA实现数码管显示分秒时间
目录 一. verilog实现 二. 烧录验证 三. 结果验证 使用开发板:DE2-115开发板 一. verilog实现 要实现分和秒,需要知道定时器的频率,通过查手册可知,我使用的开发板时钟为50hz,也就是时钟一个周期是2微秒。 5000000…...
读书记录九之《在峡江的转弯处-陈行甲人生笔记》
距离上本读完的书,写读后感有很长一段时间了,中间读了几本书,但都没写点文字,没错,是懒病又犯了。陈行甲这本书,一开始从网络上推荐看到,看之前介绍是一本人物自传的回忆录。我个人对这类贴近的…...
可视化开发:用Qt实现Excel级动态柱状图
Qt柱状图 QtChart 首先我们介绍一下 图表建立的基础:Qt Charts QtChart 是Qt框架的一个模块,专注与提供交互式数据可视化功能 俗话就是 用于用户轻松创建各种类型的图表和图形界面 它包含的图表类型有很多:折线图,饼图&#x…...
从零实现Json-Rpc框架】- 项目实现 - 基于Dispatcher模块的RPC框架
📢博客主页:https://blog.csdn.net/2301_779549673 📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! &…...
kubekey -实现懒人一键部署K8S集群
kubekey -实现懒人一键部署K8S集群 操作步骤 官网: https://kubesphere.io/zh/ 一、执行以下命令快速创建一个 Kubernetes 集群。 Master节点 如果您访问 GitHub/Googleapis 受限,请登录 Linux 主机,执行以下命令设置下载区域。 [roottest ~]…...
Android设计模式之模板方法模式
一、定义: 定义一个操作中的算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 二、结构: AbstractClass抽象类:定义算法的骨架,包含模板方法和若干…...
李宏毅机器学习笔记(1)—机器学习基本概念+深度学习基本概念
机器学习基本概念 1、获取模型 步骤 1.1、假定未知函数 带未知参数的函数 1.2、定义损失函数 真实值:label MAE MSE 几率分布,cross-entropy? 1.3、优化 单独考虑一个参数 让损失函数最小,找导数为零的点 单独考虑w,w…...
数字IC后端项目常见问题之streamOut layermap和innovus drc violation
Q1:我需要将Innovus设计GDS导出到Virtuoso,但发现写出GDS的过程会报如下所示的警告。这里写出GDS使用的是Virtuoso (DFII) streamOut mapping文件! Clock Gen模块Routing DRC,Timing分析及解决 streamOut tease.gds2 -mapFile cd…...
短剧系统开发动漫短剧系统源码开发上线小程序app教程
一、市场规模与用户增长:突破677亿,Z世代成主力 整体扩张 2025年短剧市场预计同比增长15%,规模达677.9亿元,用户规模6.62亿(占网民59.7%)。动漫短剧作为细分领域,增速显著受益于二次元文化渗透&…...
太阳能高杆路灯:照亮未来的新光
在全球能源转型进程加速以及可持续发展理念日益深入人心的背景下,太阳能高杆路灯作为融合新能源技术、智能控制技术与多功能集成特性的创新产品,正逐步革新传统路灯的格局。其不仅有效解决了传统路灯对电网供电的依赖问题,更为城市及乡村的照…...
《C++Linux编程进阶:从0实现muduo 》-第8讲.C++面试如何高效获取线程ID
章节重点 在C面试时,经常被问到如果高效获取线程ID,但不少同学都不知道如何回答。 重点是通过__thread关键字。 重点内容 视频讲解:《CLinux编程进阶:从0实现muduo C网络框架系列》-第8讲. C面试如何高效获取线程ID 测试获取线…...
【Tauri2】011——菜单menu(2)
前言 前面简单地创建了菜单,接下来就来试试菜单中的action Rust中菜单项注册action AppHandle in tauri - Rusthttps://docs.rs/tauri/2.4.0/tauri/struct.AppHandle.html#method.on_menu_event这就需要用到App或者AppHandle中的方法on_menu_event #[must_use] …...
架构设计基础系列:面向对象设计的原则
引言 面向对象设计(Object-Oriented Design,OOD)是软件开发中的重要概念,其核心在于通过对象、类、继承、封装和多态等机制,实现对现实世界问题的抽象和建模。OOD不仅有助于提高代码的可重用性、可维护性和可扩展性&a…...
UE5学习笔记 FPS游戏制作35 使用.csv配置文件
文章目录 导入.csv要求首先创建一个结构体导入配置文件读取配置 导入 .csv要求 第一行必须包含标题 第一列的内容必须不能重复,因为第一列会被当成行的名字,在数据处理中发挥类似于字典的key的作用 当前的配置文件内容如下 首先创建一个结构体 结构…...
嵌入式单片机ADC数模转换的基本方法
第一:模数转换的概述 1:模数转换的概念 一般在电路中,信号分为两种,一种是模拟信号,一种是数字信号,绝大多数传感器采集的都是模拟信号,如温度、湿度、烟雾浓度、亮度.......,但是对于计算机需要处理的数字信号,那就需要利用电路把模拟信号转换为数字信号,这个转换的…...
Web数据挖掘及其在电子商务中的研究与应用
标题:Web数据挖掘及其在电子商务中的研究与应用 内容:1.摘要 随着互联网的飞速发展,Web数据呈现出爆炸式增长,电子商务领域更是积累了海量数据。在此背景下,对Web数据进行有效挖掘并应用于电子商务具有重要意义。本研究旨在探索Web数据挖掘技…...
01-Docker 安装
1、安装环境介绍 安装环境:Linux CentOS 7 本安装教程参考Docker官方文档,地址如下:https://docs.docker.com/engine/install/centos/ 2、卸载旧版docker 首先如果系统中已经存在旧的Docker,则先卸载: yum remove do…...
Redis 的缓存雪崩、击穿、穿透及其解决办法
文章目录 Redis 的缓存雪崩、击穿、穿透及其解决办法缓存雪崩解决办法 缓存击穿解决方案 缓存穿透解决方案 Redis 的缓存雪崩、击穿、穿透及其解决办法 本篇文章回顾 Redis 当中缓存崩溃、击穿、穿透现象以及相应的解决办法,主要的参考资料是:https://w…...
使用 Selenium 构建简单高效的网页爬虫
在当今数据驱动的世界中,网络爬虫已成为获取网络信息的重要工具。本文将介绍如何使用 Python 和 Selenium 构建一个简单而高效的网页爬虫,该爬虫能够处理现代网站的动态内容,支持代理设置和用户配置文件。 为什么选择 Selenium? …...
性能比拼: Pingora vs Nginx (My NEW Favorite Proxy)
本内容是对知名性能评测博主 Anton Putra Pingora vs Nginx Performance Benchmark: My NEW Favorite Proxy! 内容的翻译与整理, 有适当删减, 相关指标和结论以原作为准 介绍 在本视频中,我们将对比 Nginx 和 Pingora(一个用于构建网络服务的 Rust 框架…...
Ranger一分钟
简介 Ranger Admin:Web UIPolicy Admin Tool:定义和管理策略的模块Ranger Plugins:HDFS、Hive、HBase、Kafka、Storm、YARNRanger UserSync: LDAP、Active DirectoryRanger KMS:管理和保护数据加密的密钥 加密密钥管理…...
STM32单片机入门学习——第5节: [3-1]GPIO输出
写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做! 本文写于:2025.04.01 STM32开发板学习——第5节: [3-1]GPIO输出 前言开发板说明引用解答和…...
Open GL ES ->模型矩阵、视图矩阵、投影矩阵等变换矩阵数学推导以及方法接口说明
Open GL ES 变换矩阵详解 一、坐标空间变换流程 局部空间 ->Model Matrix(模型矩阵)-> 世界空间 世界空间->View Matrix(视图矩阵)->观察空间 观察空间 ->Projection Matrix(投影矩阵)->裁剪空间 裁剪空间 ->ViewPort Transform(视口变换)>屏幕空间 …...
AI提示词:自然景区智能客服
提示描述 专为自然景区游客设计的智能客服系统,旨在通过人工智能技术提供实时、准确的景区信息、游览建议、安全提示和服务支持,提升游客的体验质量和满意度。 提示词 # Role: 自然景区智能客服## Profile: - Author: xxx - Version: 1.0 - Language: …...
c#的反射和特性
在 C# 中,反射(Reflection)和特性(Attributes)是两个强大的功能,它们在运行时提供元编程能力,广泛用于框架开发、对象映射和动态行为扩展。以下是对它们的详细介绍,包括定义、用法、…...
