apache poi 实现下拉框联动校验

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

‍

步骤如下:

  1. 创建一个隐藏 sheet
java 复制代码
 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
java 复制代码
        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 的数据
java 复制代码
    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
java 复制代码
 // 设置市下拉框  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. 完整代码如下:
java 复制代码
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 依赖

xml 复制代码
     <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>

运行截图:

​​

相关推荐
哦虎!4 小时前
【JavaEE】网络初识
java
for_ever_love__5 小时前
MySQL ORDER BY 排序优化:从 Using filesort 到索引有序扫描(含双路 / 单路排序原理)
java·mysql·优化·存储·by·order·filesort
我是人✓6 小时前
Java文件上传三方式对比:从传统到SpringBoot
java·开发语言
欣栀♡6 小时前
JVM 频繁 Full GC 先看日志括号里的 cause,jstat 的 FGC 在 JDK 8 上会骗人
java·jvm
IT研究室6 小时前
最新计算机毕业设计选题推荐-基于spring boot的葡萄酒文化宣传网站-网站-文档指导-Java-springboot
java·spring boot·课程设计
慧都小项6 小时前
MyEclipse 中创建和测试 JAX-RS REST 接口:从项目配置到 REST Explorer
java·restful·myeclipse·jax-rs
Wang's Blog6 小时前
Java 项目实战: 交友项目 - 入门案例:编写 Dubbo 服务提供者
java·dubbo·交友
秋饼7 小时前
Spring AI 2.0 结构化输出企业级实战:从 BeanOutputConverter 源码到生产级解析容错
java·ai·技术分享·后端开发
摇滚侠7 小时前
《计算机是如何工作的:人人都能懂的计算机软硬件工作原理》第 9 章 机器码与汇编语言 阅读笔记 9
java·开发语言·笔记
Cc.Y7 小时前
Java零基础入门:深入Java核心:文件IO与序列化全解
java·开发语言·python