【EasyExcel】多sheet、追加列
业务-EasyExcel多sheet、追加列
背景
最近接到一个导出Excel的业务,需求就是多sheet,每个sheet导出不同结构,第一个sheet里面能够根据最后一列动态的追加列,追加多少得看运营人员传了多少需求列。原本使用的 pig4cloud 架子,使用 @ResponseExcel注解方式组装返回数据即可,但是实现过程中发现并不是所想要的效果。
组件地址:https://github.com/pig-mesh/excel-spring-boot-starter
这样写能够实现多 sheet 导出,但是动态的移除列然后在追加列我尝试了并没有好的方案,有可能也是我没有找到,我找到的是下面面动态的修改列名称。
多 sheet导出,只需要返 List<List> 即可。
@ResponseExcel(name = "不同Sheet的导出", sheet = {"sheet1", "sheet2"})
@PostMapping("/export")
public List<List> export(@RequestBody queryModel model) {model.setSize(-1);return userService.userExcelList(model);
}
导出并自定义头信息
@Data
public class SimpleData {@ExcelProperty("字符串标题")private String string;@ExcelProperty("日期标题")private Date date;@ExcelProperty("数字标题")private Integer number;// 忽略@ExcelIgnoreprivate String ignore;
}
自定义头信息生成器:
注意需要实现 HeadGenerator 接口,且注册为一个 spring bean.
@Component
public class SimpleDataHeadGenerator implements HeadGenerator {@Overridepublic HeadMeta head(Class<?> clazz) {HeadMeta headMeta = new HeadMeta();headMeta.setHead(simpleDataHead());// 排除 number 属性headMeta.setIgnoreHeadFields(new HashSet<>(Collections.singletonList("number")));return headMeta;}private List<List<String>> simpleDataHead() {List<List<String>> list = new ArrayList<>();List<String> head0 = new ArrayList<>();head0.add("自定义字符串标题" + System.currentTimeMillis());List<String> head1 = new ArrayList<>();head1.add("自定义日期标题" + System.currentTimeMillis());list.add(head0);list.add(head1);return list;}
}
该头生成器,将固定返回 自定义字符串标题 和 自定义日期标题 两列头信息,实际使用时可根据业务动态处理,方便在一些权限控制时动态修改或者增删列头。
@RequestMapping("/head")
@RestController
public class ExcelHeadTestController {@ResponseExcel(name = "customHead", headGenerator = SimpleDataHeadGenerator.class)@GetMappingpublic List<SimpleData> multi() {List<SimpleData> list = new ArrayList<>();for (int i = 0; i < 10; i++) {SimpleData simpleData = new SimpleData();simpleData.setString("str" + i);simpleData.setNumber(i);simpleData.setDate(new Date());list.add(simpleData);}return list;}
}

那就只能放弃使用组件方式,自己写 EasyExcel 拦截器。
代码实现
导出工具
exHealthSheetDy 静态方法如下,实现了 2 个 sheet 不同结构导出。
/*** 2 sheet 动态追加列** @param response 响应* @param dataMap dataMap* @param fileName Excel名称* @param sheetNameList sheet名称* @throws Exception Exception*/
public static void exHealthSheetDy(HttpServletResponse response, Map<Integer, List<? extends Object>> dataMap, String fileName, List<String> sheetNameList, List<String> labelGroupName) throws Exception {// 表头样式WriteCellStyle headWriteCellStyle = new WriteCellStyle();// 设置表头居中对齐headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);// 内容样式WriteCellStyle contentWriteCellStyle = new WriteCellStyle();// 设置内容剧中对齐contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);ExcelWriter build = EasyExcel.write(getOutputStream(fileName, response)).excelType(ExcelTypeEnum.XLSX).registerWriteHandler(horizontalCellStyleStrategy).build();for (String s : sheetNameList) {WriteSheet writeSheet;if (s.equals("风险")) {// 风险writeSheet = EasyExcel.writerSheet(s).head(HealthUserOneExcelVo.class).registerWriteHandler(new LabelGroupNameRowWriteHandler(labelGroupName)).build();build.write(dataMap.get(0), writeSheet);} else {// 指标writeSheet = EasyExcel.writerSheet(s).head(HealthUserExcelIndexVo.class).build();build.write(dataMap.get(1), writeSheet);}}build.finish();
}private static OutputStream getOutputStream(String fileName, HttpServletResponse response) throws Exception {fileName = URLEncoder.encode(fileName, "UTF-8");response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf8");response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");return response.getOutputStream();
}
拦截器
业务需求是根据 13 列切割根据传入的要求集合追加列。
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.write.handler.RowWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;/*** 行拦截器 将字符串换成多列数据** @author William*/
@Slf4j
public class LabelGroupNameRowWriteHandler implements RowWriteHandler {/*** 样式,与其他列保持一样的样式*/private CellStyle firstCellStyle;/*** 体检标签分组列表*/private List<String> labelGroupName;public LabelGroupNameRowWriteHandler(List<String> labelGroupName) {this.labelGroupName = labelGroupName;}/*** 字符串转*/@Overridepublic void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer integer, Boolean isHead) {// ONE 13 行, 我的是 13 列 具体根据自己的 Excel 定位Cell cell = row.getCell(13);row.removeCell(cell);Map<String, Cell> map = new LinkedHashMap<>();int cellIndex = 0;for (int i = 0; i < labelGroupName.size(); i++) {if (StrUtil.isBlank(labelGroupName.get(i)) || map.containsKey(labelGroupName.get(i))) {continue;}Cell fi = row.createCell(cellIndex + 13);map.put(labelGroupName.get(i), fi);cellIndex++;}if (!isHead) {String stringCellValue = cell.getStringCellValue();try {String[] split = stringCellValue.split(",");for (Map.Entry<String, Cell> stringCellEntry : map.entrySet()) {boolean equalsRes = false;for (String s : split) {if (stringCellEntry.getKey().equals(s)) {equalsRes = true;break;}}if (equalsRes) {stringCellEntry.getValue().setCellValue("有");} else {stringCellEntry.getValue().setCellValue("无");}}} catch (Exception e) {log.error("afterRowDispose Exception:{}", e.getMessage(), e);}} else {Workbook workbook = writeSheetHolder.getSheet().getWorkbook();firstCellStyle = firstCellStyle(workbook);for (Map.Entry<String, Cell> stringCellEntry : map.entrySet()) {stringCellEntry.getValue().setCellValue(stringCellEntry.getKey());stringCellEntry.getValue().setCellStyle(firstCellStyle);}}}/*** excel列样式** @param workbook Workbook* @return CellStyle*/public CellStyle firstCellStyle(Workbook workbook) {CellStyle cellStyle = workbook.createCellStyle();// 居中cellStyle.setAlignment(HorizontalAlignment.CENTER);cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);// 灰色cellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());// 设置边框cellStyle.setBorderBottom(BorderStyle.THIN);cellStyle.setBorderLeft(BorderStyle.THIN);cellStyle.setBorderRight(BorderStyle.THIN);cellStyle.setBorderTop(BorderStyle.THIN);// 文字Font font = workbook.createFont();font.setFontHeightInPoints((short) 14);font.setFontName("宋体");font.setBold(Boolean.TRUE);cellStyle.setFont(font);return cellStyle;}@Overridepublic void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer integer, Integer integer1, Boolean aBoolean) {}@Overridepublic void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer integer, Boolean aBoolean) {}
}
相关文章:
【EasyExcel】多sheet、追加列
业务-EasyExcel多sheet、追加列 背景 最近接到一个导出Excel的业务,需求就是多sheet,每个sheet导出不同结构,第一个sheet里面能够根据最后一列动态的追加列,追加多少得看运营人员传了多少需求列。原本使用的 pig4cloud 架子&…...
韩顺平 | 零基础快速学Python
环境准备 开发工具:IDLE、Pycharm、Sublime Text、Eric 、文本编辑器(记事本/editplus/notepad) Python特点:既支持面向过程OOP、也支持面向对象编程;具有解释性,不需要编程二进制代码,可以直…...
docker部署DOS游戏
下载镜像 docker pull registry.cn-beijing.aliyuncs.com/wuxingge123/dosgame-web-docker:latestdocker-compose部署 vim docker-compose.yml version: 3 services:dosgame:container_name: dosgameimage: registry.cn-beijing.aliyuncs.com/wuxingge123/dosgame-web-docke…...
基于单片机的无线红外报警系统
**单片机设计介绍,基于单片机的无线红外报警系统 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的无线红外报警系统是一种结合了单片机控制技术和无线红外传感技术的安防系统。该系统通过无线红外传感器实…...
【JAVAEE学习】探究Java中多线程的使用和重点及考点
˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如…...
Day81:服务攻防-开发框架安全SpringBootStruts2LaravelThinkPHPCVE复现
目录 PHP-框架安全-Thinkphp&Laravel Laravel CVE-2021-3129 RCE Thinkphp 版本3.X RCE-6.X RCE 版本6.X lang RCE J2EE-框架安全-SpringBoot&Struts2 Struct2 旧漏洞(CVE-2016-0785等) struts2 代码执行 (CVE-2020-17530)s2-061 Str…...
.kat6.l6st6r勒索病毒肆虐,这些应对策略或许能帮到你
引言: 近年来,网络安全问题日益凸显,其中勒索病毒更是成为了公众关注的焦点。其中,.kat6.l6st6r勒索病毒以其独特的传播方式和破坏力,给全球用户带来了极大的困扰。本文将深入探讨.kat6.l6st6r勒索病毒的特点…...
maya移除节点 修改节点
目录 maya移除节点 使用 Maya 用户界面: 使用脚本: maya 修改节点名字 使用 Maya 用户界面: 使用 MEL 脚本: 使用 Python 脚本: 注意事项: maya移除节点 使用 Maya 用户界面: 在“层次…...
嵌入式算法开发系列之卡尔曼滤波算法
卡尔曼滤波算法 文章目录 卡尔曼滤波算法前言一、卡尔曼滤波算法原理二、算法应用三、C语言实现总结 前言 在嵌入式系统中,传感器数据通常受到噪声、误差和不确定性的影响,因此需要一种有效的方法来估计系统的状态。卡尔曼滤波算法是一种基于概率理论的…...
简述对css工程化的理解
一、css工程化解决了哪些问题 1、宏观设计:css如何组织、拆分、设计模块结构 2、编码优化:如何更好地编写css 3、构建:如何处理css,使打包结果最优 4、可维护性:最小化后续的变更成本 二、针对问题,如何解…...
.NET 5种线程安全集合
在.NET中,有许多种线程安全的集合类,下面介绍五种我们常用的线程安全集合以及他们的基本用法。 ConcurrentBag ConcurrentBag 是一个线程安全的无序包。它适用于在多线程环境中频繁添加和移除元素的情况。 ConcurrentBag<int> concurrentBag n…...
计算机信息自查
文章目录 操作系统安装时间硬盘序列号查询上网IPMAC地址 操作系统安装时间 可以使用命令行形式,查询windows系统安装时间: wmic OS get InstallDate首先显示年份,然后是月份,然后是日期,然后是安装的确切时间 或者w…...
配置vite配置文件更改项目端口、使用@别名
一、配置vite配置文件更改项目端口 vite官方文档地址:开发服务器选项 | Vite 官方中文文档 (vitejs.dev) 使用: 二、使用别名 1. 安装 types/node types/node 包允许您在TypeScript项目中使用Node.js的核心模块和API,并提供了对它们的类型…...
【LeetCode热题100】【链表】环形链表
题目链接:141. 环形链表 - 力扣(LeetCode) 判断一个链表有没有环可以用快慢指针的方法,如果没有环,那么最终可以让两个指针中一个为空,如果有环,那么快指针终会与慢指针相遇 class Solution {…...
SpringBoot整合ELK8.1.x实现日志中心教程
目录 背景 环境准备 环境安装 1.JDK安装 2.安装Elasticsearch 3.安装zookeeper 4.安装Kafka 5.安装logstash 6.安装file beat 解决方案场景 1.日志采集 1.1 应用日志配置 1.1.1 创建logback-spring.xml文件 1.1.2 创建LoggerFactory 1.1.3 trace日志的记录用法 …...
计算机网络:数据链路层 - 封装成帧 透明传输 差错检测
计算机网络:数据链路层 - 封装成帧 & 透明传输 & 差错检测 数据链路层概述封装成帧透明传输差错检测 数据链路层概述 从数据链路层来看,主机 H1 到 H2 的通信可以看成是在四段不同的链路上的通信组成的,所谓链路就是从一个节点到相邻…...
Open3D (C++) 计算点云的特征值特征向量
目录 一、算法原理二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理 针对整个点云 P = { p i } i...
Java | Leetcode Java题解之第8题字符串转换整数atoi
题目: 题解: class Solution {public int myAtoi(String str) {Automaton automaton new Automaton();int length str.length();for (int i 0; i < length; i) {automaton.get(str.charAt(i));}return (int) (automaton.sign * automaton.ans);} …...
BL200耦合器数据采集模块
BL200耦合器数据采集模块是一个数据采集和控制系统,基于强大的32 位ARM926EJ-S™ 微处理器设计,采用Linux操作系统,支持Modbus TCP协议,可以快速接入现场PLC、MES、Ignition和SCADA以及ERP系统,同时也能快速连接到AWS云…...
基于Uni-app的体育场馆预约系统的设计与实现
个人介绍 hello hello~ ,这里是 code袁~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 🦁作者简介:一名喜欢分享和记录学习的…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
