Apache Poi 实现Excel多级联动下拉框

由于最近做的功能,需要将接口返回的数据列表,输出到excel中,以供后续导入,且网上现有的封装,使用起来都较为麻烦,故参考已有做法封装了工具类。

使用apache poi实现excel联动下拉框思路

  1. 创建隐藏单元格,存储下拉数据
  2. 创建名称管理器
  3. 使用indirect表达式进行联动

添加依赖

<!--Java程序对Microsoft Office格式档案读和写的功能-->
<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>5.2.2</version>
</dependency>
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.2</version>
</dependency>

直接上代码

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.*;import java.util.List;
import java.util.Map;
import java.util.Set;/*** excel验证工具类** @author chenchuancheng github.com/meethigher* @since 2023/08/20 23:55*/
public class ExcelValidationUtils {private static final int minRow = 1;private static final int maxRow = 100;private static final boolean debugHideSheet = true;/*** 创建一个xlsx** @return {@link XSSFWorkbook}*/public static XSSFWorkbook createOneXLSX() {return new XSSFWorkbook();}/*** 为xlsx添加一个sheet** @param wb        xlsx* @param sheetName sheet名* @param headers   首行标题头* @return sheet*/public static XSSFSheet addOneSheet(XSSFWorkbook wb, String sheetName, String[] headers) {XSSFSheet st = wb.createSheet(sheetName);//表头样式CellStyle style = wb.createCellStyle();style.setAlignment(HorizontalAlignment.CENTER); // 创建一个居中格式//字体样式Font fontStyle = wb.createFont();fontStyle.setFontName("微软雅黑");fontStyle.setFontHeightInPoints((short) 12);style.setFont(fontStyle);//单元格格式为文本XSSFDataFormat format = wb.createDataFormat();style.setDataFormat(format.getFormat("@"));//写标题XSSFRow row = st.createRow(0);st.createFreezePane(0, 1, 0, 1);for (int i = 0; i < headers.length; i++) {String value = headers[i];XSSFCell cell = row.createCell(i);st.setColumnWidth(i, value.length() * 1000);cell.setCellStyle(style);st.setDefaultColumnStyle(i, style);cell.setCellValue(value);}return st;}/*** 添加两层级联数据** @param wb                  xlsx* @param targetSheet         目标sheet* @param linkageData         两层级联数据* @param parentCol           父列* @param childCol            孩子列* @param parentColIdentifier 父列标识符* @return {@link XSSFSheet}*/public static XSSFSheet addLinkageDataValidation(XSSFWorkbook wb, XSSFSheet targetSheet, Map<String, List<String>> linkageData,int parentCol, int childCol, String parentColIdentifier) {XSSFSheet hideSt = wb.createSheet();wb.setSheetHidden(wb.getSheetIndex(hideSt), !debugHideSheet);int rowId = 0;Set<String> keySet = linkageData.keySet();for (String parent : keySet) {List<String> sonList = linkageData.get(parent);XSSFRow row = hideSt.createRow(rowId++);row.createCell(0).setCellValue(parent);for (int i = 0; i < sonList.size(); i++) {XSSFCell cell = row.createCell(i + 1);cell.setCellValue(sonList.get(i));}// 添加名称管理器,1表示b列,从b列开始往后,都是子级String range = getRange(1, rowId, sonList.size());Name name = wb.createName();name.setNameName(parent);String formula = hideSt.getSheetName() + "!" + range;name.setRefersToFormula(formula);}//创建表达式校验XSSFDataValidationHelper helper = new XSSFDataValidationHelper(targetSheet);//        //父级校验,如需生成更多,用户手动拖拽下拉即可。此操作会导致数组内容总长度超过255时报错
//        DataValidation parentValidation = helper.createValidation(helper.createExplicitListConstraint(keySet.toArray(new String[0])),
//                new CellRangeAddressList(minRow, maxRow, parentCol, parentCol));
//        parentValidation.createErrorBox("错误", "请选择正确的父级类型");
//        parentValidation.setShowErrorBox(true);
//        parentValidation.setSuppressDropDownArrow(true);
//        targetSheet.addValidationData(parentValidation);//解决长度为255的问题Name name = wb.createName();name.setNameName(hideSt.getSheetName());name.setRefersToFormula(hideSt.getSheetName() + "!$A$1:$A$" + keySet.size());DataValidation parentValidation = helper.createValidation(helper.createFormulaListConstraint(hideSt.getSheetName()), new CellRangeAddressList(minRow, maxRow, parentCol, parentCol));parentValidation.createErrorBox("错误", "请选择正确的父级类型");parentValidation.setShowErrorBox(true);targetSheet.addValidationData(parentValidation);//子级校验,如需生成更多,用户手动拖拽下拉即可for (int i = minRow; i < maxRow; i++) {DataValidation childValidation = helper.createValidation(helper.createFormulaListConstraint("INDIRECT(" + parentColIdentifier + "" + (i + 1) + ")"),new CellRangeAddressList(i, i, childCol, childCol));childValidation.createErrorBox("错误", "请选择正确的子级类型");childValidation.setShowErrorBox(true);childValidation.setSuppressDropDownArrow(true);targetSheet.addValidationData(childValidation);}return hideSt;}/*** 添加简单下拉列表验证-下拉列表总内容不超过255字符** @param st           sheet* @param dropDownList 下拉列表数据* @param firstCol     开始列,从0开始* @param lastCol      结束列,从0开始*/public static void addSimpleDropDownListValidation(XSSFSheet st, String[] dropDownList, int firstCol, int lastCol) {XSSFDataValidationHelper helper = new XSSFDataValidationHelper(st);XSSFDataValidationConstraint constraint = (XSSFDataValidationConstraint) helper.createExplicitListConstraint(dropDownList);CellRangeAddressList addressList = new CellRangeAddressList(minRow, maxRow, firstCol, lastCol);XSSFDataValidation validation = (XSSFDataValidation) helper.createValidation(constraint, addressList);validation.setSuppressDropDownArrow(true);validation.setShowErrorBox(true);st.addValidationData(validation);}/*** 添加复杂下拉列表验证-下拉列表总内容允许超过255字符** @param wb           xlsx* @param dropDownList 下拉列表数据* @param firstCol     开始列,从0开始* @param lastCol      结束列,从0开始*/public static void addComplexDropDownListValidation(XSSFWorkbook wb, XSSFSheet st, String[] dropDownList, int firstCol, int lastCol) {XSSFSheet hideSt = wb.createSheet();wb.setSheetHidden(wb.getSheetIndex(hideSt), !debugHideSheet);XSSFDataValidationHelper helper = new XSSFDataValidationHelper(st);for (int i = 0, length = dropDownList.length; i < length; i++) {String value = dropDownList[i];XSSFRow row = hideSt.createRow(i);XSSFCell cell = row.createCell(0);cell.setCellValue(value);}//解决长度为255的问题Name name = wb.createName();name.setNameName(hideSt.getSheetName());name.setRefersToFormula(hideSt.getSheetName() + "!$A$1:$A$" + dropDownList.length);DataValidation parentValidation = helper.createValidation(helper.createFormulaListConstraint(hideSt.getSheetName()), new CellRangeAddressList(minRow, maxRow, firstCol, lastCol));parentValidation.createErrorBox("错误", "请选择正确的类型");parentValidation.setShowErrorBox(true);st.addValidationData(parentValidation);}/*** 计算formula** @param offset   偏移量,如果给0,表示从A列开始,1,就是从B列* @param rowId    第几行* @param colCount 一共多少列* @return 如果给入参 1,1,10. 表示从B1-K1。最终返回 $B$1:$K$1*/private static String getRange(int offset, int rowId, int colCount) {char start = (char) ('A' + offset);if (colCount <= 25) {char end = (char) (start + colCount - 1);return "$" + start + "$" + rowId + ":$" + end + "$" + rowId;} else {char endPrefix = 'A', endSuffix;if ((colCount - 25) / 26 == 0 || colCount == 51) {// 26-51之间,包括边界(仅两次字母表计算)if ((colCount - 25) % 26 == 0) {// 边界值endSuffix = (char) ('A' + 25);} else {endSuffix = (char) ('A' + (colCount - 25) % 26 - 1);}} else {// 51以上if ((colCount - 25) % 26 == 0) {endSuffix = (char) ('A' + 25);endPrefix = (char) (endPrefix + (colCount - 25) / 26 - 1);} else {endSuffix = (char) ('A' + (colCount - 25) % 26 - 1);endPrefix = (char) (endPrefix + (colCount - 25) / 26);}}return "$" + start + "$" + rowId + ":$" + endPrefix + endSuffix + "$" + rowId;}}
}

使用示例

public class TestExportExcelWithValidation {private final static String[] headers = new String[]{"性别","省","市","区",};private static Map<String, List<String>> 省级() {Map<String, List<String>> map = new HashMap<>();map.put("湖北省", Arrays.asList("武汉市", "襄阳市"));map.put("吉林省", Arrays.asList("长春市", "吉林市"));return map;}private static Map<String, List<String>> 市级() {Map<String, List<String>> map = new HashMap<>();map.put("武汉市", Arrays.asList("洪山区", "江夏区"));map.put("长春市", Arrays.asList("宽城区", "南关区"));return map;}public static void main(String[] args) throws Exception {XSSFWorkbook wb = createOneXLSX();XSSFSheet st = addOneSheet(wb, "data", headers);addSimpleDropDownListValidation(st, new String[]{"男", "女"}, 0, 0);addLinkageDataValidation(wb, st, 省级(), 1, 2, "B");addLinkageDataValidation(wb, st, 市级(), 2, 3, "C");wb.write(new FileOutputStream("aaa.xlsx"));}
}

最终结果展示如图


idation(st, new String[]{“男”, “女”}, 0, 0);
addLinkageDataValidation(wb, st, 省级(), 1, 2, “B”);
addLinkageDataValidation(wb, st, 市级(), 2, 3, “C”);

