Как передать основной источник данных отчета в вложенный отчет (JasperReports)?

Я использую JasperReports, и я заполняю JRDataSource для отчета. Теперь я хочу пройти главный REPORT_DATA_SOURCE на подотчете. Как я могу это сделать?

насколько я знаю REPORT_DATA_SOURCE является потребляемым объектом, поэтому его можно использовать только один раз, верно?. Могу ли я скопировать этот источник данных и передать его?

BTW: я использую iReport для создания макета.

5 ответов


вы можете пройти источник через встроенный 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>

Примечание: Используя то же самое (с мастер-отчетом) источник на отчета может привести к эффект потери первого ряда на отчета. Вы можете читать почему первая запись отсутствует в моем вложенном отчете? пост для понимания того, как избежать этой проблемы.


Да, вам нужно быть осторожным о том, как передать источник данных. С соединением 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; 
    } 
}

мы предполагаем, что параметр datasource является "dataSourceParam", а значение источника данных (список) - " 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>

"REPORT_DATA_SOURCE" является потребляемым объектом, вы можете использовать столько времени, сколько хотите.

Я тестирую источник данных как источник данных xml-файла и не будет отображаться, как сказал Алекс.

" Это не приведет к потере первой строки во вложенном отчете."

Я думаю, может быть, я использую xpath для выбора, поэтому каждый раз не будет записей потерь.

Если вы используете базы данных JDBC в качестве источника данных, пеалсе передать SQL в качестве параметра вложенного отчета.

Если вы используйте ResultSet в качестве параметра, возможно, потеряете одну запись при определении вложенного отчета в подробных полосах.


Это старый вопрос, на который уже ответили, но я передаю undelying bean во вложенный отчет, избегая потери первой записи или передачи всех записей во вложенный отчет. Это решение имеет то преимущество, что вложенный отчет может использоваться в качестве основного отчета и "просто" передает фактическую запись в качестве источника данных вложенного отчета (используя groovy как report lang):

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