主报表中的多个子报表使用相同的数据源
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>
我尝试了以下方法:
- 将子报表放在不同的详细信息区域中。
- 正在将 "Position Type" 设置为 "Float"。
- 正在将 "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()
方法中发生的事情相同。
我有一个包含 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>
我尝试了以下方法:
- 将子报表放在不同的详细信息区域中。
- 正在将 "Position Type" 设置为 "Float"。
- 正在将 "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()
方法中发生的事情相同。