Как загрузить ресурсы подотчета с помощью Jasper? - PullRequest
6 голосов
/ 28 января 2011

С помощью Jasper я использую ресурсы для загрузки отчета. Итак, для загрузки основного отчета я использую что-то вроде:

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

Но если в report1.jrxml есть подотчет, как сказать, что он находится в / resources / sub.jrxml ?

Ответы [ 2 ]

17 голосов
/ 28 января 2011

Я сделал это следующим образом:

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» в качестве выражения Subreport в вашем отчете.1006 *

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

Я не знаю, используете ли вы IReport для дизайна отчетов.Щелкнув правой кнопкой мыши по вашему подотчету, вы найдете SubreportExpression.Параметры - это карта, которую я передаю «fillReport»

Удачи.

5 голосов
/ 21 февраля 2016

Я был не совсем доволен ответом lkdg, потому что хотел отделить задачу загрузки правильного файла от дизайна, так как, по моему мнению, я не должен быть вынужден организовывать из того места, где отчеты загружаются во время разработки файлов JRXML.

К сожалению, код библиотеки Jasper полон статических ссылок, которые затрудняют поиск правильного места для загрузки пользовательского загрузчика подотчета, а также отстой некоторых документов (например, интерфейс 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 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);
    }
}

В качестве альтернативы локальному внедрению вы также можете написать глобальное расширение .Насколько я понял (я не пробовал), это требует создания файла jasperreports_extension.properties с именами классов, которые должны быть загружены, которые могут включать в себя собственный репозиторий для загрузки отчетов.Однако в этом случае вы полностью теряете способность работать с конфликтующими конфигурациями, необходимыми в разных случаях использования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...