Звоните Джасперу в Ява

Я довольно знаком с jasperstudio 6.3.0 и могу запускать другие отчеты из Java без проблем. Работает хорошо. Однако я не могу запустить отчет, содержащий подотчеты. Здесь я нашел решения для stackru, но все еще не могу заставить его работать. В моем решении я загружаю отчеты в таблицу для хранения, извлекаю вложенные отчеты и основной отчет из базы данных и компилирую jrxml. Все работает хорошо там и тогда

net.sf.jasperreports.engine.JRException: ресурс не найден в: subInvoiceSummary.jasper. ОШИБКА в runReport: ресурс не найден по адресу: subInvoiceSummary.jasper. в net.sf.jasperreports.repo.RepositoryUtil.getResourceFromLocation(RepositoryUtil.java:153) в net.sf.jasperreports.repo.RepositoryUtil.getReport(RepositoryUtil.java:112) в net.sf.jasperreports.engine.fill.JR.loadReport(JRFillSubreport.java:398) на net.sf.jasperreports.engine.fill.JRFillSubreport.evaluateReport(JRFillSubreport.java:365) на net.sf.jasperreports.engine.fill.JRFillSubreport.evaluateSubreport(27)) в net.sf.jasperreports.engine.fill.JRFillSubreport.evaluate(JRFillSubreport.java:341) в net.sf.jasperreports.engine.fill.JRFillElementContainer.evaluate(JRFillElementContainer.java:381) в net.sf.jp.engine.fill.JRFillBand.evaluate(JRFillBand.java:500) в net.sf.jasperreports.engine.fill.JRVerticalFiller.fillColumnBand(JRVerticalFiller.java:2022) в net.sf.jasperreports.engine.fill.JRVerticalFiller (JRVerticalFiller.java:748) в net.sf.jasperreports.engine.fill.JRVerticalFiller.fillReportStart(JRVerticalFiller.java:255) в net.sf.jasperreports.engine.fill.JRVerticalFiller.fillReport(JRVerticalFiller.java:115) на net.sf.jasperreports.engine.fill.JRBaseFiller.fill(JRBaseFiller.java:580) на net.sf.jasperreports.engine.fill.BaseReportFiller.fill(BaseReportFiller.java:396) в net.sf.jasperreports.engine.fill.JRFiller.fill(JRFiller.java:90) в net.sf.jasperreports.engine.JasperFillManager.fill(JasperFillManager.java:456) на net.sf.jasperreports.engine.JasperFillManager.fillReport(JasperFillManager.java:863)

Я пробовал много перестановок, но безрезультатно. Я также попытался добавить код для jasperreports для отслеживания стека, показанного выше, но существует так много.jar-зависимостей и версий зависимостей, что я не смог заставить его скомпилироваться в моем проекте через 2 дня (если у кого-то есть ссылка на простой способ сделать эту работу, пожалуйста, дайте мне знать). Вот фрагмент кода:

Map<String, Object> rptParms = new HashMap<String, Object>();

List<daRecOnDemandSubReport> subReports = report.getOnDemandSubReport();
Iterator<daRecOnDemandSubReport> subReportList = subReports.iterator();
while (subReportList.hasNext()) {
daRecOnDemandSubReport subReport = subReportList.next();
ByteArrayInputStream x = getSubReportDataStream(dbConnROIPro, report.getODReportID());
JasperReport compiledSubReport = JasperCompileManager.compileReport(x);
String fileName = subReport.getODSubReportFileName().replace(".jrxml", ".jasper");
rptParms.put(fileName, compiledSubReport);
}

ByteArrayInputStream x = getReportDataStream(dbConnROIPro, report.getODReportID());

JasperReport cRpt = JasperCompileManager.compileReport(x);

rptParms = getReportParameters(dbConnGTrack,report.getODReportID(), rptParms, report.getOnDemandParm(), programID);

JasperPrint rpt = JasperFillManager.fillReport(cRpt,rptParms,dbConnGTrack.getDbConn());

ByteArrayOutputStream outStream = new ByteArrayOutputStream();
JRXlsxExporter XLSXexporter = new JRXlsxExporter();
   XLSXexporter.setExporterInput(new SimpleExporterInput(rpt));
   XLSXexporter.setExporterOutput(new SimpleOutputStreamExporterOutput(outStream)); 
   XLSXexporter.exportReport();

Спасибо заранее за любую помощь

1 ответ

У меня была такая же проблема, и я никогда не находил простой способ добиться этого. Сами разработчики Jasper говорят, что подотчеты не очень хорошо реализованы на их форумах.

