Apache POI学习总结,Excel数据的导入与导出

该部分学习代码托管地址:https://gitee.com/imdongrui/study-poi

简介

Apache POI是一个用于支持Java程序操作Excel文件的jar包

从maven引入

<!--必须要引入的包-->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>4.1.2</version>
</dependency>
<!--需要操作XSSFWorkbook,即xlsx时,需要引入poi-ooxml-->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.1.2</version>
</dependency>

导出Excel文件

实现步骤

使用poi导出Excel文件我们可以将其分为三个步骤:

  1. 创建工作簿实例,工作簿实例即对应一个Excel文件;
  2. 创建Sheet工作表,并向工作表中写入数据;
  3. 输出Excel文件到指定位置;

我们将这几个步骤体现到代码中:

1 创建工作簿实例

在创建时需要注意,Workbook有两种,分别是org.apache.poi.hssf.usermodel.HSSFWorkbook与org.apache.poi.xssf.usermodel.XSSFWorkbook,其中org.apache.poi.xssf.usermodel.HSSFWorkbook对应的是Office97-2003的早期Excel版本,org.apache.poi.xssf.usermodel.XSSFWorkbook对应的是Excel 2007以上的版本

不能简单地理解为HSSFWorkbook对应xls,XSSFWorkbook对应xlsx,因为单纯通过后缀不足以判断一个Excel文件是什么版本的,因为Excel在打开表格文件时,并没有严格要求后缀与版本对应,即使版本与后缀不对应,仍然可以打开使用,但却会影响poi的解析,这在程序开发时需要注意

/**
 * 生成工作簿实例
 *
 * @return 工作簿实例
 */
public static Workbook createExcel() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
    return (Workbook) Class.forName("org.apache.poi.hssf.usermodel.HSSFWorkbook").newInstance();
}

2 创建Sheet并写入数据

/**
 * 创建工作表,多个Sheet则调用此函数多次
 *
 * @param sheetName 工作表名称,若传null,则使用默认的名称
 * @param titles    表头
 * @param dataSet   数据集
 * @param workbook  工作簿实例
 * @return 工作表实例
 */
public static Sheet createSheet(String sheetName, String[] titles, String[][] dataSet, Workbook workbook) {
    // 创建Sheet实例
    Sheet sheet = null == sheetName ? workbook.createSheet() : workbook.createSheet(sheetName);
    // 创建表头行,并依次向表头行的表格写入表头数据
    Row row = sheet.createRow(0);// 创建数据航
    for (int i = 0; i < titles.length; i++) {
        Cell cell = row.createCell(i);// 创建单元格
        cell.setCellValue(titles[i]);// 写入数据
    }
    // 循环写入数据集中的数据
    int rows = dataSet.length;
    int cols = dataSet[0].length;
    // 依次处理数据行
    for (int rowNum = 0; rowNum < rows; rowNum++) {
        Row tmpRow = sheet.createRow(rowNum + 1);//因为表头行占用一行,此处+1
        // 依次处理数据列
        for (int colNum = 0; colNum < cols; colNum++) {
            Cell cell = tmpRow.createCell(colNum);
            cell.setCellValue(dataSet[rowNum][colNum]);
        }
    }
    return sheet;
}

3 输出Excel文件到指定路径

/**
 * 输出Excel文件到指定路径
 *
 * @param filePath 输出路径(含文件名)
 * @param workbook 当前工作簿实例
 */
public static void outputExcel(String filePath, Workbook workbook) throws IOException {
    OutputStream outputStream = new FileOutputStream(filePath);
    try {
        workbook.write(outputStream);
    } finally {
        outputStream.close();
    }
}

完整调用步骤

通过下面的调用步骤,可以在指定路径下创建一个test.xls文件,并写入我们需要的数据

String[] headers = {"编号", "姓名", "班级", "入学时间"};
// students是一个Student列表,Student是一个简单的数据对象
String[][] dataSet = ExcelUtils.list2Matrix(students, Student.class);
Workbook workbook = ExcelUtils.createExcel();
// 此处创建两个Sheet
ExcelUtils.createSheet("student", headers, dataSet, workbook);
ExcelUtils.createSheet("student2", headers, dataSet, workbook);
ExcelUtils.outputExcel("D:\\test.xls", workbook);

辅助函数

list2Matrix

/**
 * 将数据对象的List转换为字符串的二维数组
 *
 * @param data   数据对象的List
 * @param tClass 数据对象的class
 * @param <T>    数据对象
 * @return 二维数组
 */
