2017-02-21 4 views
1

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

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.JRFillSubreport.loadReport (JRFillSubreport.java:398) на net.sf.jasperreports.engine.fill.JRFillSubreport.evaluateReport (JRFillSubreport.java:365) в net.sf.jasperreports.engine.fill.JRFillSubreport.evaluateSubreport (JRFillSubreport.java:427) at net.sf.jasperreports.engine.fill.JRFillSubreport.evaluate (JRFillSubreport.java:341) at net.sf.jasperreports.engine.fill.JRFillElementContainer.evaluate (JRFillElementContainer.java:381) at net.sf.jasperreports.engine.fill.JRFillBand.evaluate (JRFillBand.java:500) в net.sf.jasperreports.engine.fill.JRVerticalFiller.fillColumnBand (JRVerticalFiller.java:2022) at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillDetail (JRVerticalFiller.java:748) at net.sf. jasperreports.engine.fill.JRVerticalFiller.fillReportStart (JRVerticalFiller.java:255) at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillReport (JRVerticalFiller.java:115) по адресу net.sf.jasperreports.engine.fill. JRBaseFiller.fill (JRBaseFiller.java:580) at net.sf.jasperreports.engine.fill.BaseReportFiller.fill (BaseReportFiller.java:396) at net.sf.jasperreports.engine.fill.JRFiller.fill (JRFiller.fill (JRFiller.fill). java: 90) at net.sf.jasperreports.engine.JasperFillManager.fill (JasperFillManager.java:456) at net.sf.jasperreports.engine.JasperFillManager.fillRe port (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(); 

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

ответ

0

Я имел такой же вопрос и не нашел простой способ achieive это. Разработчики 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; 
} 

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