該部分學習代碼託管地址: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文件我們可以將其分爲三個步驟:
- 創建工作簿實例,工作簿實例即對應一個Excel文件;
- 創建Sheet工作表,並向工作表中寫入數據;
- 輸出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文件中的數據也可以分爲兩個步驟:
- 導入Excel文件並生成Workbook實例;
- 讀取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()));