2011-01-28 22 views
5

Với Jasper, tôi sử dụng tài nguyên để tải báo cáo. Vì vậy, để tải các báo cáo chính, tôi sử dụng cái gì đó như:Làm cách nào để tải các tài nguyên phụ với Jasper?

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

Nhưng, nếu có một subreport trong report1.jrxml, làm thế nào để nói nó là trong /resources/sub.jrxml?

Trả lời

15

tôi đã làm nó theo cách này:

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" sẽ là một tham số của các loại "JasperReport" như một SubreportExpression trong Báo cáo.

Trong .jrxml:

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

Tôi không biết nếu Bạn sử dụng iReport cho thiết kế của bạn của Báo cáo. Với một nhấp chuột phải vào subreport của bạn, bạn nên tìm SubreportExpression. Tham số là bản đồ mà tôi chuyển đến "fillReport"

Chúc may mắn.

3

Tôi không hài lòng với câu trả lời của lkdg vì tôi muốn tách mối quan tâm về việc tải tệp chính xác từ thiết kế theo ý kiến ​​của tôi, tôi không bị buộc phải tổ chức từ nơi báo cáo được tải vào thời gian thiết kế của JRXML các tập tin.

Thật không may mã của Thư viện Jasper có đầy đủ các tham chiếu tĩnh khiến cho khó tìm được vị trí chính xác cho việc chèn bộ nạp con tùy chỉnh và một số tài liệu hút (ví dụ: giao diện RepositoryService hoàn toàn thiếu hợp đồng tài liệu vì vậy tôi cần phải đoán hợp đồng bằng cách đọc gọi code), nhưng nó có thể:

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); 
    } 
} 

là một thay thế cho tiêm địa phương mà bạn cũng có thể viết một global extension. Theo như tôi đã nhận nó (tôi đã không cố gắng) điều này đòi hỏi việc tạo ra một tập tin jasperreports_extension.properties với tên lớp cần được tải mà có thể bao gồm một kho lưu trữ tùy chỉnh để tải các báo cáo từ. Tuy nhiên trong trường hợp này, bạn hoàn toàn mất khả năng làm việc với các cấu hình xung đột cần thiết trong các trường hợp sử dụng khác nhau.

Các vấn đề liên quan