4

我搜索了几天来修复这个错误,没有什么新东西。

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

当我尝试将它部署到我的JasperServer. 当我尝试上传第一个主报告时,iReport向导让我附加subreport.jrxml资源文件夹中的第一个并使用repo:subreport.jrxmlor访问它repo:subreport.jasper。然后我手动上传二级子报表并做同样的事情将子报表表达式更改为repo:subreportA.jasperand repo: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

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

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

4

4 回答 4

10

Longtalk 之前的 Smalltalk ;)

(当然我不想鼓励你阅读这篇冗长的详细帖子的所有内容!粗体标记可能已经足以解决你的问题,但我发现值得更详细地记录这些棘手的东西!)

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

(如果希望有的话,我会在这里更新我的或其他发现)

捷径细节/最佳实践?!4

直到 Jasper 功能本身提供了类似的“包装”解决方案......

为了解决与在本地以预览模式或在 JasperServer 上远程运行 *.jrxml、*.jasper 文件相关的所有问题,我现在使用以下方法,它只允许使用单个 *.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(包含 ANT 构建魔法)      
        |- build.properties(包含全局属性)      
        |- local.properties(在版本控制中被忽略,例如 .hgignore,从 local.template.properties 生成的用户特定)
        |- local.template.properties(生成上述 local.properties 的 ANT 构建任务的源代码)
           |- mycomp.local.proj.reporting.dir=D:/reporting
        |- 源/报告
           |- jr.utl.properties(在版本控制中被忽略,用户特定根据下面的模板生成)
           |- jr.utl.template.properties(生成上述 jr.utl.properties 的 ANT 构建任务的源代码)
              jr.utl.env=${用户名}
              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_SCRIPTLETor scriptlet 功能可能不是最好的方法,但它可能适用于绝大多数用例
  • 尽管两个现有的 Jasper 类都表明了这一点,但它们似乎无法正确处理上述问题:

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

简介(背景)

首先要知道的是,JasperStudio 中的处理/设置与Jasper Server (Repository) 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 因为在某些情况下您可能拥有/想要以应该是空或“未斜线”路径表达式的方式使用它
      • 例如$P{BASE_DIR} + "subrep1.jrxml",应该解决 repo:subrep1.jrxml
    • 有关更多详细信息,请参见此处(查找SUBREPORT_DIR

1:在处理类似目录的结构时,我个人认为一般来说这是一种不好的做法(在这方面不看 Jasper 报告))

JasperStudio Designer(Eclipse 插件)

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

(如果您不使用预览功能,您可能对此不感兴趣)

  • 不幸的是,我发现没有实用的方法来完全支持(正常)“团队开发”与子报告(以及可能的其他相关资源),这意味着(目前对我来说未知)不存在分离本地路径和 *.jrxml 文件的可能性: -(
    • 例如,如果您有一个版本控制系统并在不同的环境中工作(到 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处理报告结果“缓存”的存储是不相关的(在这里没用)
      • 当然,我可以编写一个 ANT 任务来根据每次使用/结帐时的正则表达式过滤器副本替换这些本地模式,但这似乎不是处理这个问题的好方法
  • 如果您只想处理*.jrxml文件(就像我一样3),您必须参考subrep1.jrxml以下内容:net.sf.jasperreports.engine.JasperCompileManager.compileReport($P{BASE_DIR} + "subrep1.jrxml")

3:我不需要这些*.jasper文件,也不明白为什么要处理它们。顺便说一句,JasperServer WebGUI 似乎只支持*.jrxml文件上传)

JasperServer Web 图形用户界面

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

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

  • 如果您一般不想重用您的报告,将您的支持添加到您的主报告似乎很好(因此它在 GUI 存储库树中不可见 - 请参见下面的子项,无论如何您如何在您的主报告之外引用它)
  • 如果您附加您的子报告,它通常应该将其文件名作为其资源 id,例如,我们subrep1.jrxml从上面上传的资源 id 为subrep1.jrxml(从而使本地设计参考和服务器参考的处理不那么复杂)
  • 以上面的示例报告为例,我们必须在要上传的主报告中设置BASE_DIR我们repo:
    • 因此子报表表达式$P{BASE_DIR} + "subrep1.jrxml"$P{BASE_DIR} + "somesubdir/subrep2.jrxml"应该在服务器上工作
    • 不推荐!:您仍然可以从具有绝对路径的其他报告中引用这些报告,例如2repo:/x/y/z/masterrep.jrxml_files/masterrep.jrxml_

2:在这种情况下我不建议这样做;它没有记录并且可能会改变;最好将您的子报告放入“GUI repo path”中,如下所述)

场景 2:参考 repo 子报告资源

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

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

    • 我们不想子报表用作独立报表(它总是只包含在其他主报表中)

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

      • ../subrep1.jrxml或者./subrep1.jrxml不起作用,因为似乎底层逻辑无法处理相对路径表达式..可能.也不是)(这实际上会很好:-()

      • 所以我们在这里要做的是在我们的 masterrep.jrxml中提供一个绝对规范的路径,例如BASE_DIRrepo:/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文件执行此操作

    • 我没有完全调查其他一些可能被错误使用的方法,这些方法对我解决上述问题不起作用(也许其他人在这里有一些结果/更正):

      • $P{REPORT_FILE_RESOLVER}.resolveFile("subrep1.jrxml")(空指针异常)
      • 导致主报告中的子报告部分为空:
        • $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 论坛上与此相关的问题包括:

于 2013-12-04T11:45:34.720 回答
3

Not sure if this mechanism works in all cases but it certainly works for JasperSoft Studio 5.6.0 and Jasper Reports Server 5.6.0.

Essentially we need a simple way to detect that we are running on the server - I use the presence (or absence) of the $P{REPORT_CONTEXT} parameter which experiments show is present on the server but not present during preview.

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

Once you have that you can then define the location of your subreport from a choice of two:

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

And then include the sub report:

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

You can then use Preview in studio and all still works when you deploy to server.

于 2014-07-29T11:23:47.123 回答
0

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

于 2012-08-02T13:56:17.737 回答
0

我不是这个答案的 100%,但是:您必须将您的子报告作为 jrxml 资源上传并放置“repo://subreport.jrxml”才能使其工作。如果你在那一天读到这篇文章,请告诉我它是否有效或你找到了什么解决方案。问候

于 2011-03-21T11:47:18.507 回答