    wb.write(new FileOutputStream("aaa.xlsx"));
}

}


最终结果展示如图[外链图片转存中...(img-zQCvRcAm-1693070160923)]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/54288.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何评估开源项目的活跃度和可持续性?

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

元矿山下的音视频应用

// 近年来&#xff0c;矿业的技术和管理模式随着元宇宙的火爆和自动驾驶技术的发展逐渐变化、升级&#xff0c;进而衍生出元矿山的概念&#xff0c;音视频技术也在其中成为了关键一环。LiveVideoStackCon 2023 上海站邀请了来自希迪智驾的任思亮&#xff0c;为大家分享希迪智…

windows MFC消息demo

1、在BEGIN_MESSAGE_MAP添加MAP映射 BEGIN_MESSAGE_MAP(CdesktopTotalMapDlg, CDialogEx)ON_MESSAGE(WM_SYS_NORMAL_MSG, OnSysNormalMessage)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_BUTTON_SELECTSOURCEDIR, &CdesktopTotalMapDlg::OnB…

基于神经网络的3D地质模型

地球科学家需要对地质环境进行最佳估计才能进行模拟或评估。 除了地质背景之外&#xff0c;建立地质模型还需要一整套数学方法&#xff0c;如贝叶斯网络、协同克里金法、支持向量机、神经网络、随机模型&#xff0c;以在钻井日志或地球物理信息确实稀缺或不确定时定义哪些可能是…

