如何在Spring MVC中合并两个Jasper Report为单个视图?
当然有可行的办法啦!我给你整理了几个实用的方案,你可以根据自己的场景来选:
方案1:用JasperReports的子报表(Subreport)功能
这是最常用、最灵活的方式,把你现有的两个独立报表作为子报表嵌入到一个主报表模板里:
- 第一步:新建一个主报表模板(比如
main_report.jrxml),在主报表中添加两个「子报表组件」,分别指向你已有的两个报表文件(report1.jasper和report2.jasper)。 - 第二步:在Spring MVC控制器里,只需要返回主报表的视图名,同时准备好两个子报表需要的数据源和参数,注意要把这些参数/数据源传递给主报表,由主报表转发给对应的子报表。
- 控制器代码示例:
@GetMapping("/combined-report") public ModelAndView generateCombinedReport() { ModelAndView mav = new ModelAndView("jasperView"); // 你的Jasper视图名 // 准备第一个报表的数据源 List<Report1Data> data1 = report1Service.getReportData(); JRBeanCollectionDataSource ds1 = new JRBeanCollectionDataSource(data1); // 准备第二个报表的数据源 List<Report2Data> data2 = report2Service.getReportData(); JRBeanCollectionDataSource ds2 = new JRBeanCollectionDataSource(data2); // 主报表参数:传递子报表路径和数据源 Map<String, Object> params = new HashMap<>(); params.put("SUBREPORT_DIR", "classpath:reports/"); // 子报表所在目录 params.put("report1DataSource", ds1); params.put("report2DataSource", ds2); mav.addObject("datasource", new JREmptyDataSource()); // 主报表用空数据源即可 mav.addObject("params", params); mav.addObject("reportName", "main_report"); // 主报表模板名 return mav; }
- 主报表子报表配置:在子报表组件的「Data Source Expression」中填写
$P{report1DataSource},「Report Expression」填写$P{SUBREPORT_DIR} + "report1.jasper",第二个子报表同理配置即可。
方案2:合并两个报表的输出流
如果不想修改原有的报表模板,可以在控制器里分别生成两个报表的输出流,再合并成一个文件返回:
- 第一步:分别生成两个报表的
JasperPrint对象。 - 第二步:用JasperReports自带的
JRPdfExporter把两个JasperPrint合并成一个PDF输出流(如果需要其他格式可能要借助第三方工具)。 - 控制器代码示例:
@GetMapping("/combined-report") public void generateCombinedReport(HttpServletResponse response) throws Exception { // 生成第一个报表的JasperPrint Map<String, Object> params1 = new HashMap<>(); List<Report1Data> data1 = report1Service.getReportData(); JRBeanCollectionDataSource ds1 = new JRBeanCollectionDataSource(data1); JasperPrint print1 = JasperFillManager.fillReport( getClass().getResourceAsStream("/reports/report1.jasper"), params1, ds1 ); // 生成第二个报表的JasperPrint Map<String, Object> params2 = new HashMap<>(); List<Report2Data> data2 = report2Service.getReportData(); JRBeanCollectionDataSource ds2 = new JRBeanCollectionDataSource(data2); JasperPrint print2 = JasperFillManager.fillReport( getClass().getResourceAsStream("/reports/report2.jasper"), params2, ds2 ); // 合并两个JasperPrint为单个PDF List<JasperPrint> printList = Arrays.asList(print1, print2); JRPdfExporter exporter = new JRPdfExporter(); exporter.setExporterInput(SimpleExporterInput.getInstance(printList)); exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(response.getOutputStream())); // 设置响应头,让浏览器直接展示PDF response.setContentType("application/pdf"); response.setHeader("Content-Disposition", "inline; filename=combined_report.pdf"); exporter.exportReport(); }
- 这个方案的优势是不用改动原报表,但缺点是仅适合输出PDF这类可以直接合并的格式,如果要输出HTML可能会比较麻烦。
方案3:合并报表模板内容
如果两个报表的逻辑关联性很强,也可以直接把两个原报表的内容复制到一个新的JRXML模板里,用分段、书签或者分组来区分两部分内容。这个方案适合报表结构不复杂的场景,省去了子报表的配置步骤,但需要你手动整合模板内容。
小提醒
- 用子报表方案时,一定要注意子报表的路径配置,避免出现找不到文件的错误;
- 合并输出流时,要确保两个报表的输出格式兼容,比如都是PDF。
内容的提问来源于stack exchange,提问作者MD RAHIIM
相关产品推荐
相关产品推荐

