apache poi 实现下拉框联动校验

news2024/11/26 2:49:38

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);
    }
  1. 将数据放入隐藏 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++;
        }
  1. 在主 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);
  1. 设置联动下拉框 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);
  1. 完整代码如下:
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>

运行截图:

​​运行截图

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

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

相关文章

LabVIEW扫描探针显微镜系统

开发了一套基于LabVIEW软件开发的扫描探针显微镜系统。该系统专为微观尺度材料的热性能测量而设计&#xff0c;特别适用于纳米材料如石墨烯、碳纳米管等的研究。系统通过LabVIEW编程实现高精度的表面形貌和热性能测量&#xff0c;广泛应用于科研和工业领域。 项目背景 随着纳…

【Python】强大的正则表达式工具:re模块详解与应用

强大的正则表达式工具&#xff1a;re模块详解与应用 在编程和数据处理中&#xff0c;字符串的处理是不可避免的一项任务。无论是从文本中提取信息、验证数据格式&#xff0c;还是进行复杂的替换操作&#xff0c;正则表达式&#xff08;Regular Expression&#xff0c;简称Rege…

Redis数据库测试和缓存穿透、雪崩、击穿

Redis数据库测试实验 实验要求 1.新建一张user表&#xff0c;在表内插入10000条数据。 2.①通过jdbc查询这10000条数据&#xff0c;记录查询时间。 ②通过redis查询这10000条数据&#xff0c;记录查询时间。 3.①再次查询这一万条数据&#xff0c;要求根据年龄进行排序&#…

今天要重新认识下注解@RequestBody

在Spring框架中&#xff0c;RequestBody是一个常用的注解&#xff0c;它用于将HTTP请求体中的数据绑定到控制器&#xff08;Controller&#xff09;处理方法的参数上。这个注解通常与RESTful Web服务一起使用&#xff0c;在处理POST或PUT请求时尤为常见&#xff0c;因为这些请求…

在vscode中如何利用git 查看某一个文件的提交记录

在 Visual Studio Code (VSCode) 中&#xff0c;你可以使用内置的 Git 集成来查看某个文件的提交历史。以下是具体步骤&#xff1a; 使用 VSCode 内置 Git 功能 打开项目&#xff1a; 打开你的项目文件夹&#xff0c;确保该项目已经是一个 Git 仓库&#xff08;即项目根目录下…

JavaScript 23种经典设计模式简介

23种JavaScript经典设计模式 JavaScript经典设计模式 通过之前的学习&#xff0c;我们知道设计模式是一种解决代码组织、代码复用和代码可维护性等问题的技术方法。它通过将代码以特定的方式组织起来&#xff0c;使代码结构更加清晰、可读性更高、易于维护和扩展。为了在开发…

LangChain Ollama实战文献检索助手(二)少样本提示FewShotPromptTemplate示例选择器

本期是用样例来提示大模型生成我们想要的答案。即在输入中给定提示的样例&#xff0c;以及提示模板&#xff0c;然后匹配较相关的样例进行文献综述。 创建示例样本FewShotPromptTemplate 这里我用GTP-o1生成了几个回答&#xff0c;作为样本 samples [{"theme": &…

R语言*号标识显著性差异判断组间差异是否具有统计意义

前言 该R代码用于对Iris数据集进行多组比较分析&#xff0c;探讨不同鸢尾花品种在不同测量变量&#xff08;花萼和花瓣长度与宽度&#xff09;上的显著性差异。通过将数据转换为长格式&#xff0c;并利用ANOVA和Tukey检验&#xff0c;代码生成了不同品种间的显著性标记&#x…

AUTOSAR CP NVRAM Manager规范导读

一、NVRAM Manager功能概述 NVRAM Manager是AUTOSAR(AUTomotive Open System ARchitecture)框架中的一个模块,负责管理非易失性随机访问存储器(NVRAM)。它提供了一组服务和API,用于在汽车环境中存储、维护和恢复NV数据。以下是NVRAM Manager的一些关键功能: 数据存储和…

PDF编辑工具Adobe Acrobat DC 2023安装教程(附安装包)

