Spring MVC 處理子報表並不像我之前的筆記 使用 Java 輸出資料到 JasperReports 子報表表身(Subreport Detail)那樣,由 Java 組出子報表再丟給主報表,而是在 Java 將子報表(Jasper)與子報表要用的 Data 一起丟給 Spring MVC 就可以了。
講得更精確,Data 是由 Java 丟的,而子報表 Jasper 則是透過設定的。
這邊一次就玩大一點,使用兩個子表,這樣可以引出一個有趣的問題。
Java 負責所有的 DataSource,包括主表和「所有」子表的。
@RequestMapping("/helloReport") public String helloReport(Model model) { model.addAttribute("title", "這是主報表"); // 主表 Collection<Map<String, ?>> list = new ArrayList<Map<String, ?>>(); for (int i = 0; i < 5; i++) { Map<String, Object> data = new HashMap<String, Object>(); data.put("id", new BigDecimal(i + 1)); data.put("title", "中文 字串 String " + i); data.put("date", new Date(112, 9, i + 1)); list.add(data); } model.addAttribute("dataSource", list); // 子表1 list = new ArrayList<Map<String, ?>>(); for (int i = 10; i < 15; i++) { Map<String, Object> data = new HashMap<String, Object>(); data.put("id", new BigDecimal(i + 1)); data.put("title", "中文 字串 String " + i); data.put("date", new Date(112, 9, i + 1)); list.add(data); } // 這裡一定要用 JRDataSource 包起來才行,不能用 Collection model.addAttribute("dataSource2", new JRMapCollectionDataSource(list)); // 子表2 list = new ArrayList<Map<String, ?>>(); for (int i = 20; i < 25; i++) { Map<String, Object> data = new HashMap<String, Object>(); data.put("id", new BigDecimal(i + 1)); data.put("title", "中文 字串 String " + i); data.put("date", new Date(112, 9, i + 1)); list.add(data); } // 這裡一定要用 JRDataSource 包起來才行,不能用 Collection model.addAttribute("dataSource2", new JRMapCollectionDataSource(list)); return "helloReport"; }除了子表只接受 JRDataSource 介面的物件,不能用 Collection,也不是說不能用,如果要用,那在 iReport 裡就得從 net.sf.jasperreports.engine.data.JRMapCollectionDataSource 改用 net.sf.jasperreports.engine.data.JRBeanCollectionDataSource,其他就是一般的作法,沒什麼特別。
然後透過 ResourceBundleMessageSource 的 views.properties 設定主表與子表的 Japser 位置,以及主表與子表要使用的 DataSource。
helloReport.(class)=org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView helloReport.url=/WEB-INF/reports/helloReport.jasper helloReport.reportDataKey=dataSource helloReport.subReportUrls=helloReport1=/WEB-INF/reports/helloReport1.jasper\r\nhelloReport2=/WEB-INF/reports/helloReport2.jasper helloReport.subReportDataKeys=dataSource1,dataSource2最有趣的點來了!
分別是 helloReport.subReportUrls 與 helloReport.subReportDataKeys 的設值方式。
先看看原始檔,從 JasperReportsPdfView 一路往上追到 AbstractJasperReportsView,可以看到兩個參數,subReportUrls 與 subReportDataKeys。
/** * A String key used to lookup the <code>JRDataSource</code> in the model. */ private String reportDataKey; /** * Stores the paths to any sub-report files used by this top-level report, * along with the keys they are mapped to in the top-level report file. */ private Properties subReportUrls; /** * Stores the names of any data source objects that need to be converted to * <code>JRDataSource</code> instances and included in the report parameters * to be passed on to a sub-report. */ private String[] subReportDataKeys;特別的地方在於它們的型別,一個是 Properties,另一個是 String[],嘿嘿,這種型別在怎麼在 views.properties 裡設定?
字串陣列還好,猜一下就知道,用逗號區隔就沒問題了;順序也不重要,重要的是名字,用在 iReport 裡參考使用。
但是 Properties 呢?怎麼在一個 Properties 裡傳入另一個 Properties?抓破頭無法理解!
神奇的作法,用一行文字代表一個 Properties 檔,也就是將一個 Properties 檔裡的每一行用 \r\n 串成一行。
A=123 B=456變成
A=123\r\nB=456最後再當成值,只派給另一個 Property 的 key。
aKey=A=123\r\nB=456這樣就可以同時指定子報表 Japser 檔的位置和 Data 的名稱,至於報表麼拉,請參考 使用 Java 輸出資料到 JasperReports 子報表表身(Subreport Detail)。
結果如下。
---
---
---
沒有留言:
張貼留言