Как передать основной источник данных отчета в подотчет (JasperReports)?
Я использую JasperReports и заполняю JRDataSource
для отчета. Теперь я хочу пройти основной REPORT_DATA_SOURCE
в подотчет. Как я могу это сделать?
Насколько я знаю REPORT_DATA_SOURCE
это расходный объект, поэтому его можно использовать только один раз, верно? Могу ли я скопировать этот источник данных и передать его?
Кстати: я использую iReport для создания макета.
6 ответов
Вы можете передать источник данных через встроенный 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>
Примечание. Использование одного и того же (с основным отчетом) источника данных в подотчете может привести к потере первой строки в подотчете. Вы можете прочитать Почему первая запись отсутствует в моем подотчете? пост для понимания, как избежать этой проблемы.
Мы предполагаем, что параметром источника данных является "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>
Да, вы должны быть осторожны с передачей источника данных. С соединением 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;
}
}
"REPORT_DATA_SOURCE" - это расходный объект, вы можете использовать столько времени, сколько хотите.
Я протестировал источник данных как xml File dataSource и не появится, как сказал ALEX.
msgstr "это не будет терять первую строку в подотчете."
Я думаю, может быть, я использую xpath для выбора, поэтому каждый раз не будет записей потерь.
Если вы используете базу данных JDBC в качестве источника данных, pealse передает sql в качестве параметра для подчиненного отчета.
Если вы используете ResultSet в качестве параметра, возможно, будет потеряна одна запись при определении подотчета в подробных бэндах.
Это старый вопрос, на который уже дан ответ, но я могу передать неподходящий компонент в подотчет, чтобы избежать потери первой записи или передать все записи в подотчет. Преимущество этого решения заключается в том, что вложенный отчет можно использовать в качестве основного отчета, и он "просто" передает фактическую запись как источник данных вложенного отчета (используя 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>
У меня была ситуация, когда у меня был стол в подотчете. Подотчет содержит только полосу заголовка и сводную полосу с таблицей в сводке. Я также хотел использовать источник данных подотчета для таблицы, но не смог получить ни один из подходов в принятом ответе на работу. Итак, вот альтернативный подход, который отлично работает в версии 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"
или что-то в этом роде, иначе подотчет будет пустым, поскольку в нем нет данных.
Чтобы завершить ответ Алекса К., что действительно заставило меня работать, так это клонировать источник данных следующим образом:
<dataSourceExpression><![CDATA[((net.sf.jasperreports.engine.data.JRBeanCollectionDataSource) $P{REPORT_DATA_SOURCE}).cloneDataSource()]]></dataSourceExpression>