机器学习笔记之优化算法(十九)经典牛顿法的收敛性分析

机器学习笔记之优化算法——经典牛顿法的收敛性分析 引言回顾&#xff1a;算法的收敛性分析 Wolfe \text{Wolfe} Wolfe准则的收敛性分析梯度下降法在凸函数的收敛性分析梯度下降法在强凸函数的收敛性分析 经典牛顿法的收敛性分析收敛性定理介绍证明过程关于隐含条件的说明 引言…

FFmpeg5.0源码阅读——FFmpeg大体框架

摘要&#xff1a;前一段时间熟悉了下FFmpeg主流程源码实现&#xff0c;对FFmpeg的整体框架有了个大概的认识&#xff0c;因此在此做一个笔记&#xff0c;希望以比较容易理解的文字描述FFmpeg本身的结构&#xff0c;加深对FFmpeg的框架进行梳理加深理解&#xff0c;如果文章中有…

Android Mvvm设计模式的详解与实战教程

一、介绍 在开发设计模式中&#xff0c;模式经历了多次迭代&#xff0c;从MVC到MVP&#xff0c;再到如今的MVVM。发现的过程其实很简单&#xff0c;就是为了项目更好的管理。 设计模式严格来说属于软件工程的范畴&#xff0c;但是如今在各大面试中或者开发中&#xff0c;设计模…

三方接口调用设计方案

