JasperServer:无法找到子报告异常

时间:2010-12-06 07:41:17

标签: jasper-reports subreport jasperserver

我搜索了几天来解决这个错误没什么新问题。

我有一个包含多级子报表的报告,iReport 3.7.5上的一切正常。我在第一级&中使用subreport.jasper作为子报表表达式。还有subreportA.jaspersubreportB.jasper在第二级&将所有(主报告和子报告)放在同一路径中。

当我尝试在JasperServer上部署它时出现的问题。 当我尝试上传第一个主报告时,iReport向导要求我附加资源文件夹中的第一个subreport.jrxml,并使用repo:subreport.jrxmlrepo:subreport.jasper访问它。 然后我手动上传第二级子报表并执行相同的操作,将子报表表达式更改为repo:subreportA.jasperrepo:subreportB.jasper

我收到了编译错误:Unable to locate the subreport with expression: ""repo:subreport.jasper"". java.lang.Exception: repo:subreport.jrxml not found.

我尝试打解决方案,没有任何作用。 使用:SUBREPORT_DIR @开头,

使用完整路径:repo:/Circuit_Reports/Connectivity/Connectivity_files/

.jasper&之间切换.jrxml

在lib文件夹中使用jasperserver_api_engine_impl_0_fix.jar作为对此错误的修复,

我还搜索了数据库记录,以确保它们位于同一个文件夹中,并且具有相同的父文件夹。

4 个答案:

答案 0 :(得分:8)

Longtalk之前的Smalltalk;)

(当然我不想鼓励你阅读这篇长篇详细文章的内容!大胆的标记可能已足以解决你的问题但我发现值得记录这个更详细一些棘手的东西!)

因为我在这上面投入了几个小时(在我几周前解决之后,现在有了改变,但忘记了正确记录,忘了我是怎么做的,并且无法以任何形式再次检索这些信息 - 当上传和配置到/在JasperServer中)...这里有一些关于子报告引用的各种网站上提到的聚合功能,它是如何工作的以及可以尝试的...

(如果有希望的话,我会更新我的或其他调查结果)

捷径详情/最佳实践?! 4

直到Jasper的功能可能会提供类似的"包装"解决方案本身......

