You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Apache POI将列数动态增加的Excel文件转换为Java对象

处理动态列Excel转Java对象(Apache POI实现)

嘿,这个场景我太熟了——固定实体类根本扛不住动态增加的列,得换个灵活的思路。下面给你两个实用的方案,都是基于Apache POI来实现的:

方案一:用Map<String, Object>存储每行数据(最简单直接)

这种方式不用定义任何实体类,直接用Map的键对应Excel列名,值对应单元格内容,非常适合快速开发。

核心步骤:

  1. 先读取Excel的表头行,把所有列名存成一个列表;
  2. 遍历后续的每一行数据,把每个单元格的值和对应的列名绑定到Map中;
  3. 处理不同类型的单元格(字符串、数字、日期等),避免类型转换错误。

代码示例:

import org.apache.poi.ss.usermodel.*;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DynamicExcelReader {
    public static void main(String[] args) throws Exception {
        String filePath = "your-dynamic-excel.xlsx";
        List<Map<String, Object>> dataList = readDynamicExcel(filePath);
        
        // 打印测试
        for (Map<String, Object> row : dataList) {
            System.out.println(row);
        }
    }

    public static List<Map<String, Object>> readDynamicExcel(String filePath) throws Exception {
        List<Map<String, Object>> result = new ArrayList<>();
        Workbook workbook = WorkbookFactory.create(new FileInputStream(filePath));
        Sheet sheet = workbook.getSheetAt(0);

        // 第一步:读取表头列名
        Row headerRow = sheet.getRow(0);
        List<String> columnNames = new ArrayList<>();
        for (Cell cell : headerRow) {
            columnNames.add(cell.getStringCellValue().trim());
        }

        // 第二步:遍历数据行
        for (int i = 1; i <= sheet.getLastRowNum(); i++) {
            Row dataRow = sheet.getRow(i);
            if (dataRow == null) continue;

            Map<String, Object> rowMap = new HashMap<>();
            for (int j = 0; j < columnNames.size(); j++) {
                Cell cell = dataRow.getCell(j, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
                rowMap.put(columnNames.get(j), getCellValue(cell));
            }
            result.add(rowMap);
        }

        workbook.close();
        return result;
    }

    // 处理不同类型的单元格值
    private static Object getCellValue(Cell cell) {
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue().trim();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue();
                } else {
                    // 处理数字,避免变成科学计数法
                    double numericValue = cell.getNumericCellValue();
                    if (numericValue == (long) numericValue) {
                        return (long) numericValue;
                    }
                    return numericValue;
                }
            case BOOLEAN:
                return cell.getBooleanCellValue();
            case FORMULA:
                return cell.getCellFormula();
            default:
                return null;
        }
    }
}

方案二:自定义动态实体类(更贴近面向对象)

如果觉得Map不够“像对象”,可以封装一个通用的DynamicEntity类,内部用Map存储属性,对外提供类似实体类的get/set方法,用起来更顺手。

自定义DynamicEntity类:

import java.util.HashMap;
import java.util.Map;

public class DynamicEntity {
    private final Map<String, Object> properties = new HashMap<>();

    public void setProperty(String key, Object value) {
        properties.put(key, value);
    }

    public Object getProperty(String key) {
        return properties.get(key);
    }

    // 可以加泛型方法,方便类型转换
    @SuppressWarnings("unchecked")
    public <T> T getProperty(String key, Class<T> clazz) {
        return (T) properties.get(key);
    }

    @Override
    public String toString() {
        return properties.toString();
    }
}

读取Excel并转换为DynamicEntity列表:

只需要把方案一中的Map<String, Object>替换成DynamicEntity即可,修改部分代码:

// 遍历数据行时替换成:
DynamicEntity entity = new DynamicEntity();
for (int j = 0; j < columnNames.size(); j++) {
    Cell cell = dataRow.getCell(j, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
    entity.setProperty(columnNames.get(j), getCellValue(cell));
}
result.add(entity);

使用示例:

// 获取某个属性并转成指定类型
String name = entity.getProperty("name", String.class);
Long empId = entity.getProperty("empId", Long.class);

注意事项

  • 要确保Excel的表头行是第一行,如果表头位置变化,记得调整代码中sheet.getRow(0)的索引;
  • 处理空行:代码中已经判断dataRow == null时跳过,避免空指针;
  • 单元格类型处理:一定要覆盖所有可能的类型(字符串、数字、日期、布尔值等),不然容易出现类型转换异常。

内容的提问来源于stack exchange,提问作者Ankit Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:24:39