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

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