我们导入excel表,解析数据时,有的时候需要把单元格是下拉框的所有下拉项拿到,有的下拉项是直接在单元格里面添加的下拉列表,还有的下拉项则是从其它表引用过来的,如下图:
那我们要怎么读取这两种不同方式添加的下拉列表数据呢?
如果是在当前表的单元格里添加的下拉列表,获取方式则比较简单,poi有专门的方法可以拿到指定sheet的所有下拉列表。
如果是从别的表引用过来的,则比较麻烦,poi那个方法拿到的被引用过来的下拉列表,拿到的并不是那些下拉项,而是范围区域字符串。例如:Sheet1!$A$1:$A$3
、Sheet1!$F$1:$F$4
、Sheet1!$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;
}
获取结果
这样我们就可以完美获取这些下拉数据啦