1. 简介

数据映射是软件开发中的核心技能。Excel作为广泛使用的数据管理工具,掌握Java对象与Excel数据的转换对开发者至关重要。

本教程将探讨如何将Excel数据转换为Java对象列表。

Maven仓库中提供了多个处理Excel文件的Java库,其中Apache POI最为常用。但**我们将使用四个库实现转换:Apache POI、Poiji、FastExcel和JExcelApi (Jxl)**。

2. 模型准备

首先需要创建对象蓝图——FoodInfo类:

public class FoodInfo {

    private String category; 
    private String name; 
    private String measure;
    private double calories; 
   
    // 标准构造方法、toString、getter和setter
}

3. Apache POI

Apache POI (Poor Obfuscation Implementation) 是处理Microsoft文档的Java API。它是一套纯Java库,用于读写Microsoft Office文件(如Word、Outlook、Excel等)。

3.1. Maven依赖

Maven依赖添加到pom.xml

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>5.2.5</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.2.5</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-schemas</artifactId>
    <version>4.1.2</version>
</dependency>

3.2. 转换Excel数据为对象列表

通过Workbook接口可以访问Excel文件的sheet和单元格。该接口有两个实现类:HSSFWorkbook处理.xls文件,XSSFWorkbook处理.xlsx文件

以下代码使用Apache POI将.xlsx文件转换为FoodInfo对象列表:

public static List<FoodInfo> excelDataToListOfObjets_withApachePOI(String fileLocation)
  throws IOException {
    FileInputStream file = new FileInputStream(new File(fileLocation));
    Workbook workbook = new XSSFWorkbook(file);
    Sheet sheet = workbook.getSheetAt(0);
    List<FoodInfo> foodData = new ArrayList<FoodInfo>();
    DataFormatter dataFormatter = new DataFormatter();
    for (int n = 1; n < sheet.getPhysicalNumberOfRows(); n++) {
        Row row = sheet.getRow(n);
        FoodInfo foodInfo = new FoodInfo();
        int i = row.getFirstCellNum();

        foodInfo.setCategory(dataFormatter.formatCellValue(row.getCell(i)));
        foodInfo.setName(dataFormatter.formatCellValue(row.getCell(++i)));
        foodInfo.setMeasure(dataFormatter.formatCellValue(row.getCell(++i)));
        foodInfo.setCalories(row.getCell(++i).getNumericCellValue());
       
        foodData.add(foodInfo);
    }
    return foodData;
}

使用getPhysicalNumberOfRows()方法获取非空行数。循环时跳过标题行(i = 1)。

根据字段类型,使用dataFormattergetNumericValue()方法转换单元格值

通过单元测试验证代码(使用food_info.xlsx文件):