Я решил проблему с этим моим кодом. Это также далеко от совершенства, но это работает.

public byte[] generateReport(ExportType exportType, String resourceName, Connection connection, Map<String, Object> parameters) throws JRException, SQLException {
    JasperReport jasperReport = loadReport(resourceName);

    LOGGER.debug("Loading subreports if any...");
    Map<String, JasperReport> subReports = loadSubReports(resourceName, jasperReport);
    parameters.putAll(subReports);

    LOGGER.debug("Filling report with JDBC and {}", parameters);
    JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, connection);

    LOGGER.debug("Exporting report with {}", exportType.getClass().getSimpleName());
    byte[] pdf = exportType.export(jasperPrint);

    return pdf;
}

/**
 * Converts a system resource into a JasperReport instance.
 * If the extension is ".jasper", it tries to load a pre-compiled report.
 * If the extension is ".jrxml", it tries to compile the report.
 */
private JasperReport loadReport(String resourceName) throws JRException {
    JasperReport jasperReport = null;
    InputStream inputStream = this.getClass().getResourceAsStream(resourceName);

    if (inputStream != null) {
        if (resourceName.toLowerCase().endsWith(JASPER)) {
            LOGGER.debug("Loading pre-compiled report: {}", resourceName);
            jasperReport = (JasperReport) JRLoader.loadObject(inputStream);
        } else {
            LOGGER.debug("Compiling XML report: {}", resourceName);
            jasperReport = JasperCompileManager.compileReport(inputStream);
        }
    } else {
        LOGGER.warn("Unable to open resource: {}", resourceName);
    }
    return jasperReport;
}

/**
 * Parses a Report for SubReport parameters.
 * A Parameter has to be a <code>java.lang.Object</code> or a <code>net.sf.jasperreports.engine.JasperReport</code> to be considered a SubReport Input
 * An Object parameter has the advantage to allow Jasper Report's IDE to accept a Filename String resource.
 * If the parameter is an Object, the Filename declared as <b>default value</b> is used to load the SubReport.
 * If the parameter is a JasperReport, the parameter's name is used instead.
 * 
 * The default value, or the parameter's name, have to use a ".jasper" or ".jrxml" extension.
 * The SubReport resource's path has to be located relatively to the parent Report.
 */
private Map<String, JasperReport> loadSubReports(String masterResource, JasperReport jasperReport) throws JRException {
    Map<String, JasperReport> subReportExpressions = new HashMap<>();
    String masterPath = FilenameUtils.getFullPath(masterResource);

    for (JRParameter jrParameter : jasperReport.getParameters()) {
        String subReportName = getSubReportName(jrParameter);
        if (subReportName != null) {
            String name = jrParameter.getName();
            JasperReport subReport = loadReport(masterPath + subReportName);
            subReportExpressions.put(name, subReport);
        }
    }
    return subReportExpressions;
}


/**
 * Analyses the parameter to find a SubReport resource name respecting the defined rules
 * 
 * @return The filename of the resource, or null
 */
private String getSubReportName(JRParameter jrParameter) {
    String ret = null;
    Class<?> valueClass = jrParameter.getValueClass();
    boolean isObject = (valueClass == Object.class);
    boolean isJasperReport = (valueClass == JasperReport.class);

    // If the parameter is an Object,
    // we take the SubReport name from the default value (a String)
    if (isObject) {
        String defaultValue = getDefaultValue(jrParameter);
        if (defaultValue != null && checkExtension(defaultValue)) {
            ret = defaultValue;
        }
    }

    // If the parameter is a JasperReport, or an Object without a correct defaultValue,
    // we take the SubReport name from the parameter's name
    if (isJasperReport || (ret == null && isObject)) {
        String name = jrParameter.getName();
        if (checkExtension(name)) {
            ret = name;
        }
    }
    return ret;
}


private boolean checkExtension(String defaultValue) {
    defaultValue = defaultValue.toLowerCase();
    return defaultValue.endsWith(JRXML) || defaultValue.endsWith(JASPER);
}

private String getDefaultValue(JRParameter jrParameter) {
    String ret = null;
    JRExpression defaultValueExpression = jrParameter.getDefaultValueExpression();
    if (defaultValueExpression != null) {
        ret = defaultValueExpression.getText();
        if (ret != null && ret.length() > 2 && ret.startsWith(QUOTE) && ret.endsWith(QUOTE)) {
            // Removing quotes from the String
            ret = ret.substring(1, ret.length() - 1);
        }
    }
    return ret;
}

Надеюсь это поможет. Я буду любить твой вопрос, если у кого-нибудь есть лучшее решение.

Другие вопросы по тегам