如何使用Jasper加载子报表资源?

使用Jasper,我使用资源来加载报告。 因此,要加载主报告,我使用类似的东西:

InputStream is = getClass().getResourceAsStream("/resources/report1.jrxml"); design = JRXmlLoader.load(is); 

但是,如果report1.jrxml中有子报告,怎么说它在/resources/sub.jrxml

我是这样做的:

 jasperDesign = JRXmlLoader.load(rootpath + "/WEB-INF/templates/Report.jrxml"); jasperDesignSR = JRXmlLoader.load(rootpath + "/WEB-INF/templates/SubReport.jrxml"); JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign); JasperReport jasperReportSR = JasperCompileManager.compileReport(jasperDesignSR); parameters.put("SubReportParam", jasperReportSR); JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource); 

“SubReportParam”将是“JasperReport”类型的参数,作为报表中的SubreportExpression。

在.jrxml中:

  

我不知道你是否使用IReport进行报告设计。 右键单击子报表,您应找到SubreportExpression。 参数是我传递给“fillReport”的地图

祝你好运。

我对lkdg的答案不太满意,因为我想分离从设计中加载正确文件的问题,因为在我看来,我不应该强迫在JRXML文件的设计时加载报告。

不幸的是,Jasper Library的代码充满了静态引用,这使得很难找到注入自定义子报告加载器的正确位置,而且一些文档也很糟糕(例如, RepositoryService接口完全没有合同文档所以我需要通过阅读调用代码猜测合同),但有可能:

 private static void fillReport() throws IOException, JRException { // The master report can be loaded just like that, because the // subreports will not be loaded at this point, but later when // report is filled. final JasperReport report = loadReport("masterReport.jasper"); // The SimpleJasperReportsContext allows us to easily specify some // own extensions that can be injected into the fill manager. This // class will also delegate to the DefaultJasperReportsContext and // combine results. Thus all the default extensions will still be available SimpleJasperReportsContext jasperReportsContext = new SimpleJasperReportsContext(); jasperReportsContext.setExtensions( RepositoryService.class, singletonList(new SubReportFindingRepository()) ); final byte[] pdf = JasperExportManager.exportReportToPdf( JasperFillManager .getInstance(jasperReportsContext) // carefully select the correct `fill` method here and don't // accidentally select one of the static ones!: .fill(report, YOUR_PARAMS, YOUR_CONNECTION) ); } private static JasperReport loadReport(final String fileName) throws IOException, JRException { try(InputStream in = loadReportAsStream(fileName)) { return (JasperReport) JRLoader.loadObject(in); } } private static InputStream loadReportAsStream(final String fileName) { final String resourceName = "/package/path/to/reports/" + fileName; final InputStream report = CurrentClass.class.getResourceAsStream(resourceName); if (report == null) { throw new RuntimeException("Report not found: " + resourceName); } return report; } private static class SubReportFindingRepository implements RepositoryService { @Override public Resource getResource(final String uri) { return null; // Means "not found". The next RepositoryService will be tried } @Override public void saveResource(final String uri, final Resource resource) { throw new UnsupportedOperationException(); } @Override public  K getResource(final String uri, final Class resourceType) { if (!isKnownSubReport(uri)) { return null; // Means "not found". The next RepositoryService will be tried } final ReportResource reportResource = new ReportResource(); try { reportResource.setReport(loadReport(uri)); } catch (IOException | JRException e) { throw new Error(e); } return resourceType.cast(reportResource); } private static boolean isKnownSubReport(final String uri) { return "subReport1.jasper".equals(uri) || "subReport2.jasper".equals(uri); } } 

作为本地注射的替代方案,您还可以编写全局扩展 。 据我所知(我没试过),这需要创建一个jasperreports_extension.properties文件,其中应该加载类名,其中可以包含一个自定义存储库来加载报告。 但是,在这种情况下,您完全无法使用不同用例中所需的冲突配置。