使用EasyExcel实现导出excel文件时生成多级下拉选
前言
公司有个需求本来只涉及到两个下拉选项,后面就想能不能实现多个下拉选,当然我这里说的多个下拉选是联动的,比如省、地市、区县这种。
实现步骤
1、添加EasyExcel的Maven依赖
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.3.2</version></dependency>
2、一个具有多级关联的数据项
/*** excel下拉框数据项* @author lcy*/
@Data
public class SelectItem {public SelectItem(Integer columnIndex) {this.columnIndex = columnIndex;}/*** 下拉框所在列的索引,从0开始*/private Integer columnIndex;/*** 下拉框的值列表*/private List<DataItem> dataItems;/*** 子级对应的下拉框数据*/private SelectItem subSelect;public void addDataItem(String mappingKey,List<String> values){if (this.dataItems == null){this.dataItems = new ArrayList<>();}this.dataItems.add(new DataItem(mappingKey,values));}public void addDataItem(List<String> values){this.addDataItem("_"+UUID.randomUUID().toString().replaceAll("-",""),values);}@Datapublic static class DataItem{/*** 关联上级的key*/private String mappingKey;/*** 当前下拉框的值*/private List<String> values;/*** 当前下拉框的引用,隐藏页单元格地址*/private String hiddenFormulaRef;public DataItem(String mappingKey, List<String> values) {Assert.notBlank(mappingKey,"mappingKey is not blank");Assert.notEmpty(values,"values is not empty");this.mappingKey = mappingKey;this.values = values;}}
3、定义一个SheetWriteHandler,这是EasyExcel提供的一个组件,允许我们在sheet页生成前后做一些干预动作。
/*** @author lcy*/
public class SelectWriteHandler implements SheetWriteHandler , CellWriteHandler {private static final int ROW_SIZE = 10000;private final WriteFont redFont;private final List<SelectItem> selectItems;private final String HIDDEN_SHEET_NAME = "hidden_sheet";private final Set<Integer> selectColumns = new HashSet<>();private boolean isLoadSelectColumns = false;private int rowIndex = 0;public SelectWriteHandler(List<SelectItem> selectItems) {Assert.notEmpty(selectItems, "selectItems can not be empty");this.selectItems = selectItems;redFont = getRedFont();}@Overridepublic void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {Workbook workbook = writeWorkbookHolder.getWorkbook();Sheet hiddenSheet = workbook.getSheet(HIDDEN_SHEET_NAME);if (hiddenSheet != null){return ;}hiddenSheet = workbook.createSheet(HIDDEN_SHEET_NAME);workbook.setSheetHidden(workbook.getSheetIndex(hiddenSheet),true);Sheet sheet = writeSheetHolder.getSheet();for (SelectItem selectItem : selectItems) {buildHiddenSheetSelectRef(workbook,sheet,hiddenSheet,selectItem,null);}if (!isLoadSelectColumns){isLoadSelectColumns = true;}}private void buildHiddenSheetSelectRef(Workbook workbook,Sheet sheet,Sheet hiddenSheet, SelectItem selectItem,String formulaRef ) {if (!isLoadSelectColumns){selectColumns.add(selectItem.getColumnIndex());}List<SelectItem.DataItem> dataItems = selectItem.getDataItems();for (SelectItem.DataItem dataItem : dataItems) {setDataAndName(workbook, hiddenSheet, dataItem);}// 单元格地址引用if (formulaRef == null || formulaRef.isEmpty()){formulaRef = dataItems.get(0).getHiddenFormulaRef();}// 创建检验器DataValidation dataValidation = getDataValidation(sheet, selectItem, formulaRef);sheet.addValidationData(dataValidation);SelectItem subSelect = selectItem.getSubSelect();if (subSelect != null){buildHiddenSheetSelectRef(workbook,sheet,hiddenSheet,subSelect,getInDirectFormulaRef(selectItem.getColumnIndex()));}}private DataValidation getDataValidation(Sheet sheet, SelectItem selectItem, String formulaRef) {DataValidationHelper helper = sheet.getDataValidationHelper();DataValidationConstraint constraint = helper.createFormulaListConstraint(formulaRef);CellRangeAddressList rangeAddressList = new CellRangeAddressList(1,ROW_SIZE, selectItem.getColumnIndex(), selectItem.getColumnIndex());DataValidation dataValidation = helper.createValidation(constraint, rangeAddressList);dataValidation.setShowErrorBox(true);return dataValidation;}private void setDataAndName(Workbook workbook, Sheet hiddenSheet, SelectItem.DataItem dataItem) {// 构建隐藏数据Row row = hiddenSheet.createRow(rowIndex);List<String> values = dataItem.getValues();for (int i = 0; i < values.size(); i++) {row.createCell(i).setCellValue(values.get(i));}// 创建名称命名器Name name = workbook.createName();name.setNameName(dataItem.getMappingKey());name.setRefersToFormula(getFormulaRef(row));dataItem.setHiddenFormulaRef(name.getRefersToFormula());rowIndex++;}private String getInDirectFormulaRef(Integer columnIndex){CellReference slectCellReference = new CellReference(1, columnIndex);return "INDIRECT("+joinFormulaRef(slectCellReference, false)+")";}@Overridepublic void afterCellDispose(CellWriteHandlerContext context) {if (!context.getHead()){Integer columnIndex = context.getColumnIndex();if (selectColumns.contains(columnIndex)){// 设置红色字体context.getFirstCellData().getOrCreateStyle().setWriteFont(redFont);}}CellWriteHandler.super.afterCellDispose(context);}private String getFormulaRef(Row prvRow) {Cell startCell = prvRow.getCell(prvRow.getFirstCellNum());Cell endCell = prvRow.getCell(prvRow.getLastCellNum() - 1);return HIDDEN_SHEET_NAME + "!" + joinFormulaRef(new CellReference(startCell),true) + ":" + joinFormulaRef(new CellReference(endCell),true);}public String joinFormulaRef(CellReference cellReference,boolean isAbsolute){StringBuilder sb = new StringBuilder();String[] refs = cellReference.getCellRefParts();for (int i = refs.length -1 ; i >= 1; i--) {if (isAbsolute){sb.append("$");}sb.append(refs[i]);}return sb.toString();}/*** 返回一个红色字体* @return*/private WriteFont getRedFont() {WriteFont redFont = new WriteFont();redFont.setColor(IndexedColors.RED.getIndex());return redFont;}
}
4、准备数据
// 准备数据SelectItem selectItem = new SelectItem(0);selectItem.addDataItem(List.of("浙江省","河南省"));SelectItem subSelectItem = new SelectItem(1);subSelectItem.addDataItem("浙江省",List.of("杭州市","宁波市"));subSelectItem.addDataItem("河南省",List.of("郑州市","洛阳市","开封市"));selectItem.setSubSelect(subSelectItem);SelectItem selectItem3 = new SelectItem(2);selectItem3.addDataItem("杭州市",List.of("滨江区","西湖区"));selectItem3.addDataItem("宁波市",List.of("宁波市1","宁波市2"));selectItem3.addDataItem("郑州市",List.of("金水区","二七区"));selectItem3.addDataItem("洛阳市",List.of("洛阳市1","洛阳市2"));selectItem3.addDataItem("开封市",List.of("开封市1","开封市2"));subSelectItem.setSubSelect(selectItem3);
5、测试
EasyExcel.write("d:\\5555.xlsx").registerWriteHandler(new SelectWriteHandler(List.of(selectItem))).sheet().doWrite(Collections.emptyList());
完整的测试代码
public class SelectExcelTest {public static void main(String[] args) {// 准备数据SelectItem selectItem = new SelectItem(0);selectItem.addDataItem(List.of("浙江省","河南省"));SelectItem subSelectItem = new SelectItem(1);subSelectItem.addDataItem("浙江省",List.of("杭州市","宁波市"));subSelectItem.addDataItem("河南省",List.of("郑州市","洛阳市","开封市"));selectItem.setSubSelect(subSelectItem);SelectItem selectItem3 = new SelectItem(2);selectItem3.addDataItem("杭州市",List.of("滨江区","西湖区"));selectItem3.addDataItem("宁波市",List.of("宁波市1","宁波市2"));selectItem3.addDataItem("郑州市",List.of("金水区","二七区"));selectItem3.addDataItem("洛阳市",List.of("洛阳市1","洛阳市2"));selectItem3.addDataItem("开封市",List.of("开封市1","开封市2"));subSelectItem.setSubSelect(selectItem3);EasyExcel.write("d:\\5555.xlsx").registerWriteHandler(new SelectWriteHandler(List.of(selectItem))).sheet().doWrite(Collections.emptyList());}}
6、结果
相关文章:

使用EasyExcel实现导出excel文件时生成多级下拉选
前言 公司有个需求本来只涉及到两个下拉选项,后面就想能不能实现多个下拉选,当然我这里说的多个下拉选是联动的,比如省、地市、区县这种。 实现步骤 1、添加EasyExcel的Maven依赖 <dependency><groupId>com.alibaba</group…...

微信小程序 高校教材征订系统
文章目录 项目介绍具体实现截图技术介绍mvc设计模式小程序框架以及目录结构介绍错误处理和异常处理java类核心代码部分展示详细视频演示源码获取 项目介绍 系统分为三个角色,分别是教材科、系教学秘书、教研室主任。系统主要完成功能是教材科要发布教材征订信息&am…...

从0开始的STM32 定时器(I):聊一聊基本定时器
目录 时钟源 控制器 时基单元 关于HAL库如何配置基本定时器 HAL是如何初始化我们的定时器句柄的 HAL_TIM_Base_Init 开始定时 如何处理句柄? 在我们使用STM32解决一些问题的时候,常常会遇到说:我想要以一个周期做一些事情:…...

vue常见题型(1-10)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 2.2双向绑定的原理是什么vue框架采用的是数据双向绑定的方式,由三个重要部分构成2.2.1.ViewModel2.2.2 双向绑定2.2.3.1.编译Compile2.2.3.2.依赖收集 3…...
【SpringBoot】使用注解进行XSS防御
在Spring Boot中,我们可以使用注解的方式来进行XSS防御。注解是一种轻量级的防御手段,它可以在方法或字段级别对输入进行校验,从而防止XSS攻击。 引入相关依赖 maven依赖: <!--JSR-303/JSR-380用于验证的注解 --> <de…...

华为海思招聘-芯片与器件设计工程师-模拟芯片方向- 机试题-真题套题题目——共8套(每套四十题)
华为海思招聘-芯片与器件设计工程师-模拟芯片方向- 机试题-真题套题题目分享——共九套(每套四十题) 岗位——芯片与器件设计工程师 岗位意向——模拟芯片 真题题目分享,完整题目,无答案(共8套) 实习岗位…...
vscode 下载慢的解决方法
下载链接示例:https://az764295.vo.msecnd.net/stable/ccbaa2d27e38e5afa3e5c21c1c7bef4657064247/code1.62.3-1637137107amd64.deb 解决方法: 把 az764295.vo.msecnd.net 替换成 vscode.cdn.azure.cn...

STM32ZET6-USART使用
一、原理说明 STM32自带通讯接口 通讯目的 通信方式: 全双工:通信时可以双方同时通信。 半双工:通信时同一时间只能一个设备发送数据,其他设备接收。 单工:只能一个设备发送到另一个设备,例如USART只有…...

es自动补全(仅供自己参考)
elasticssearch提供了CompletionSuggester查询来实现自动补全功能。这个查询会匹配以用户输入内容开头的词条并返回。为了提高补全查询效率,对于文档中字段的类型有一些约束: 查询类型必须是:completion 字段内容是多个补全词条形成的数组 P…...

13-综合排序:Function Score Query 优化算分
使用了 function_score 查询来根据某个字段的值对查询结果进行打分。以下是该查询的主要部分: query: 包含了实际执行搜索的部分,在这里包括一个 multi_match 查询。 multi_match:用于在多个字段上执行相同的查询。 query:设置…...

鸿蒙应用App测试-专项测试(DevEco Testing)
注意:大家记得先学通用测试在学专项测试 鸿蒙应用App测试-通用测试-CSDN博客 注意:博主有个鸿蒙专栏,里面从上到下有关于鸿蒙next的教学文档,大家感兴趣可以学习下 如果大家觉得博主文章写的好的话,可以点下关注&am…...

RabbitMQ设置消息过期时间
RabbitMQ设置消息过期时间 1、过期消息(死信)2、设置消息过期的两种方式2.1、设置单条消息的过期时间2.1.1、配置文件application.yml2.1.2、配置类RabbitConfig2.1.3、发送消息业务类service(核心代码)2.1.4、启动类2.1.5、依赖文…...

大数据-209 数据挖掘 机器学习理论 - 梯度下降 梯度下降算法调优
点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: Hadoop(已更完)HDFS(已更完)MapReduce(已更完&am…...

粒子群优化双向深度学习!PSO-BiTCN-BiGRU-Attention多输入单输出回归预测
粒子群优化双向深度学习!PSO-BiTCN-BiGRU-Attention多输入单输出回归预测 目录 粒子群优化双向深度学习!PSO-BiTCN-BiGRU-Attention多输入单输出回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现PSO-BiTCN-BiGRU-Attention粒子…...

排序算法简介
直接插入排序: 将第一个元素视为已排序的序列,其余元素视为未排序序列。 逐个处理:从第二个元素开始,逐个将当前元素插入到已排序序列的适当位置,直到所有元素都被插入。 插入过程:对于每个待…...

(没有跳过联网激活)导致使用微软账号激活电脑---修改为本地账户和英文名字
修改为本地账户和英文名字 前言微软账号,本地账号与用户名基本知识账户管理方式一方式2 查看账户的sid并且修改文件夹名字和系统变量修改注册表和建立软件路径超链接注意事项总结 前言 当没有联网激活新买的电脑时候,这个就不用看了 当你是联网激活的时…...

[论文粗读][REALM: Retrieval-Augmented Language Model Pre-Training
引言 今天带来一篇检索增强语言模型预训练论文笔记——REALM: Retrieval-Augmented Language Model Pre-Training。这篇论文是在RAG论文出现之前发表的。 为了简单,下文中以翻译的口吻记录,比如替换"作者"为"我们"。 语言模型预训练…...
flink 内存配置(五):网络缓存调优
flink 内存配置(一):设置Flink进程内存 flink 内存配置(二):设置TaskManager内存 flink 内存配置(三):设置JobManager内存 flink 内存配置(四)…...

set和map的使用
目录 1.关联式容器 2.键值对 3.set 3.1set的模版参数列表 3.2对set的修改 3.2.1insert 3.2.2 erase 3.2.3clear 3.2.4swap 3.2.5 find 3.3set的迭代器 3.4set的容量 4.map 4.1对map的修改 4.1.1insert 4.1.2erase 4.1.3swap 4.1.4clear 4.2map的迭代器 4.3opera…...

LCL三相并网逆变器simulink仿真+说明文档
背景描述: 详细解析了LCL三相并网逆变器的工作原理,强调了准PR比例谐振控制的重要性,讨论了电感、电容参数选择及保护电路设计。通过仿真结果展示了逆变器性能优化的方法,以提升系统效率和稳定性。 模型介绍: 整体模…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...

《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...

2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...