poi中导入excel时,获取下拉选项、解析从子表引用的下拉选项

我们导入excel表,解析数据时,有的时候需要把单元格是下拉框的所有下拉项拿到,有的下拉项是直接在单元格里面添加的下拉列表,还有的下拉项则是从其它表引用过来的,如下图:

在这里插入图片描述

在这里插入图片描述

那我们要怎么读取这两种不同方式添加的下拉列表数据呢?

如果是在当前表的单元格里添加的下拉列表,获取方式则比较简单,poi有专门的方法可以拿到指定sheet的所有下拉列表。

如果是从别的表引用过来的,则比较麻烦,poi那个方法拿到的被引用过来的下拉列表,拿到的并不是那些下拉项,而是范围区域字符串。例如:Sheet1!$A$1:$A$3Sheet1!$F$1:$F$4Sheet1!$B$1:$E$1 是这样的字符串,这个时候就需要我们自己解析这串字符,并根据范围去取数据。

实现

/**
 * 获取下拉项
 */
public static Map<Integer,String> getSelectOption(Workbook workbook,Sheet sheet){
    Map<Integer,String> validations = new HashMap<>(); // 是下拉框的字段的列索引和下拉项(key为列索引,value为下拉项)
    // 通过正则表达式来解析引用的范围,获得被引用的sheet名和单元格范围
    // 这个正则表达式可以匹配包含中文、数字、字母、下划线的sheet名,但是不允许包含空格和其它特殊字符
    Pattern pattern = Pattern.compile("([^\\/:\\?\\*\\[\\]\\']+)!\\$(\\w+)\\$(\\d+)\\:\\$(\\w+)\\$(\\d+)");
    //DataValidationHelper validationHelper = sheet.getDataValidationHelper();
    // 获取下拉框数据
    for (DataValidation validation : sheet.getDataValidations()) {
        DataValidationConstraint constraint = validation.getValidationConstraint();
        CellRangeAddress cellRangeAddress = validation.getRegions().getCellRangeAddress(0);
        String selectOption = constraint.getFormula1().replaceAll("\"", "");
        Matcher matcher = pattern.matcher(selectOption);
        if (matcher.find()) {
            selectOption = selectOption(workbook,matcher,selectOption);
        }
        System.out.println("下拉数据:" + selectOption);
        validations.put(cellRangeAddress.getFirstColumn(),selectOption);
    }
    return headers;
}

/**
 * 解析子表引用的下拉选项
 */
public static String selectOption(Workbook workbook,Matcher matcher,String selectOption){
    String sheetName = matcher.group(1); // 被引用的sheet名称
    String startColumnName = matcher.group(2); // 开始的列名
    int startRowNum = Integer.parseInt(matcher.group(3)); // 开始的行号
    String endColumnName = matcher.group(4); // 结束的列名
    int endRowNum = Integer.parseInt(matcher.group(5)); // 结束的行号

    List<String> options = new ArrayList<>();
    Sheet child = workbook.getSheet(sheetName);
    if (startColumnName.equals(endColumnName)){ // 同一列不同行
        int colIndex = columnIndexFromName(startColumnName); // 获取列索引
        for (int rowNum = startRowNum - 1; rowNum < endRowNum; rowNum++) {
            Row row = child.getRow(rowNum);
            if (row != null) {
                Cell cell = row.getCell(colIndex);
                options.add(getCellValue(cell));
            }
        }
    }else if (!startColumnName.equals(endColumnName) && startRowNum == endRowNum){ // 同一行不同列
        Row row = child.getRow(startRowNum - 1); // 获取行索引
        int startColIndex = columnIndexFromName(startColumnName); // 获取开始的列索引
        int endColIndex = columnIndexFromName(endColumnName); // 获取结束的列索引
        for (int col = startColIndex; col <= endColIndex; col++) {
            Cell cell = row.getCell(col);
            options.add(getCellValue(cell));
        }
    }else {
        throw new ExceptionVo(-1,"下拉项的子表引用【 " + selectOption + " 】无法解析");
    }
    return StrUtil.join(",",options);
}

/**
 * 根据列名获取列索引
 */
public static int columnIndexFromName(String columnName) {
    int sum = 0;
    for (char ch : columnName.toCharArray()) {
        sum = sum * 26 + (ch - 'A' + 1);
    }
    return sum - 1; // 因为索引是从0开始的,而Excel的列名是从1开始的"感觉"
}

/**
 * 获取单元格的值
 */
public static String getCellValue(Cell cell){
    String cellValue = "";
    if (cell != null){
        switch (cell.getCellType()) {
            case STRING:
                cellValue = cell.getStringCellValue();
                break;
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    // 处理日期类型
                    Date dateValue = cell.getDateCellValue();
                    // 这里你可以根据需要将日期转换为字符串或其他格式
                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    cellValue = dateFormat.format(dateValue);
                } else {
                    cell.setCellType(CellType.STRING); // 将单元格内容以字符串形式获取
                    // 处理数值类型
                    //double numericValue = cell.getNumericCellValue();
                    //cellValue = String.valueOf(numericValue);
                    cellValue = cell.getStringCellValue();
                }
                break;
            // 其他类型的单元格可以根据需要进一步处理
            case BOOLEAN:
                cellValue = String.valueOf(cell.getBooleanCellValue());
                break;
            case BLANK:
                // 处理空单元格
                cellValue = "";
                break;
            default:
                // 处理其他类型的单元格
                throw new ExceptionVo(-1,"不支持的单元格类型");
        }
    }
    return cellValue;
}

获取结果

在这里插入图片描述

这样我们就可以完美获取这些下拉数据啦

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

符华-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值