【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袁~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 🦁作者简介:一名喜欢分享和记录学习的…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
