如何将主报表数据源传递给子报表(JasperReports)?

时间:2011-12-13 14:08:21

标签: jasper-reports datasource report ireport subreport

我正在使用JasperReports并填写JRDataSource以获取报告。 现在,我想将主REPORT_DATA_SOURCE传递给子报表。我怎么能这样做?

据我所知,REPORT_DATA_SOURCE是一个可消耗的对象,所以它只能使用一次,对吗?我可以复制此数据源并将其传递吗?

BTW:我使用iReport创建布局。

7 个答案:

答案 0 :(得分:35)

您可以通过内置的 REPORT_DATA_SOURCE 参数传递数据源

示例:

<subreport>
    <reportElement x="261" y="25" width="200" height="100"/>
    <dataSourceExpression><![CDATA[$P{REPORT_DATA_SOURCE}]]></dataSourceExpression>
    <subreportExpression><![CDATA[$P{SUBREPORT_DIR} + "subreport.jasper"]]></subreportExpression>
</subreport>

您可以根据变量,参数或字段创建数据源的新实例。

样本:

<variable name="HeadingsCollection" class="java.util.Collection" calculation="System">
    <initialValueExpression><![CDATA[new java.util.ArrayList()]]></initialValueExpression>
</variable>
...
<subreport>
    <reportElement x="0" y="0" width="515" height="20"/>
    <subreportParameter name="ReportTitle">
        <subreportParameterExpression><![CDATA[$P{ReportTitle}]]></subreportParameterExpression>
    </subreportParameter>
    <dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($V{HeadingsCollection})]]></dataSourceExpression>
    <subreportExpression class="java.lang.String"><![CDATA["HeadingsReport.jasper"]]></subreportExpression>
</subreport>

另一个样本:

<field name="cast" class="java.util.Collection"/>
...
<subreport>
    <reportElement positionType="Float" x="15" y="25" width="245" height="20" isRemoveLineWhenBlank="true" backcolor="#99CCFF"/>
    <dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{cast})]]></dataSourceExpression>
    <subreportExpression class="java.lang.String"><![CDATA["JRMDbCastSubreport.jasper"]]></subreportExpression>
</subreport>

或者您可以通过参数:

传递数据源
<parameter name="SubreportDataSource" class="net.sf.jasperreports.engine.JRDataSource"/>
...
<subreport>
    <reportElement positionType="Float" x="15" y="25" width="245" height="20" isRemoveLineWhenBlank="true"/>
    <dataSourceExpression>$P{SubreportDataSource}</dataSourceExpression>
    <subreportExpression class="java.lang.String"><![CDATA["Subreport.jasper"]]></subreportExpression>
</subreport>

注意:子报告中使用相同的(使用主报告) datasource 可能会导致子报告中丢失第一行的效果 >。您可以阅读Why is the first record missing from my subreport?帖子,了解如何避免此问题。

答案 1 :(得分:1)

是的,您需要注意如何传递数据源。使用SQL连接,您只需传递像$P{REPORT_CONNECTION}这样的连接表达式。然后子报表有自己的SQL查询。

在您的情况下,您想要传递实际数据。根据细节,它可能就像定义像$P{REPORT_PARAMETERS_MAP}这样的参数映射表达式一样简单。它位于同一窗口中的不同选项卡上,您可以在iReport中设置子报表连接。通常这足以传递数据源。

但是你可能需要一些代码来处理事情。请考虑此示例,并在子报表中重复使用CSV数据源。您不能仅使用JRParameter.REPORT_DATA_SOURCE对象的原因是因为索引行指针永远不会重置,因此将原始对象传递到子报表将使记录集过早关闭。我们用最小的辅助类来解决这个问题:

package com.jaspersoft.untested_unsupported; 

import java.io.File; 
import java.io.FileNotFoundException; 
import net.sf.jasperreports.engine.JRDataSource; 
import net.sf.jasperreports.engine.data.JRCsvDataSource; 

public class CsvDataSourceFactory { 
    public static JRDataSource getDataSource(String fileName, boolean firstRowHeaders) throws FileNotFoundException { 
        JRCsvDataSource csvDs = new JRCsvDataSource(new File(fileName)); 
        csvDs.setUseFirstRowAsHeader(firstRowHeaders); 
        return csvDs; 
    } 
}

答案 2 :(得分:0)

我们假设datasource参数是“dataSourceParam”,数据源值(list)是“dataSourceList” 在java类我们把:

