apache poi 实现下拉框联动校验

apache poi 提供了 DataValidation​ 接口 让我们可以轻松实现 Excel 下拉框数据局校验。但是下拉框联动校验是无法直接通过 DataValidation ​实现,所以我们可以通过其他方式间接实现。

步骤如下:

  1. 创建一个隐藏 sheet

    private static void createHiddenSheet(List<String> provinceList, Map<String, String[]> regionMap, Workbook workbook) { String hiddenSheetName = "region"; Sheet hiddenSheet = workbook.createSheet(hiddenSheetName); // 这里也可以设置 hidden 为 false 这样可以直接看到 sheet 内容 workbook.setSheetHidden(workbook.getSheetIndex(hiddenSheet), true); }
  2. 将数据放入隐藏 sheet

    int rowNum = 0; // 第一行存放省数据 Row row = hiddenSheet.createRow(rowNum); for (int i = 0; i < provinceList.size(); i++) { Cell cell = row.createCell(i); cell.setCellValue(provinceList.get(i)); } rowNum++; for (String key : regionMap.keySet()) { String[] dataArray = regionMap.get(key); // 循环创建行,每行存放一个数组 row = hiddenSheet.createRow(rowNum); // key 放在每行第一个,value 放在每行的后面 Cell keyCell = row.createCell(0); keyCell.setCellValue(key); for (int i = 0, length = dataArray.length; i < length; i++) { Cell cell = row.createCell(i + 1); cell.setCellValue(dataArray[i]); } Name name = workbook.createName(); // 将key 设置为下拉框的key name.setNameName(key); String formula = hiddenSheetName + "!$B$" + (rowNum + 1) + ":$" + (convertNumberToLetter(dataArray.length + 1)) + "$" + (rowNum + 1); name.setRefersToFormula(formula); // 可以将formula 放在最后一列 Cell formulaCell = row.createCell(dataArray.length + 1); formulaCell.setCellValue(formula); rowNum++; }
  3. 在主 sheet 中使用 formula 来使用隐藏 sheet 的数据

    DataValidationHelper helper = mainSheet.getDataValidationHelper(); // 设置省份下拉框 CellRangeAddressList provRangeAddressList = new CellRangeAddressList(1, 1000, 0, 0); // formula 为 region!$A$1:$E$1 DataValidationConstraint dvConstraint = helper.createFormulaListConstraint("region!$A$1:$" + (convertNumberToLetter(provinceList.size())) + "$1"); DataValidation provinceDataValidation = helper.createValidation(dvConstraint, provRangeAddressList); provinceDataValidation.setSuppressDropDownArrow(true); mainSheet.addValidationData(provinceDataValidation);
  4. 设置联动下拉框 DataValidation

    // 设置市下拉框 firstCol lastCol 根据实际情况设置 CellRangeAddressList cityRange = new CellRangeAddressList(1, 1000, 1, 1); DataValidationConstraint cityConstraint = helper.createFormulaListConstraint("INDIRECT(A2)"); DataValidation cityValidation = helper.createValidation(cityConstraint, cityRange); mainSheet.addValidationData(cityValidation); // 设置县下拉框 firstCol lastCol 根据实际情况设置 CellRangeAddressList districtRange = new CellRangeAddressList(1, 1000, 2, 2); DataValidation districtValidation = helper.createValidation(helper.createFormulaListConstraint("INDIRECT(B2)"), districtRange); mainSheet.addValidationData(districtValidation);
  5. 完整代码如下:

    package com.shang; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddressList; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import java.io.FileOutputStream; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author: shangwei * @date: 2024/11/3 13:01 */ public class ExcelUtil { public static void createExcel(String path, List<String> provinceList, Map<String, String[]> regionMap) { try { Workbook workbook = new XSSFWorkbook(); createHiddenSheet(provinceList, regionMap, workbook); Sheet mainSheet = workbook.createSheet("mainSheet"); // 主sheet 第一行数据 String[] titles = {"省", "市", "县"}; int rowNum = 0; Row row = mainSheet.createRow(rowNum); for (int i = 0; i < titles.length; i++) { Cell cell = row.createCell(i); cell.setCellValue(titles[i]); } DataValidationHelper helper = mainSheet.getDataValidationHelper(); // 设置省份下拉框 CellRangeAddressList provRangeAddressList = new CellRangeAddressList(1, 1000, 0, 0); // formula 为 region!$A$1:$E$1 DataValidationConstraint dvConstraint = helper.createFormulaListConstraint("region!$A$1:$" + (convertNumberToLetter(provinceList.size())) + "$1"); DataValidation provinceDataValidation = helper.createValidation(dvConstraint, provRangeAddressList); provinceDataValidation.setSuppressDropDownArrow(true); mainSheet.addValidationData(provinceDataValidation); // 设置市下拉框 firstCol lastCol 根据实际情况设置 CellRangeAddressList cityRange = new CellRangeAddressList(1, 1000, 1, 1); DataValidationConstraint cityConstraint = helper.createFormulaListConstraint("INDIRECT(A2)"); DataValidation cityValidation = helper.createValidation(cityConstraint, cityRange); mainSheet.addValidationData(cityValidation); // 设置县下拉框 firstCol lastCol 根据实际情况设置 CellRangeAddressList districtRange = new CellRangeAddressList(1, 1000, 2, 2); DataValidation districtValidation = helper.createValidation(helper.createFormulaListConstraint("INDIRECT(B2)"), districtRange); mainSheet.addValidationData(districtValidation); FileOutputStream fileOutputStream = new FileOutputStream(path); workbook.write(fileOutputStream); } catch (Exception e) { e.printStackTrace(); } } private static void createHiddenSheet(List<String> provinceList, Map<String, String[]> regionMap, Workbook workbook) { String hiddenSheetName = "region"; Sheet hiddenSheet = workbook.createSheet(hiddenSheetName); int rowNum = 0; // 第一行存放省数据 Row row = hiddenSheet.createRow(rowNum); for (int i = 0; i < provinceList.size(); i++) { Cell cell = row.createCell(i); cell.setCellValue(provinceList.get(i)); } rowNum++; for (String key : regionMap.keySet()) { String[] dataArray = regionMap.get(key); // 循环创建行,每行存放一个数组 row = hiddenSheet.createRow(rowNum); // key 放在每行第一个,value 放在每行的后面 Cell keyCell = row.createCell(0); keyCell.setCellValue(key); for (int i = 0, length = dataArray.length; i < length; i++) { Cell cell = row.createCell(i + 1); cell.setCellValue(dataArray[i]); } Name name = workbook.createName(); // 将key 设置为下拉框的key name.setNameName(key); String formula = hiddenSheetName + "!$B$" + (rowNum + 1) + ":$" + (convertNumberToLetter(dataArray.length + 1)) + "$" + (rowNum + 1); name.setRefersToFormula(formula); // 可以将formula 放在最后一列 Cell formulaCell = row.createCell(dataArray.length + 1); formulaCell.setCellValue(formula); rowNum++; } // 这里也可以设置 hidden 为 false 这样可以直接看到 sheet 内容 workbook.setSheetHidden(workbook.getSheetIndex(hiddenSheet), true); } /** * 将数字 1 到 26 转换为对应的字母 A 到 Z。 * * @param number 要转换的数字,范围是 1 到 26。 * @return 对应的字母。 */ public static String convertNumberToLetter(int number) { if (number < 1 || number > 26) { throw new IllegalArgumentException("Number must be between 1 and 26"); } return String.valueOf((char) ('A' + number - 1)); } public static void main(String[] args) { Map<String, String[]> regionMap = new HashMap<>(); List<String> provinceList = Arrays.asList("湖北省", "湖南省", "广东省", "江苏省", "浙江省"); regionMap.put("湖北省", new String[]{"武汉市", "黄石市", "十堰市", "宜昌市", "襄樊市", "鄂州市", "荆门市", "孝感市", "荆州市", "黄冈市", "咸宁市", "随州市"}); regionMap.put("湖南省", new String[]{"长沙市", "株洲市", "湘潭市", "衡阳市", "邵阳市", "岳阳市", "常德市", "张家界市", "益阳市", "郴州市", "永州市", "怀化市"}); regionMap.put("广东省", new String[]{"广州市", "韶关市", "深圳市", "珠海市", "汕头市", "佛山市", "江门市", "湛江市", "茂名市", "肇庆市", "惠州市", "梅州市", "汕尾市", "河源市", "阳江市", "清远市"}); regionMap.put("江苏省", new String[]{"南京市", "无锡市", "徐州市", "常州市", "苏州市", "南通市", "连云港市", "淮安市", "盐城市", "扬州市", "镇江市", "泰州市", "宿迁市"}); regionMap.put("浙江省", new String[]{"杭州市", "宁波市", "温州市", "嘉兴市", "湖州市", "绍兴市", "金华市", "衢州市", "舟山市", "台州市", "丽水市"}); regionMap.put("武汉市", new String[]{"江岸镇", "江汉镇", "江夏镇", "硚口镇", "武昌镇", "江夏镇"}); regionMap.put("黄石市", new String[]{"黄石港镇", "西塞山镇", "下陆镇", "大冶镇", "大冶镇"}); String path = "/Users/shangwei/Desktop/example" + System.currentTimeMillis() + ".xlsx"; createExcel(path, provinceList, regionMap); } }

相关 Maven 依赖

<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.3</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.11.0</version> </dependency>

运行截图:

image

  • POI
    23 引用 • 21 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • 智能合约

    智能合约(Smart contract)是一种旨在以信息化方式传播、验证或执行合同的计算机协议。智能合约允许在没有第三方的情况下进行可信交易,这些交易可追踪且不可逆转。智能合约概念于 1994 年由 Nick Szabo 首次提出。

    1 引用 • 11 回帖
  • 新人

    让我们欢迎这对新人。哦,不好意思说错了,让我们欢迎这位新人!
    新手上路,请谨慎驾驶!

    52 引用 • 228 回帖
  • 钉钉

    钉钉,专为中国企业打造的免费沟通协同多端平台, 阿里巴巴出品。

    15 引用 • 67 回帖 • 297 关注
  • Love2D

    Love2D 是一个开源的, 跨平台的 2D 游戏引擎。使用纯 Lua 脚本来进行游戏开发。目前支持的平台有 Windows, Mac OS X, Linux, Android 和 iOS。

    14 引用 • 53 回帖 • 544 关注
  • 服务

    提供一个服务绝不仅仅是简单的把硬件和软件累加在一起,它包括了服务的可靠性、服务的标准化、以及对服务的监控、维护、技术支持等。

    41 引用 • 24 回帖
  • RIP

    愿逝者安息!

    8 引用 • 92 回帖 • 393 关注
  • Hexo

    Hexo 是一款快速、简洁且高效的博客框架,使用 Node.js 编写。

    22 引用 • 148 回帖 • 8 关注
  • iOS

    iOS 是由苹果公司开发的移动操作系统,最早于 2007 年 1 月 9 日的 Macworld 大会上公布这个系统,最初是设计给 iPhone 使用的,后来陆续套用到 iPod touch、iPad 以及 Apple TV 等产品上。iOS 与苹果的 Mac OS X 操作系统一样,属于类 Unix 的商业操作系统。

    87 引用 • 139 回帖
  • 招聘

    哪里都缺人,哪里都不缺人。

    189 引用 • 1057 回帖
  • 酷鸟浏览器

    安全 · 稳定 · 快速
    为跨境从业人员提供专业的跨境浏览器

    3 引用 • 59 回帖 • 45 关注
  • Gzip

    gzip (GNU zip)是 GNU 自由软件的文件压缩程序。我们在 Linux 中经常会用到后缀为 .gz 的文件,它们就是 Gzip 格式的。现今已经成为互联网上使用非常普遍的一种数据压缩格式,或者说一种文件格式。

    9 引用 • 12 回帖 • 168 关注
  • JWT

    JWT(JSON Web Token)是一种用于双方之间传递信息的简洁的、安全的表述性声明规范。JWT 作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以 JSON 的形式安全的传递信息。

    20 引用 • 15 回帖 • 20 关注
  • WebSocket

    WebSocket 是 HTML5 中定义的一种新协议,它实现了浏览器与服务器之间的全双工通信(full-duplex)。

    48 引用 • 206 回帖 • 297 关注
  • 设计模式

    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

    200 引用 • 120 回帖 • 1 关注
  • Ant-Design

    Ant Design 是服务于企业级产品的设计体系,基于确定和自然的设计价值观上的模块化解决方案,让设计者和开发者专注于更好的用户体验。

    17 引用 • 23 回帖 • 1 关注
  • GitBook

    GitBook 使您的团队可以轻松编写和维护高质量的文档。 分享知识,提高团队的工作效率,让用户满意。

    3 引用 • 8 回帖
  • NGINX

    NGINX 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 NGINX 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,第一个公开版本 0.1.0 发布于 2004 年 10 月 4 日。

    315 引用 • 547 回帖
  • TensorFlow

    TensorFlow 是一个采用数据流图(data flow graphs),用于数值计算的开源软件库。节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)。

    20 引用 • 19 回帖
  • 深度学习

    深度学习(Deep Learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。

    53 引用 • 40 回帖
  • ngrok

    ngrok 是一个反向代理,通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道。

    7 引用 • 63 回帖 • 645 关注
  • 30Seconds

    📙 前端知识精选集,包含 HTML、CSS、JavaScript、React、Node、安全等方面,每天仅需 30 秒。

    • 精选常见面试题,帮助您准备下一次面试
    • 精选常见交互,帮助您拥有简洁酷炫的站点
    • 精选有用的 React 片段,帮助你获取最佳实践
    • 精选常见代码集,帮助您提高打码效率
    • 整理前端界的最新资讯,邀您一同探索新世界
    488 引用 • 384 回帖 • 5 关注
  • 工具

    子曰:“工欲善其事,必先利其器。”

    295 引用 • 750 回帖
  • Hadoop

    Hadoop 是由 Apache 基金会所开发的一个分布式系统基础架构。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。

    88 引用 • 122 回帖 • 622 关注
  • 百度

    百度(Nasdaq:BIDU)是全球最大的中文搜索引擎、最大的中文网站。2000 年 1 月由李彦宏创立于北京中关村,致力于向人们提供“简单,可依赖”的信息获取方式。“百度”二字源于中国宋朝词人辛弃疾的《青玉案·元夕》词句“众里寻他千百度”,象征着百度对中文信息检索技术的执著追求。

    63 引用 • 785 回帖 • 109 关注
  • OnlyOffice
    4 引用 • 24 关注
  • Vditor

    Vditor 是一款浏览器端的 Markdown 编辑器,支持所见即所得、即时渲染(类似 Typora)和分屏预览模式。它使用 TypeScript 实现,支持原生 JavaScript、Vue、React 和 Angular。

    366 引用 • 1842 回帖 • 1 关注
  • Caddy

    Caddy 是一款默认自动启用 HTTPS 的 HTTP/2 Web 服务器。

    12 引用 • 54 回帖 • 165 关注