在为第三方系统提供接口的时候&#xff0c;肯定要考虑接口数据的安全问题&#xff0c;比如数据是否被篡改&#xff0c;数据是否已经过时&#xff0c;数据是否可以重复提交等问题 在设计三方接口调用的方案时&#xff0c;需要考虑到安全性和可用性。以下是一种设计方案的概述&a…

【跟小嘉学 Rust 编程】十七、面向对象语言特性

系列文章目录 【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据 【跟小嘉学…

C# 学习笔记--个人学习使用 <2>

C# 学习笔记 Chapter 2 比较硬的基础部分Section 1 委托Part 1 Action 与 func 委托的示例Part 2 自定义委托Part 3 委托的一般使用Part 4 委托的高级使用Part 5 适时地使用接口 Interface 取代一些对委托的使用 Section 2 事件Part 1 初步了解事件Part 2 事件的应用Part 3 事件…

【Luniux】解决Ubuntu外接显示器不显示的问题

Luniux】解决Ubuntu外接显示器不显示的问题 文章目录 Luniux】解决Ubuntu外接显示器不显示的问题1. 检查nvidia显卡驱动是否正常2. 更新驱动3. 检查显示器是否能检测到Reference 1. 检查nvidia显卡驱动是否正常 使用命令行 nvidia-smi来检查显卡驱动是否正常&#xff0c;如果…

持续集成与持续交付:现代软件测试的变革之路

引言 在数字化时代&#xff0c;软件开发的速度和复杂性都在不断增加。为了满足市场的需求&#xff0c;企业需要更快、更高效地交付高质量的软件产品。在这样的背景下&#xff0c;持续集成与持续交付&#xff08;CI/CD&#xff09;成为了软件开发和测试的核心实践。 软件开发的…

论文阅读 The Power of Tiling for Small Object Detection

The Power of Tiling for Small Object Detection Abstract 基于深度神经网络的技术在目标检测和分类方面表现出色。但这些网络在适应移动平台时可能会降低准确性&#xff0c;因为图像分辨率的增加使问题变得更加困难。在低功耗移动设备上实现实时小物体检测一直是监控应用的…

小研究 - Java虚拟机性能及关键技术分析

利用specJVM98和Java Grande Forum Benchmark suite Benchmark集合对SJVM、IntelORP,Kaffe3种Java虚拟机进行系统测试。在对测试结果进行系统分析的基础上&#xff0c;比较了不同JVM实现对性能的影响和JVM中关键模块对JVM性能的影响&#xff0c;并提出了提高JVM性能的一些展望。…

css之文字连续光影特效、动画、scss

文章目录 效果图htmlscsscss 效果图 html <div><span>C</span><span>O</span><span>L</span><span>O</span><span>R</span><span>F</span><span>U</span><span>L</span&…

WOFOST模型与PCSE模型应用

实现作物产量的准确估算对于农田生态系统响应全球变化、可持续发展、科学粮食政策制定、粮食安全维护都至关重要。传统的经验模型、光能利用率模型等估产模型原理简单&#xff0c;数据容易获取&#xff0c;但是作物生长发育非常复杂&#xff0c;中间涉及众多生理生化过程&#…

Java学数据结构(2)——树Tree 二叉树binary tree 二叉查找树 AVL树 树的遍历

目录 引出什么是树Tree&#xff1f;树的实现二叉树binary tree查找树ADT——二叉查找树Binary Search Tree1.contains方法2.findMax和findMin方法3.insert方法4.remove方法&#xff08;复杂&#xff09;二叉查找树的深度 AVL(Adelson-Velskii和Landis)树——平衡条件(balance c…

流处理详解

【今日】 目录 一 Stream接口简介 Optional类 Collectors类 二 数据过滤 1. filter()方法 2.distinct()方法 3.limit()方法 4.skip()方法 三 数据映射 四 数据查找 1. allMatch()方法 2. anyMatch()方法 3. noneMatch()方法 4. findFirst()方法 五 数据收集…

微信小程序的form表单提交

获取input有两种方法&#xff1a; 第一&#xff1a;bindsubmit方法 注意&#xff1a; 1.使用form里面定义bindsubmit事件 2.bindsubmit事件需要配合button里面定义的formType“submit” 操作 3.设置input的name值来获取对应的数据 <form bindsubmit"formSubmit"…