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>

运行截图:

​​

相关推荐
前行的小黑炭27 分钟前
设计模式:为什么使用模板设计模式(不相同的步骤进行抽取,使用不同的子类实现)减少重复代码,让代码更好维护。
android·java·kotlin
Java技术小馆32 分钟前
如何设计一个本地缓存
java·面试·架构
XuanXu1 小时前
Java AQS原理以及应用
java
风象南4 小时前
SpringBoot中6种自定义starter开发方法
java·spring boot·后端
mghio13 小时前
Dubbo 中的集群容错
java·微服务·dubbo
咖啡教室18 小时前
java日常开发笔记和开发问题记录
java
咖啡教室18 小时前
java练习项目记录笔记
java
鱼樱前端19 小时前
maven的基础安装和使用--mac/window版本
java·后端
RainbowSea19 小时前
6. RabbitMQ 死信队列的详细操作编写
java·消息队列·rabbitmq