【问题标题】:JasperServer: Unable to locate the subreport exceptionJasperServer:无法定位子报表异常
【发布时间】:2016-07-13 03:26:55
【问题描述】:

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

我有一份报告,其中包括多级子报告,在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 来修复此错误,

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

【问题讨论】:

  • 嗨 karimhammoda,如果我的回答对你有用,或者至少让你明白了,请接受我的回答。谢谢

标签: jasper-reports subreport jasperserver


【解决方案1】:

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 系统属性的任何其他方式也可以正常工作 - 已经设置的属性将覆盖加载的文件properties) 来配置不同的环境,包括你的

    • 当前环境信息通过 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_SCRIPTLET 或 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 报告服务器 GUI 存储库 ID 路径将是:/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
    • 参见例如here 了解更多详情(查找 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@987654382 @

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

JasperServer 网页界面

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

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

  • 如果您一般不想重复使用您的报告,将您的超级报告添加到您的主报告中似乎很好(因此它在 GUI 存储库树中不可见 - 请参阅下面的子项如何在您的主报告之外引用它无论如何)
  • 如果您附加子报告,它通常应该将其文件名作为其资源 ID,例如我们上面的subrep1.jrxml 使用subrep1.jrxml 的资源ID 上传(从而使本地设计参考和服务器参考的处理变得不那么复杂)
  • 以上面的示例报告为例,我们必须在要上传的主报告中将我们的 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 存储库路径”,如下所述)

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

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

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

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

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

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

      • 所以我们在这里要做的是在我们的 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 文件执行此操作

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

      • $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 文件以进行部署 *关于BASE_DIR 和其他转换的.jrxml 文件转换。

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 论坛上与此相关的问题包括:

【讨论】:

  • 我通过 jasper utils 包提供了一些 *.jar 功能来简化答案。因此,进一步的简化/修改可能会隐藏在那里。
  • 使用报告特定资源包(包含子报告路径等特定属性)甚至更容易(没有 jasper-utils.jar)等可通过 $R{subrep1.parentdir} 引用),report-unit-附加 jars(不需要为更改/更新而重新启动全局服务器),而所有这些也可以是 链接资源,因此易于重复使用,避免冗余。稍后我会相应地更新我的答案。
【解决方案2】:

不确定这种机制是否适用于所有情况,但它肯定适用于 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,当您部署到服务器时,一切仍然有效。

【讨论】:

  • 这个答案对我很有帮助。但是,我没有使用 Jasper Reports Server(所以我不能使用参数 REPORT_CONTEXT 来决定我是否在服务器上),我正在从数据库中读取 JasperReport 实例,并在 Java 代码中将其设置为参数 @ 987654330@。我的subreportExpression$P{SUBREPORT} != null ? $P{SUBREPORT} : "subreport.jasper"。这样的 JRXML 报告及其子报告在 Java 代码和 JasperSoft Studio 6.3.1 中都适用,无需任何 JRXML 更改。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 2013-03-09
      • 1970-01-01
      • 1970-01-01
      • 2016-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-23
      • 1970-01-01
      相关资源
      最近更新 更多