主报表中的多个子报表使用相同的数据源

Multiple Subreports in Main Report using same datasource

我有一个包含 2 个子报表的主报表。我正在使用自定义数据源来获取报告内容。但是在 jasper studio 中预览主报表时只显示一个子报表(以先出现的子报表为准)。

例如。只有 report1.jrxml 得到 displayed.If 我删除了那个子报表然后显示 report2.jrxml。

main.jrxml

<detail>
    <band height="250">
        <subreport runToBottom="true">
            <reportElement positionType="Float" x="0" y="130" width="1960" height="120" uuid="89a9f872-756e-4c82-922d-537cfde30cca"/>
            <dataSourceExpression><![CDATA[$P{REPORT_DATA_SOURCE}]]></dataSourceExpression>
            <subreportExpression><![CDATA["report1.jrxml"]]></subreportExpression>
        </subreport>
    </band>
    <band height="250">
        <subreport runToBottom="true">
            <reportElement positionType="Float" x="0" y="90" width="1960" height="120" uuid="892c0849-9532-48cb-94c0-f2e87528232a"/>
            <dataSourceExpression><![CDATA[$P{REPORT_DATA_SOURCE}]]></dataSourceExpression>
            <subreportExpression><![CDATA["report2.jrxml"]]></subreportExpression>
        </subreport>
    </band>
</detail>

我尝试了以下方法:

  1. 将子报表放在不同的详细信息区域中。
  2. 正在将 "Position Type" 设置为 "Float"。
  3. 正在将 "Run To Bottom" 属性 设置为 "True"。

问题在于尝试对多个子报表使用相同的数据源。第一个子报表的数据源已耗尽,因此没有数据可用于后续子报表。

解法:

您必须使用 JRRewindableDataSource

倒回数据源

感谢 lucianc Community answer

任务总结:

创建一个包装器 RewindableDSWrapper 来回绕数据源并将所有调用委托给它。

package com.jasper.api;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRField;
import net.sf.jasperreports.engine.JRRewindableDataSource;

public class RewindableDSWrapper implements JRRewindableDataSource {

  private final JRRewindableDataSource ds;

  public RewindableDSWrapper(JRRewindableDataSource ds) {

    this.ds = ds;

    try {
        this.ds.moveFirst();
    } catch (JRException e) {
        e.printStackTrace();
    }

  }

  public boolean next() throws JRException {

    return ds.next();

  }

  public Object getFieldValue(JRField jrField) throws JRException {

    return ds.getFieldValue(jrField);

  }

  public void moveFirst() throws JRException {

    ds.moveFirst();

   }

 }

在您的自定义数据源中class实现 JRRewindableDataSource 接口。

public void moveFirst() throws JRException {
    // provide logic for rewinding datasource
}

在您的 jrxml 文件中,如果您的数据源是自定义的,那么

<dataSourceExpression><![CDATA[new com.jasper.api.RewindableDSWrapper((JRRewindableDataSource)$P{REPORT_DATA_SOURCE})]]></dataSourceExpression>

您将 REPORT_DATA_SOURCE 转换为 JRRewindableDataSource,因为编译器会尝试将其转换为 JRDataSource。

同时将包含 RewindableDSWrapper class 的 jar 文件添加到您工作室的 class 路径中。

我找到了不需要额外 java 类 的替代解决方案。如果您的数据源是 JRBeanCollectionDataSource,您可以像这样在 dataSourceExpression 字段中调用方法 cloneDataSource()

<dataSourceExpression><![CDATA[$P{REPORT_DATA_SOURCE}.cloneDataSource()]]></dataSourceExpression>

这将实例化一个新的迭代器,这与 moveFirst() 方法中发生的事情相同。

documentation