Apache POI支持新旧Excel格式(.xls.xlsx

4. Poiji

Poiji是线程安全的Java库,提供Excel到Java类的单向映射API。它基于Apache POI构建,但使用更简单,可直接将Excel行转换为Java对象。

4.1. 设置Maven依赖

添加Poiji依赖pom.xml

<dependency>
    <groupId>com.github.ozlerhakan</groupId>
    <artifactId>poiji</artifactId>
    <version>4.1.1</version>
</dependency>

4.2. 使用注解配置类

Poiji通过@ExcelCellName(String cellName)@ExcelCell(int cellIndex)注解简化数据映射

FoodInfo类添加注解:

public class FoodInfo { 
    
    @ExcelCellName("Category") 
    private String category; 
    
    @ExcelCellName("Name") 
    private String name;
 
    @ExcelCellName("Measure") 
    private String measure;
 
    @ExcelCellName("Calories") 
    private double calories;
 
    // 标准构造方法、getter和setter 
}

API支持多sheet工作簿。使用@ExcelSheet(String sheetName)注解指定目标sheet,其他sheet将被忽略。

未使用注解时,仅处理第一个sheet。

若需跳过特定行,添加@ExcelRow注解的private int rowIndex属性

4.3. 转换Excel数据为对象列表

Poiji默认忽略Excel标题行

以下代码将Excel文件转换为FoodInfo列表:

public class ExcelDataToListOfObjectsPOIJI {
    public static List<FoodInfo> excelDataToListOfObjets_withPOIJI(String fileLocation){
        return Poiji.fromExcel(new File(fileLocation), FoodInfo.class);
    }
}

程序将首个sheet转换为FoodInfo对象列表,每行对应一个对象,单元格值映射为属性。列表大小等于非标题行数。

处理加密Excel时,通过PoijiOptionsBuilder设置密码:

PoijiOptions options = PoijiOptionsBuilder.settings()
  .password("excel123").build();
List<FoodInfo> foodData = Poiji.fromExcel(new File(fileLocation), FoodInfo.class, options);

单元测试验证:

@Test
public void whenParsingExcelFileWithPOIJI_thenConvertsToList() throws IOException {
    List<FoodInfo> foodInfoList = 
      ExcelDataToListOfObjectsPOIJI
        .excelDataToListOfObjets_withPOIJI("src\\main\\resources/food_info.xlsx");

    assertEquals("Beverages", foodInfoList.get(0).getCategory());
    assertEquals("Dairy", foodInfoList.get(3).getCategory());
}

5. FastExcel

FastExcel是高效低内存的库,专为Java中创建和读取基础Excel工作簿设计。仅支持.xlsx格式,功能少于Apache POI

仅读取单元格内容,不支持图表、样式等格式。

5.1. 设置Maven依赖

添加FastExcelFastExcel Reader依赖:

5.2. 转换Excel数据为对象列表

处理大文件时,FastExcel是理想选择(尽管功能有限)通过ReadableWorkbook类访问整个工作簿

可按名称或索引获取sheet。

以下代码将Excel数据转换为FoodInfo列表:

public static List<FoodInfo> excelDataToListOfObjets_withFastExcel(String fileLocation)
   throws IOException, NumberFormatException {
    List<FoodInfo> foodData = new ArrayList<FoodInfo>();

    try (FileInputStream file = new FileInputStream(fileLocation);
      ReadableWorkbook wb = new ReadableWorkbook(file)) {
        Sheet sheet = wb.getFirstSheet();
        for (Row row: sheet.read()) {
            if (row.getRowNum() == 1) {
                continue;
            }
            FoodInfo food = new FoodInfo();
            food.setCategory(row.getCellText(0));
            food.setName(row.getCellText(1));
            food.setMeasure(row.getCellText(2));
            food.setCalories(Double.parseDouble(row.getCellText(3)));
            
            foodData.add(food);
        }
    }
    return foodData;
}

API读取所有行(包括标题行),需跳过第一行(非零基索引)。

访问单元格有两种方式:

  • 创建Cell对象:Cell cell = row.getCell(int cellIndex)row.getCell(String cellAddress)
  • 直接获取数据:row.getCellText()

提取内容后需转换为food对象的字段类型。

单元测试验证:

@Test
public void whenParsingExcelFileWithFastExcel_thenConvertsToList() throws IOException {
    List<FoodInfo> foodInfoList = ExcelDataToListOfObjectsFastExcel
      .excelDataToListOfObjets_withFastExcel("src\\main\\resources/food_info.xlsx");

    assertEquals("Beverages", foodInfoList.get(0).getCategory());
    assertEquals("Dairy", foodInfoList.get(3).getCategory());
}

6. JExcelApi (Jxl)

JExcelApi (Jxl) 是轻量级Java库,用于读写修改Excel电子表格

6.1. 设置Maven依赖

添加JExcelApi依赖pom.xml

<dependency>
    <groupId>net.sourceforge.jexcelapi</groupId>
    <artifactId>jxl</artifactId>
    <version>2.6.12</version>
</dependency>

6.2. 转换Excel数据为对象列表

仅支持旧版Excel格式(.xlsWorkbook类用于访问sheet列表。

以下代码将.xls文件转换为FoodInfo列表:

public static List<FoodInfo> excelDataToListOfObjets_withJxl(String fileLocation) 
  throws IOException, BiffException {

    List<FoodInfo> foodData = new ArrayList<FoodInfo>();

    Workbook workbook = Workbook.getWorkbook(new File(fileLocation));
    Sheet sheet = workbook.getSheet(0);

    int rows = sheet.getRows();

    for (int i = 1; i < rows; i++) {
        FoodInfo foodInfo = new FoodInfo();

        foodInfo.setCategory(sheet.getCell(0, i).getContents());
        foodInfo.setName(sheet.getCell(1, i).getContents());
        foodInfo.setMeasure(sheet.getCell(2, i).getContents());
        foodInfo.setCalories(Double.parseDouble(sheet.getCell(3, i).getContents()));
        
        foodData.add(foodInfo);

    }
    return foodData;
}

库不忽略标题行,需从i = 1开始循环。sheet对象是零基索引的行列表。

JExcel的单元格访问与FastExcel类似,都使用getCell()方法。但JExcel直接从Sheet对象调用,且方法接受colNumrowNum两个整数参数:sheet.getCell(colNum, rowNum)

单元测试验证:

@Test
public void whenParsingExcelFileWithJxl_thenConvertsToList()
  throws IOException, BiffException {
    List<FoodInfo> foodInfoList = ExcelDataToListOfObjectsJxl
      .excelDataToListOfObjets_withJxl("src\\main\\resources/food_info.xls");

    assertEquals("Beverages", foodInfoList.get(0).getCategory());
    assertEquals("Dairy", foodInfoList.get(3).getCategory());
}

7. 总结

本文探讨了使用Apache POI、Poiji、FastExcel和JExcelApi将Excel数据转换为Java对象的方法。选择库需根据具体需求权衡利弊:

Poiji:最简单直接的转换方案
⚠️ FastExcel/Jxl:高性能双向映射,但功能有限
Apache POI:功能最全(支持样式/图表),但较复杂

完整源代码见GitHub仓库


原始标题:How To Convert Excel Data Into List Of Java Objects | Baeldung