final Map<String, Object> params = new HashMap<String, Object>();
JRDataSource dataSource = new ListOfArrayDataSource( dataSourceList, 
                          new String[] {"date", "age", "adress", "email"});
params.put("dataSourceParam",dataSourceList);**

在我们放入参数声明的主报告模板中:

<parameter name="dataSourceParam" class="net.sf.jasperreports.engine.JRDataSource"/>

然后在子报告标记中输入:

<subreport isUsingCache="true">
    <reportElement key="subreport-1" stretchType="RelativeToTallestObject" isPrintRepeatedValues="false" x="112" y="45" width="338" height="29"/>
    <subreportParameter name="otherParameter">
        <subreportParameterExpression><![CDATA[$P{sumM1}]]></subreportParameterExpression>
    </subreportParameter>
    <dataSourceExpression><![CDATA[$P{dataSourceParam}]]></dataSourceExpression>
    <subreportExpression class="net.sf.jasperreports.engine.JasperReport"><![CDATA[$P{subReportFile}]]></subreportExpression>
</subreport>

答案 3 :(得分:0)

“REPORT_DATA_SOURCE”是一个可消耗的对象,您可以根据需要使用尽可能多的时间。

我已将数据源测试为xml文件dataSource,并且不会像ALEX所说的那样出现。

“这不会丢失子报告中的第一行。”

我想可能是我使用xpath来选择,所以每次都不会丢失记录。

如果您使用JDBC数据库作为数据源,则会将sql作为参数传递给子报告。

如果使用ResultSet作为参数,可能会丢失一条记录,因为您在详细频段中定义了子报表。

答案 4 :(得分:0)

这是一个已经回答的旧问题,但是我将未通过的bean传递给子报告,避免丢失第一条记录或将所有记录传递给子报告。 该解决方案的优点是子报表可以用作主报表,并且简单地&#34;将实际记录作为子报表数据源传递(使用groovy作为报表):

<subreport>
    <reportElement x="261" y="25" width="200" height="100"/>
    <dataSourceExpression><![CDATA[new JRBeanCollectionDataSource(
       $P{REPORT_DATA_SOURCE}.data.toList().subList($V{REPORT_COUNT}-1,$V{REPORT_COUNT})]]></dataSourceExpression>
    <subreportExpression><![CDATA[$P{SUBREPORT_DIR} + "subreport.jasper"]]></subreportExpression>
</subreport>

答案 5 :(得分:0)

我遇到了在子报表中有一个表的情况。子报表只有一个标题栏和一个摘要栏,表格在摘要中。我也想为表使用子报表数据源,但是无法获得公认的答案中的任何一种方法。因此,在6.6.0版中,这是一种行之有效的替代方法:

在主报告中:

        <subreport>
            <reportElement x="0" y="0" width="468" height="0" uuid="c057b890-3889-43dd-8634-bbf2e857cc0d"/>
            <subreportParameter name="partsList">
                <subreportParameterExpression><![CDATA[$F{drawingRevision}.getPartsList()]]></subreportParameterExpression>
            </subreportParameter>
            <subreportExpression><![CDATA["static/engineering/drawings/subreports/DrawingPartsList.jasper"]]></subreportExpression>
        </subreport>

这里的关键是List作为参数传递,而作为数据源传递,例如:

<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{drawingRevision}.getPartsList())]]></dataSourceExpression>

子报表然后包括:

...
<parameter name="partsList" class="java.util.List" isForPrompting="false"/>
...
<summary>
    <band height="60" splitType="Stretch">
        <componentElement>
            <reportElement key="table" style="table" x="0" y="0" width="468" height="60" uuid="09499b35-b122-4fe4-a2b3-d91d6a19b2ab"/>
            <jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" whenNoDataType="AllSectionsNoDetail">
                <datasetRun subDataset="PartList" uuid="87fcbcc9-f0f0-4397-87f2-237201fc1857">
                    <dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($P{partsList})]]></dataSourceExpression>
                </datasetRun>
...

请注意,在子报表中,您还需要包括属性whenNoDataType="AllSectionsNoDetail"或类似的内容,否则子报表将为空,因为它没有数据。

答案 6 :(得分:0)

只需完成Alex K的answer,对我来说真正起作用的是clone the data source,如下所示:

<dataSourceExpression><![CDATA[((net.sf.jasperreports.engine.data.JRBeanCollectionDataSource) $P{REPORT_DATA_SOURCE}).cloneDataSource()]]></dataSourceExpression>