要解决与在预览模式下本地运行* .jrxml,* .jasper文件或在JasperServer上远程运行相关的所有问题,我现在使用以下方法,只允许使用单个*。 jrxml文件,在多开发人员环境中本地和远程无需修改即可工作,支持每个环境独立重构dir结构(路径,名称)(=应该;-)):

  • 使用一些jasper-utils-*.jar
    • 将它放在项目(Java)类路径中( Project->Properties->Java Build Path->Libraries->Add
    • 将其放入 ../jasperserver/WEB-INF/lib/ 文件夹
  • 引用一些自定义的Jasper Java Scriptlet jr.utl.EnvScriptlet ,它在主报告中执行丑陋的子报告路径/引用魔术
    • 通过向主报告添加属性来定义REPORT_SCRIPTLET报告属性 - >报告 - >数据集 - > Scriptlet类:jr.utl.EnvScriptlet
  • 使用一些自定义属性文件 jr.utl.properties或以其他方式提供的系统属性(设置Java系统属性的任何其他方式也可以正常工作 - 已经设置的位置属性将覆盖已加载的文件属性)以配置包括

    在内的不同环境
    • 当前环境信息通过 jr.utl.env 属性(prod,myOsUsrName,test,demo,staging,local,...)
      • 确定必须如何生成子报表引用/看起来像
    • 服务器子报告父目录属性引用
    • 拿这些属性文件内容并在每个环境中放置一个:
    • 服务器上的
    • ../jasperserver/WEB-INF/classes/jr.utl.properties

      jr.utl.env=prod
      mycompany.local.jr.gui.rep.subrep1.parentdir=repo:/x/y/z/
      mycompany.local.jr.gui.rep.subrep2.parentdir=repo:/x/y/z/
      mycompany.local.jr.gui.rep.subrep3.parentdir=repo:/x/y/foobar/
      
    • 本地JasperSoft Studio(Eclipse)Java src / build路径中的
    • 例如。 ../myrepproject/src/java/jr.utl.properties

      jr.utl.env=dietrian
      mycompany.local.jr.gui.rep.subrep1.parentdir=D:/reporting/src/reports/
      mycompany.local.jr.gui.rep.subrep2.parentdir=D:/reporting/src/reports/
      mycompany.local.jr.gui.rep.subrep3.parentdir=D:/reporting/src/reports.otherdir/
      
      • 在我们的环境中实现源修改独立性,我们根据这个想法,通过一些依赖于工作空间/用户特定的local.properties文件对这些值进行参数化并生成一次:

        |- build.xml                  (containing the ANT build magic)      
        |- build.properties           (containing global properties)      
        |- local.properties           (ignored in version control, e.g. .hgignore, user-specific generated from local.template.properties)
        |- local.template.properties  (source for ANT build task generating the local.properties above)
           |- mycomp.local.proj.reporting.dir=D:/reporting
        |- src/reports
           |- jr.utl.properties           (ignored in version control, user-specificly generated based on template below)
           |- jr.utl.template.properties  (source for ANT build task generating the jr.utl.properties above)
              jr.utl.env=${user.name}
              mycompany.local.jr.gui.rep.subrep1.parentdir=${mycomp.local.proj.reporting.dir}/src/reports/
              mycompany.local.jr.gui.rep.subrep2.parentdir=${mycompany.local.jr.gui.rep.subrep1.parentdir}
              mycompany.local.jr.gui.rep.subrep3.parentdir=${mycomp.local.proj.reporting.dir}/src/reports.otherdir/
        
  • BASE_DIR 主报告参数定义为例如 $P{REPORT_SCRIPTLET}.getProp("mycompany.allsubreports.parentdir") (匹配jr.utl.properties文件中某些与环境相关的属性)

  • 将主子报告表达式定义为例如的 jr.utl.EnvScriptlet.getSubrepPath( $P{BASE_DIR}, "subrep1.jrxml")
    • 自动解析您也可以使用的属性中的值,例如这些变种:
      • jr.utl.EnvScriptlet.getSubrepPathByPropKey( $P{BASE_DIR}, "mycompany.local.jr.gui.rep.subrep1.name")
      • jr.utl.EnvScriptlet.getSubrepPathByPropKeys( "mycompany.local.jr.gui.rep.subrep1.parentdir", "mycompany.local.jr.gui.rep.subrep1.name")
    • $P{REPORT_SCRIPTLET}.getSubrepPath(...)在这里不起作用:-((我不知道为什么)
  • 当您将所有文件放在服务器上时,不要忘记重新启动服务器

4 :当然我在这里仍然看到一些小的改进,但它似乎比我迄今发现的所有丑陋的解决方案要好得多。改进我会看到:

  • 使用REPORT_SCRIPTLET或scriptlet功能可能不是最好的方法,但它可能适用于绝大多数用例
  • 虽然两个现有的Jasper类都表明他们似乎无法正确处理上述问题:

5 :相关的特殊处理在此编码:EnvScriptlet.java/getSubrepPath(String,String,boolean,String[])

简介(背景)

首先要知道的是,JasperStudio中的处理/设置 Jasper Server(存储库) 完全不同 > 5 ...

假设我们有以下环境:

  • 我们的Eclipse安装目录:C:\eclipse\
  • 我们的Eclipse(报告)工作区:C:\workspace\
  • 我们的报告项目:C:\workspace\report-project\
  • 我们的报告在C:\workspace\report-project\src/reports
  • 主报告C:\workspace\report-project\src/reports/masterrep.jrxml
  • 一些子报告C:\workspace\report-project\src/reports/subrep1.jrxml
  • 另一个子报告C:\workspace\report-project\src/reports/somesubdir/subrep2.jrxml
  • 工作区主报告中的BASE_DIR(在下一节中说明)设置为C:\workspace\report-project\src/reports/
  • 我们的主报告的Jasper Report Server GUI repo id-path将是:/x/y/z/ (不要与视觉命名路径混淆,例如可能是Financial Reports/Expenses/Current Year

一般来说:Jasper Studio,JasperServer

(和其他" Jasper运行时环境"像自定义Java Jasper包使用):

  • 宣布报告参数"前缀"似乎良好做法这取决于您的Jasper运行时环境,例如名为 BASE_DIR
    • 这里重要的是,假设后缀 / 可能包括 1 似乎最好,因为有些情况下你可能/想要以一种空的方式使用它,或者#34; unslashed"路径表达
      • e.g。应该解决的$P{BASE_DIR} + "subrep1.jrxml" repo:subrep1.jrxml
    • 参见例如here了解更多详情(查找SUBREPORT_DIR

1 :在处理类似目录的结构时,我个人觉得这是一个不好的做法(在这方面没有看Jasper Reports)

JasperStudio Designer(Eclipse插件)

(具有更多功能的官方IReport继任者)

(如果您不使用预览功能,这可能对您无趣)

  • 不幸的是我发现没有实际的方法可以完全支持(正常)"团队开发"与子报告(以及可能还有其他相关资源),这里的意思是(目前对我不知道)不可能分离本地路径和* .jrxml文件 :-(
    • e.g。如果你有一个版本控制系统并且在不同的环境(repos和/或不同的开发人员的不同本地路径)中工作,主报告必须以某种方式包含子报告的本地路径
      • 我尝试了不同的失败方法:
      • BASE_DIR中的相对路径表达式不起作用,因为工作目录是eclipse目录,例如C:\eclipse
      • Eclipse->Window->Preferences->JasperStudio->Properties->Add例如 my.base.dir
        • 在预览模式下无法使用,例如通过new java.io.File(System.getProperty("my.base.dir")).getCanonicalPath() + "/"获取BASE_DIR表达式(这些道具可能仅供设计师使用,但未在预览中设置)
      • 以防你偶然发现(就像我一样):Eclipse->Window->Preferences->JasperStudio->Report Execution->Virtualizer Temporary Path是与报告结果存储无关的(在这里没用)和#34;缓存"
      • 当然我可以编写一个ANT任务来根据每次使用/结账时的正则表达式过滤器副本替换这些本地模式,但这似乎不是处理此问题的好方法
  • 如果您只想使用 *.jrxml个文件(就像我做 3 ),您必须像这样引用一些subrep1.jrxml:<强> net.sf.jasperreports.engine.JasperCompileManager.compileReport($P{BASE_DIR} + "subrep1.jrxml")

3 :我不明确地需要*.jasper个文件,并且不明白为什么我要处理它们.BTW JasperServer WebGUI似乎只支持上传*.jrxml个文件)

JasperServer Web GUI

(例如,由某些Tomcat应用程序服务器提供并将其数据存储在某些postgres数据库中)

场景1:引用附加的子报告资源

  • 如果您不想重复使用报告,将supreport添加到主报告中似乎很好(因此在GUI回购树中不可见 - 请参阅以下子项,如何在主数据库之外引用它反正)
  • 如果您附加子报告,则通常应将文件名作为其资源ID ,例如我们上面的subrep1.jrxml上传了资源ID为subrep1.jrxml(从而使本地设计引用和服务器引用的处理变得不那么复杂)
  • 通过上面的示例报告,我们必须在待上传的主报告中设置 BASE_DIRrepo:
    • 因此子报表表达式$P{BASE_DIR} + "subrep1.jrxml"$P{BASE_DIR} + "somesubdir/subrep2.jrxml"也可以在服务器上运行
    • 不推荐!:您仍然可以使用绝对路径引用其他报告中的这些报告,例如 2 repo:/x/y/z/masterrep.jrxml_files/masterrep.jrxml_

2 :在这种情况下我不推荐;它没有记录,可能会改变;最好把你的子报告放到&#34; GUI repo路径&#34; as如下所述)

场景2:引用repo子报告资源

  • 假设我们将子报告上传到主repo id-path /x/y/z/(如上图所示)

  • 我们必须区分两个不同的用例

    • 我们想要将子报告用作独立报告(它将始终只包含在其他主报告中)

      • 在这种情况下,我们应该使用 Add Resource->File->JRXML 上传并引用它

      • ../subrep1.jrxml./subrep1.jrxml不起作用,因为基础逻辑似乎无法处理相对路径表达式.. (并且可能.)(这实际上很不错:-()

      • 所以我们要做的就是在masterrep.jrxml的 BASE_DIR 中提供绝对规范路径例如repo:/x/y/z/

    • 我们希望将子报告用作独立报告

      • 在这种情况下,我们应该使用 Add Resource->JasperReport

      • 上传它
      • 这显然会创建一个包含报告本身和其他资源的隐藏文件夹repo:/x/y/z/subrep1.jrxml_files

      • 这就是为什么我们不仅要调整BASE_DIR(如上所述),还要将子报表表达式调整为,例如。 $P{BASE_DIR} + "subrep1.jrxml_files/subrep1.jrxml_" (指向子报告本身)

    • 可能会删除net.sf.jasperreports.engine.JasperCompileManager.compileReport(...)包装功能,因为服务器自动执行此操作用于*.jrxml个文件

      < / LI>
    • 我没有完全调查一些其他可能不正确使用的方法,这些方法对我来说无法解决上述问题(也许其他人在这里有一些结果/更正):

      • $P{REPORT_FILE_RESOLVER}.resolveFile("subrep1.jrxml")(NullPointerException)
      • 导致主报告中出现空子报表部分:
        • $P{REPORT_CONTEXT}.getRealPath("subrep1.jrxml")
        • $P{REPORT_CONTEXT}.getProperty("REPORT_FILE_RESOLVER").resolveFile("subrep1.jrxml")

其他提示

因为我喜欢自动化报表设计和部署过程,所以我写了一些 ANT任务来处理本地* .jrxml文件以便部署* .jrxml关于BASE_DIR和其他转换的文件转换。

SQL 有助于轻松调查 jasper服务器postgres元数据库中的资源ID路径结构(类似jdbc:postgresql://myjasperhost/jasperserver连接,例如与postgres用户连接) :

select
    f.id as folder_id,
    r.id as res_id,
    case when f.hidden = true then 1 else 0 end as hidden,
    f.uri||case when f.uri = '/' then '' else '/' end||coalesce(r.name,'') as res_uri,
    r.resourcetype,
    r.creation_date,
    r.update_date,
    f.uri,
    r.name,
    -- less important
    r.version,
    r.parent_folder,
    r.childrenfolder,
    f.parent_folder,
    f.version,
    f.name
-- select *
from jiresourcefolder f
    left outer join jiresource r on (r.parent_folder = f.id)
where not f.uri like '/themes%'
order by f.uri||coalesce(r.name,'')

相关问题

有关此问题的Jaspersoft论坛的问题包括:

答案 1 :(得分:3)

不确定此机制是否适用于所有情况,但它确实适用于JasperSoft Studio 5.6.0Jasper Reports Server 5.6.0

基本上我们需要一种简单的方法来检测我们在服务器上运行 - 我使用$P{REPORT_CONTEXT}参数的存在(或不存在),实验显示该参数存在于服务器上但在预览期间不存在。

<parameter name="OnServer" class="java.lang.Boolean" isForPrompting="false">
    <parameterDescription><![CDATA[Are we running on server]]></parameterDescription>
    <defaultValueExpression><![CDATA[Boolean.valueOf($P{REPORT_CONTEXT}!=null)]]></defaultValueExpression>
</parameter>

完成后,您可以从两个选项中定义子报告的位置:

<parameter name="SubReportProducts" class="java.lang.String" isForPrompting="false">
    <parameterDescription><![CDATA[The products subreport]]></parameterDescription>
    <defaultValueExpression><![CDATA[$P{OnServer}.booleanValue() ? "repo:OrderPicksheetProducts.jrxml" : "OrderPicksheetProducts.jasper"]]></defaultValueExpression>
</parameter>

然后包括子报告:

<subreportExpression><![CDATA[$P{SubReportProducts}]]></subreportExpression>

然后,您可以在工作室中使用Preview,并且在部署到服务器时仍可正常工作。

答案 2 :(得分:0)

我不是这个答案的100%但是:你必须将你的子报告作为jrxml资源上传并放入“repo://subreport.jrxml”才能使它工作。 如果您在这些日子中读到这一天,请告诉我它是否有效或您找到了哪些解决方案。 此致

答案 3 :(得分:0)

尝试完全删除扩展程序并使用“repo:/ subreportFolder / subreportName”。主报告在iReport中提取jasper文件,但是在jasperserver上你上传了jrxml。