有時候我會遇到一些比較不一樣的需求,例如需要匯出一份沒有資料來源(DataSource)的報表,只要生成一個樣式固定的靜態報表,這種報表固然簡單,但仍有值得注意的地方。
這種靜態報表第一個要考量的是,需不需要在一個檔案或畫面中重複顯示報表,只要記得把需要重複的地方放在Detail Band就好了。
如果報表靜態內容只顯示一次,可以將全都的元素都放到Title Band就好。
準備好後端程式碼,與之前不同的是dataSourceList是null。
// 1. 設定報表參數
Map<String, Object> parametersMap = new HashMap<>();
LocalDate date = new Date().toInstant()
.atZone(ZoneId.systemDefault()).toLocalDate();
parametersMap.put("date", date
.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
// 2. 匯出excel byte[]
byte[] bytes = null;
try {
String reportPath = "/Report/Jasper/NoDataSourceReport.jrxml";
bytes = ExportReportUtil.templateToExcelByte(null, reportPath, parametersMap);
} catch (Exception e) {
throw new RuntimeException(e);
}
ExportReportUtil.java
public static byte[] templateToExcelByte(List dataSourceList, String reportPath, Map<String, Object> parametersMap) throws Exception {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
// 以JasperCompileManager將jrxml模板編譯成jasper文件
JasperReport jasperReport = JasperCompileManager
.compileReport(ExportReportUtil.class.getResourceAsStream(reportPath));
// 將Java集合資料來源與Jasper報表進行綁定
JRDataSource dataSource = new JRBeanCollectionDataSource(dataSourceList);
// 將資料填入報表
JasperPrint print = JasperFillManager
.fillReport(jasperReport, parametersMap, dataSource);
// 匯出
SimpleXlsxReportConfiguration xlsxReportConfiguration = new SimpleXlsxReportConfiguration();
// setDetectCellType使excel偵測這個值的型別並轉換為對應的格式
xlsxReportConfiguration.setDetectCellType(true);
JRXlsxExporter exporter = new JRXlsxExporter();
exporter.setConfiguration(xlsxReportConfiguration);
exporter.setExporterInput(new SimpleExporterInput(print));
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(byteArrayOutputStream));
exporter.exportReport();
return byteArrayOutputStream.toByteArray();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
匯出後是一個正常的靜態報表。
如果標題與日期不希望重複顯示,放在Title Band,但項目與事由希望重複顯示,放在Detail Band。(我舉例而已,應該是沒這種單據)
後端程式碼與「模板1」相同,匯出後會是一個只有Title的報表。
這是因為Detail Band要重複幾行就是看有多少DataSource,如果沒有DataSource與jasper文件綁定,產生的JRDataSource是null,在正式填充到jasper文件時就不會產生Detail的內容。
要解決這種狀況有兩種方式:
byte[] bytes = null;
try {
String reportPath = "/Report/Jasper/NoDataSourceReport.jrxml";
List<Integer> noDataSourceList = new ArrayList();
// Detail要重複5次
for (int i = 0; i <= 5 ; i++) {
noDataSourceList.add(i);
}
bytes = ExportReportUtil.templateToExcelByte(noDataSourceList, reportPath, parametersMap);
} catch (Exception e) {
throw new RuntimeException(e);
}
new JREmptyDataSource()
不填入參數就好。public static byte[] templateToExcelByte(List dataSourceList, String reportPath, Map<String, Object> parametersMap) throws Exception {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
// 以JasperCompileManager將jrxml模板編譯成jasper文件
JasperReport jasperReport = JasperCompileManager
.compileReport(ExportReportUtil.class.getResourceAsStream(reportPath));
// 將Java集合資料來源與Jasper報表進行綁定
JRDataSource dataSource = CollectionUtils.isEmpty(dataSourceList) ?
// Detail要重複5次
new JREmptyDataSource(5) : new JRBeanCollectionDataSource(dataSourceList);
// 將資料填入報表
JasperPrint print = JasperFillManager
.fillReport(jasperReport, parametersMap, dataSource);
// 匯出
SimpleXlsxReportConfiguration xlsxReportConfiguration = new SimpleXlsxReportConfiguration();
// setDetectCellType使excel偵測這個值的型別並轉換為對應的格式
xlsxReportConfiguration.setDetectCellType(true);
JRXlsxExporter exporter = new JRXlsxExporter();
exporter.setConfiguration(xlsxReportConfiguration);
exporter.setExporterInput(new SimpleExporterInput(print));
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(byteArrayOutputStream));
exporter.exportReport();
return byteArrayOutputStream.toByteArray();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
使用其中一種方法後,匯出報表後就有看到Detail的內容了
如果我們的情境是有Field動態的顯示報表資料,但在沒有查詢到DataSource資料的狀況下,使用JREmptyDataSource,匯出時會發現所有Field會自動顯示null。
除了在後端處理之外,Jaspersoft Studio的「Text Field」元素有一個好用的屬性:Blank When Null。
選取「Text Field」之後勾選「Blank When Null」,之後不論是不是使用JREmptyDataSource造成的null都不會顯示出來了。