public static <T> String[][] list2Matrix(List<T> data, Class<T> tClass) throws IllegalAccessException {
    Field[] fields = tClass.getDeclaredFields();
    String[][] dataSet = new String[data.size()][fields.length];
    // 依次处理列表中的对象
    for (int i = 0, len = data.size(); i < len; i++) {
        T t = data.get(i);
        // 依次获取对象声明的字段值,并存入dataSet中
        for (int j = 0; j < fields.length; j++) {
            fields[j].setAccessible(true);
            Object value = fields[j].get(t);
            // 对Date类型的数据进行处理,其它类型数据有处理需求也可在此添加处理逻辑
            if (value instanceof Date) {
                value = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(value);
            }
            dataSet[i][j] = value.toString();
        }
    }
    return dataSet;
}

导入Excel文件中的数据

实现步骤

导入Excel文件中的数据也可以分为两个步骤:

  1. 导入Excel文件并生成Workbook实例;
  2. 读取Sheet中的数据,多个Sheet则多次读取;

下面将步骤反映到代码中:

1 导入并生成工作簿实例

public enum ExcelType {
    HSSF("org.apache.poi.hssf.usermodel.HSSFWorkbook"),
    XSSF("org.apache.poi.xssf.usermodel.XSSFWorkbook");

    ExcelType(String className) {
        this.className = className;
    }

    private String className;


    public String getClassName() {
        return className;
    }
}
/**
 * 从指定路径下的文件创建工作簿实例
 * @param path Excel文件路径
 * @param type Excel文件的类型
 * @return 工作簿实例
 */
public static Workbook createWorkbook(String path, ExcelType type) throws IOException {
    // 创建文件输入流
    FileInputStream fileInputStream = new FileInputStream(path);
    // 根据Excel文件的类型,生成对应的工作簿实例
    switch (type) {
        case HSSF:
            return new HSSFWorkbook(fileInputStream);
        case XSSF:
            return new XSSFWorkbook(fileInputStream);
        default:
            throw new RuntimeException();
    }
}

2 从Sheet中读取数据

/**
 * 读取Sheet中的数据
 * @param workbook 工作簿实例
 * @param sheetNo 要读取的Sheet编号
 * @param tClass 目标数据对象的class
 * @param <T> 目标数据对象
 * @return 读取出来的目标数据对象列表
 */
public static <T> List<T> readSheet(Workbook workbook, int sheetNo, Class<T> tClass) throws IllegalAccessException, InstantiationException, ParseException {
    List<T> list = new ArrayList<>();
    // 获取指定的Sheet实例
    Sheet sheet = workbook.getSheetAt(sheetNo);
    Field[] fields = tClass.getDeclaredFields();
    // 跳过表头,从第一行数据开始解析,sheet.getPhysicalNumberOfRows()获取当前Sheet中数据总行数
    for (int i = 1, rowCount = sheet.getPhysicalNumberOfRows(); i < rowCount; i++) {
        Row row = sheet.getRow(i);// 获取指定行
        T t = tClass.newInstance();
        // 解析每行数据,row.getPhysicalNumberOfCells()获取当前行下单元格总数
        for (int j = 0, cellCount = row.getPhysicalNumberOfCells(); j < cellCount; j++) {
            Cell cell = row.getCell(j);// 获取指定单元格
            String strValue = cell.getStringCellValue();
            fields[j].setAccessible(true);
            Class<?> fieldClass = fields[j].getType();
            // 按照各个字段类型,处理赋值
            if (fieldClass == Integer.class || fieldClass == int.class) {
                fields[j].setInt(t, Integer.parseInt(strValue));
            } else if (fieldClass == Boolean.class || fieldClass == boolean.class) {
                fields[j].setBoolean(t, Boolean.parseBoolean(strValue));
            } else if (fieldClass == Double.class || fieldClass == double.class) {
                fields[j].setDouble(t, Double.parseDouble(strValue));
            } else if (fieldClass == String.class) {
                fields[j].set(t, strValue);
            } else if (fieldClass == Date.class) {
                fields[j].set(t, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(strValue));
            }
        }
        list.add(t);
    }
    return list;
}

完整调用步骤

Workbook workbook = ExcelUtils.createWorkbook("D:\\test.xlsx", ExcelType.XSSF);
List<Student> list = ExcelUtils.readSheet(workbook, 0, Student.class);
list.forEach(student -> System.out.println(student.toString()));

参考文章

Java架构-Apache POI Excel

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章