Adobe Acrobat DC 2023 是 Adobe 公司推出的一款功能强大的 PDF 文档处理软件。它不仅支持创建、编辑和签署 PDF 文件&#xff0c;还提供了丰富的工具来管理和优化这些文件。以下是 Acrobat DC 2023 的一些主要特点&#xff1a; 1.PDF 创建与编辑&#xff1a;用户可以直接从多…

Tornado简单使用

Tornado简单使用 1 介绍 Tornado 是一个基于Python的Web服务框架和 异步网络库&#xff0c;它最初由 FriendFeed 开发&#xff0c;后来被 Facebook 收购并开源&#xff0c;通过利用非阻塞网络 I/O, Tornado 可以承载成千上万的活动连接&#xff0c;完美的实现了 长连接、WebS…

基于SpringBoot的城镇保障性住房管理策略

3系统分析 3.1可行性分析 通过对本城镇保障性住房管理系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本城镇保障性住房管理系统采用SSM框架&#xff0c;JA…

【万字详解】如何在微信小程序的 Taro 框架中设置静态图片 assets/image 的 Base64 转换上限值

设置方法 mini 中提供了 imageUrlLoaderOption 和 postcss.url 。 其中&#xff1a; config.limit 和 imageUrlLoaderOption.limit 服务于 Taro 的 MiniWebpackModule.js &#xff0c; 值的写法要 &#xff08;&#xff09;KB * 1024。 config.maxSize 服务于 postcss-url 的…

[实战-11] FlinkSql 设置时区对TIMESTAMP和TIMESTAMP_LTZ的影响

table.local-time-zone table.local-time-zoneDataStream-to-Table Conversion&#xff08;拓展知识&#xff09;代码测试flinksql代码执行结果截图1. Asia/Shanghai 结果如下2. UTC结果如下 table.local-time-zone table.local-time-zone可用于设置flinksql的时区。 flink的内…

Bypassuac之白名单结合注册表方式

参考 Bypass UAC 原来这么简单 本章记录一下系统白名单文件结合注册表bypassuac&#xff0c;uac这个东西并不是Windows设置的防御机制而是相当于保护机制&#xff0c;只是用来控制用户行为的&#xff0c;弹个窗来提醒一下用户的行为&#xff0c;和直接的杀软是不一样的性质&am…

【力扣打卡系列】单调栈

坚持按题型打卡&刷&梳理力扣算法题系列&#xff0c;语言为go&#xff0c;Day20 单调栈 题目描述 解题思路 单调栈 后进先出 记录的数据加在最上面丢掉数据也先从最上面开始 单调性 记录t[i]之前会先把所有小于等于t[i]的数据丢掉&#xff0c;不可能出现上面大下面小的…

如何通过CDN加速提升电商网站双十一购物节用户体验

随着双十一购物节的到来&#xff0c;电商平台迎来了一年中流量的高峰。各大电商平台如天猫、京东和抖音等纷纷推出了全新的促销活动和玩法。在这场购物狂欢中&#xff0c;用户体验成为了电商网站能否脱颖而出的关键。而CDN&#xff08;内容分发网络&#xff09;加速服务&#x…

Linux信号_信号的产生

信号概念 信号是进程之间事件异步通知的一种方式&#xff0c;属于软中断。 异步&#xff1a;在异步操作中&#xff0c;任务可以独立执行。一个任务的开始或完成不依赖于其他任务的状态。 同步&#xff1a;在同步操作中&#xff0c;任务之间的执行是相互依赖的。一个任务必须等待…

Docker学习—Docker核心概念总结

核心概念总结 容器&#xff1a;容器就是将应用运行所需的所有内容比如代码、运行时环境&#xff0c;进行打包和隔离。 容器和虚拟机的对比 虚拟机是在同一个硬件上虚拟化出多个操作系统&#xff08;OS&#xff09;实例。 容器是在操作系统上进行虚拟化&#xff0c;用于隔离…

51单片机教程(六)- LED流水灯

1 项目分析 基于点亮LED灯、LED灯闪烁&#xff0c;扩展到构成最简单、花样流水灯。 2 技术准备 1 流水灯硬件及原理图 流水灯是由多个LED灯组成的 2 C语言知识点 数组 数组声明&#xff1a;长度不可变 数据类型 数组名称[长度n] // 整数型默认为0&#xff0c;小数型默认…