2011-01-28 26 views
5

Con Jasper, uso los recursos para cargar el informe. Por lo tanto, para cargar el informe principal, utilizo algo como:Cómo cargar recursos de subinforme con Jasper?

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

Pero, si hay un informe integrado en report1.jrxml, cómo decir que está en /resources/sub.jrxml?

Respuesta

15

lo hice de esta manera:

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" sería un parámetro del tipo "JasperReport" como SubreportExpression dentro de su Informe.

En el .jrxml:

<parameter name="SubReportParam" class="net.sf.jasperreports.engine.JasperReport" isForPrompting="false"/> 

No sé si se utiliza IReport para el diseño de informes. Con un clic derecho en su subinforme, debe encontrar el SubreportExpression. parámetros es un mapa que paso a "fillReport"

Buena suerte.

3

No estaba contento con la respuesta de lkdg porque quería separar la preocupación de cargar el archivo correcto del diseño ya que en mi opinión no debería forzarme a organizar desde dónde se cargan los informes en el momento del diseño del JRXML archivos.

Desafortunadamente, el código de la Biblioteca Jasper está lleno de referencias estáticas que dificultan encontrar el lugar correcto para la inyección de un subinportador personalizado y también algunas succiones (por ejemplo, la interfaz RepositoryService carece completamente de contrato documentación por lo que necesita de adivinar el contrato mediante la lectura de código de llamada), pero es posible:

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 extends Resource> K getResource(final String uri, final Class<K> 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); 
    } 
} 

Como alternativa a la inyección local también se puede escribir una global extension. Por lo que tengo (no lo intenté), esto requiere la creación de un archivo jasperreports_extension.properties con nombres de clase que se deben cargar, que pueden incluir un repositorio personalizado para cargar los informes. Sin embargo, en este caso pierde completamente la capacidad de trabajar con configuraciones conflictivas necesarias en diferentes casos de uso.

Cuestiones relacionadas