使用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比例谐振控制的重要性,讨论了电感、电容参数选择及保护电路设计。通过仿真结果展示了逆变器性能优化的方法,以提升系统效率和稳定性。 模型介绍: 整体模…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...

WPF八大法则:告别模态窗口卡顿
⚙️ 核心问题:阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程,导致后续逻辑无法执行: var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题:…...

通过MicroSip配置自己的freeswitch服务器进行调试记录
之前用docker安装的freeswitch的,启动是正常的, 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...
加密通信 + 行为分析:运营商行业安全防御体系重构
在数字经济蓬勃发展的时代,运营商作为信息通信网络的核心枢纽,承载着海量用户数据与关键业务传输,其安全防御体系的可靠性直接关乎国家安全、社会稳定与企业发展。随着网络攻击手段的不断升级,传统安全防护体系逐渐暴露出局限性&a…...

基于谷歌ADK的 智能产品推荐系统(2): 模块功能详解
在我的上一篇博客:基于谷歌ADK的 智能产品推荐系统(1): 功能简介-CSDN博客 中我们介绍了个性化购物 Agent 项目,该项目展示了一个强大的框架,旨在模拟和实现在线购物环境中的智能导购。它不仅仅是一个简单的聊天机器人,更是一个集…...
MyBatis-Plus 常用条件构造方法
1.常用条件方法 方法 说明eq等于 ne不等于 <>gt大于 >ge大于等于 >lt小于 <le小于等于 <betweenBETWEEN 值1 AND 值2notBetweenNOT BETWEEN 值1 AND 值2likeLIKE %值%notLikeNOT LIKE %值%likeLeftLIKE %值likeRightLIKE 值%isNull字段 IS NULLisNotNull字段…...

Qt/C++学习系列之列表使用记录
Qt/C学习系列之列表使用记录 前言列表的初始化界面初始化设置名称获取简单设置 单元格存储总结 前言 列表的使用主要基于QTableWidget控件,同步使用QTableWidgetItem进行单元格的设置,最后可以使用QAxObject进行单元格的数据读出将数据进行存储。接下来…...

可视化预警系统:如何实现生产风险的实时监控?
在生产环境中,风险无处不在,而传统的监控方式往往只能事后补救,难以做到提前预警。但如今,可视化预警系统正在改变这一切!它能够实时收集和分析生产数据,通过直观的图表和警报,让管理者第一时间…...