能夠讀取Excel是JasperReports沒有的功能,今天就使用Apache POI來讀取Apache POI-寫入(匯出)Excel這篇所匯出的學生成績資料表。
create()
方法,能夠傳入File、Inputstream等等參數,就能輕鬆取得文件的Workbook。 不論要讀取的Excel是.xls還是.xlsx,不用寫判斷邏輯就可以拿到Workbook,充分顯示物件導向中多型的優點。下圖是學生成績資料表的資料:
我想將讀取到的欄位資料放到StudentCourseScoreReportModel這個物件中
@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentCourseScoreReportModel {
private String studentNumber;
private String fullName;
private String grade;
private String courseDesc;
private String departmentDesc;
private Integer score;
private String testDate;
}
步驟如下,第幾步可以對應註解來看:
getSheetAt()
取第一個,如果要寫得更通用一些可以用getNumberOfSheets()
取得sheet的數量再以for loop遍歷。getLastRowNum()
取得有內容的最後一列的index,只處理有資料的部分就好。getRow
取得Row,並且準備好StudentCourseScoreReportModel,在下面的步驟要放入Row中讀取到的資料。getCell()
取得Cell。public void readExcel(String filePath) {
// 1. 欄位名稱
String[] columnNames = {"學號", "科系", "年級", "姓名", "課程", "成績", "考試日期"};
List<StudentCourseScoreReportModel> modelList = new ArrayList<>();
try {
InputStream inputStream = Files.newInputStream(Paths.get(filePath));
// 2. 取得Workbook
Workbook workbook = WorkbookFactory.create(inputStream);
// 3. 取得sheet
Sheet sheet = workbook.getSheetAt(0);
if (sheet != null) {
// 4. 有內容的最後一列index
int lastRowNumber = sheet.getLastRowNum();
// 第1列為標題,從第2列開始讀取
for (int i = 2; i <= lastRowNumber; i++) {
// 5. 取得row
Row row = sheet.getRow(i);
StudentCourseScoreReportModel model = new StudentCourseScoreReportModel();
for (int j = 0; j < columnNames.length; j++) {
if (row != null) {
// 6. 取得cell
Cell cell = row.getCell(j);
if (cell == null) {
continue;
}
// 7. 按照欄位名稱取值,放入model
switch (columnNames[j]) {
case "學號":
if (cell.getCellType() == CellType.STRING) {
String studentNumber = cell.getStringCellValue();
if (studentNumber != null) {
model.setStudentNumber(studentNumber);
}
}
break;
case "科系":
if (cell.getCellType() == CellType.STRING) {
String departmentDesc = cell.getStringCellValue();
if (departmentDesc != null) {
model.setDepartmentDesc(departmentDesc);
}
}
break;
case "年級":
if (cell.getCellType() == CellType.STRING) {
String grade = cell.getStringCellValue();
if (grade != null) {
model.setGrade(grade);
}
}
break;
case "姓名":
if (cell.getCellType() == CellType.STRING) {
String fullName = cell.getStringCellValue();
if (fullName != null) {
model.setFullName(fullName);
}
}
break;
case "課程":
if (cell.getCellType() == CellType.STRING) {
String courseDesc = cell.getStringCellValue();
if (courseDesc != null) {
model.setCourseDesc(courseDesc);
}
}
break;
case "成績":
if (cell.getCellType() == CellType.NUMERIC) {
Double score = cell.getNumericCellValue();
if (score != null) {
model.setScore(score.intValue());
}
}
break;
case "考試日期":
if (cell.getCellType() == CellType.STRING) {
String testDate = cell.getStringCellValue();
if (testDate != null) {
model.setTestDate(testDate);
}
}
break;
default:
break;
}
}
}
modelList.add(model);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
執行到最後就能拿到List<StudentCourseScoreReportModel>
資料了
▲補充
Workbook介面有繼承Iterable<Sheet>
;Sheet介面有繼承Iterable<Row>
;Row介面有繼承Iterable<Cell>
。表示除了範例使用的遍歷方式外,可以直接以foreach遍歷資料。
Workbook workbook = WorkbookFactory.create(inputStream);
for (Sheet sheet : workbook) {
for (Row row : sheet) {
for (Cell cell : row) {
}
}
}
Apache POI讀取Excel比較繁瑣的部分就是判斷Cell中資料的型別或格式,如果要寫得更謹慎就要多一些例外處理,才能判斷日期或數字格式是否正確,不然cell.getNumericCellValue()
或cell.getDateCellValue()
都滿容易有Exception的狀況發生。