2017-02-21 144 views
1

我很熟悉jasperstudio 6.3.0,並且能夠從java運行其他報告而沒有任何問題。效果很好。但是,我無法運行包含子報表的報表。我在這裏找到了解決方案,但仍然無法使其工作。在我的解決方案中,我將報告加載到表中進行存儲,並從數據庫中提取子報表和主報表並編譯jrxml。一切工作正常,然後在java中調用Jasper子報告

net.sf.jasperreports.engine.JRException:資源未找到:subInvoiceSummary.jasper。 runReport中的錯誤:找不到資源:subInvoiceSummary.jasper。 at net.sf.jasperreports.repo.RepositoryUtil.getResourceFromLocation(RepositoryUtil.java:153) at net.sf.jasperreports.repo.RepositoryUtil.getReport(RepositoryUtil.java:112) at net.sf.jasperreports.engine。在net.sf.jasperreports.engine.fill.JRFillSubreport.evaluateReport(JRFillSubreport.java:365) at net.sf.jasperreports.engine.fill.JRFillSubreport.evaluateSubreport(JRFillSubreport.java:398) JRFillSubreport.java:427) 在net.sf.jasperreports.engine.fill.JRFillSubreport.evaluate(JRFillSubreport.java:341) 在net.sf.jasperreports.engine.fill.JRFillElementContainer.evaluate(JRFillElementContainer.java:381)at net.sf.jasperreports.engine.fill.JRFillBand.evaluate(JRFillBand.java:500) at 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) at 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。 java:90) at net.sf.jasperreports.engine.JasperFillManager.fill(JasperFillManager.java:456) at net.sf.jasperreports.engine.JasperFillManager.fillRe端口(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這一點。賈斯珀開發人員自己說,子報表在他們的論壇上執行得並不是很好。

我用這段代碼解決了這個問題。它也不是完美的,但它的工作原理。

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

希望這會有所幫助。如果有人有更好的解決方案,我會最喜歡你的問題。