資料單純時用一個模板匯出excel就能滿足,但對於大型資料集或需要區分不同類別的資料時,想將資料放在不同sheet呈現的話要怎麼做呢?以下將介紹如何實現匯出多個工作表Excel。
多個sheet會有兩種情況:
第一步先查詢要放入這兩個報表模板的資料,各回傳一個List。
// 1. 查詢學生基本資料
List<StudentDataReportModel> studentDataReportModelList =
reportDemoService.getStudentAndDepartmentData();
// 2.查詢學生考試成績資料
List<StudentCourseScoreReportModel> studentCourseScoreReportModelList =
reportDemoService.getStudentCourseScoreData();
每個模板都能有它自己的參數,雖然這兩個模板的參數都一樣是日期P${date}
,為了不混淆我還是分為兩個parametersMap。
// 學生基本資料的參數
Map<String, Object> studentDataParameters = new HashMap<>();
// 學生考試成績資料的參數
Map<String, Object> studentCourseScoreParameters = new HashMap<>();
LocalDate localDate = new Date().toInstant()
.atZone(ZoneId.systemDefault()).toLocalDate();
studentDataParameters.put("date", localDate
.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
studentCourseScoreParameters.put("date", localDate
.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
因為一個sheet的資料等於是一張報表,最後會合在同一個Excel匯出,所以將需要的報表資料封裝在物件SheetReportDetail中,能簡化後續的動作也不容易漏掉資料。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SheetReportDetail {
// 報表資料
private List dataSourceList;
// 模板路徑
private String reportPath;
// 報表parametersMap
private Map<String, Object> parametersMap;
// excel的sheet名稱
private String sheetName;
}
// 模板路徑
String reportPath1 = "/Report/Jasper/StudentDataReportExcel.jrxml";
String reportPath2 = "/Report/Jasper/StudentCourseScoreReport.jrxml";
// sheet名稱
String sheetName1 = "學生資料表";
String sheetName2 = "學生考試成績表";
// 資料放入SheetReportDetail
SheetReportDetail sheetReportDetail1 = new SheetReportDetail(studentDataReportModelList, reportPath1, studentDataParameters, sheetName1);
SheetReportDetail sheetReportDetail2 = new SheetReportDetail(studentCourseScoreReportModelList, reportPath2, parametersMap, sheetName2);
// 組成ArrayList
List<SheetReportDetail> sheetReportDetailList = new ArrayList<>();
sheetReportDetailList.add(sheetReportDetail1);
sheetReportDetailList.add(sheetReportDetail2);
我將匯出的步驟封裝在ExportReportUtil的templateToByteMultipleSheet()方法。
exporter.setExporterInput(SimpleExporterInput.getInstance(printList))
合併起來並由JRXlsxExporter匯出public static byte[] templateToByteMultipleSheet(List<SheetReportDetail> sheetReportDetailList) throws Exception {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
List<JasperPrint> printList = new ArrayList<>();
String[] sheetNames = new String[sheetReportDetailList.size()];
for (int i = 0; i < sheetReportDetailList.size(); i++) {
SheetReportDetail detail = sheetReportDetailList.get(i);
// 放入sheet名稱
sheetNames[i] = detail.getSheetName();
String path = detail.getReportPath();
List dataSourceList = detail.getDataSourceList();
Map<String, Object> parametersMap = detail.getParametersMap();
// 以JasperCompileManager將jrxml模板編譯成jasper文件
JasperReport jasperReport = JasperCompileManager
.compileReport(ExportReportUtil.class.getResourceAsStream(path));
// 將Java集合資料來源與Jasper報表進行綁定
JRDataSource dataSource =
new JRBeanCollectionDataSource(dataSourceList, true);
// 將資料填入報表
JasperPrint print = JasperFillManager
.fillReport(jasperReport, parametersMap, dataSource);
printList.add(print);
}
SimpleXlsxReportConfiguration xlsxReportConfiguration =
new SimpleXlsxReportConfiguration();
// setDetectCellType使excel偵測這個值的型別並轉換為對應的格式
xlsxReportConfiguration.setDetectCellType(true);
// 設定sheet名稱
xlsxReportConfiguration.setSheetNames(sheetNames);
JRXlsxExporter exporter = new JRXlsxExporter();
exporter.setConfiguration(xlsxReportConfiguration);
exporter.setExporterInput(SimpleExporterInput.getInstance(printList));
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(byteArrayOutputStream));
exporter.exportReport();
return byteArrayOutputStream.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
因為是匯出excel檔,不需要分頁,我將ignore pagination取消勾選,不過因為我們有兩個sheet,兩張模板,所以
要將兩張模板的ignore pagination都取消勾選!
要將兩張模板的ignore pagination都取消勾選!
要將兩張模板的ignore pagination都取消勾選!
不要像我一樣第一次做的時候只取消勾選其中一個模板,匯出excel的時候發現還是有分頁(分頁的地方會空一列,並重複顯示欄位名稱),找了很久才發現原因...
實際匯出excel檔後,我們可以看到有兩個sheet,並且也是我們所設定的sheet名稱。
如果將前面所提的setDetectCellType(),設定為false或是不設定的話,匯出的一些數值相關的格式就沒有被偵測為數值,需要自行手動轉換,對於某些需求或情境來說是不方便的,因此還是滿推薦使用這個自動偵測型別的功能的