JasperReports — это система построения отчётов для платформы Java от компании JasperSoft. Достоинства этой системы состоят, в частности, в возможности экспорта построенных отчётов во многие популярные форматы: HTML, PDF, RTF и др.

Эта статья является очень кратким руководством по составлению отчётов в системе JasperReports и работе с ними. Цель статьи в том, чтобы в нескольких словах дать ключ к пониманию основных возможностей системы и структуры отчётов.

Для знакомства с шаблонами Jasper желательно установить программу для построения шаблонов. Две основные программы от Jaspersoft — это Jaspersoft Studio и iReport Designer. Вторая программа считается устаревшей, но существует мнение (его разделяет также и автор этой статьи), что iReport Designer обладает более дружественным интерфейсом.

Основные сведения

Шаблон отчёта — это файл .jrxml в XML-формате, в котором хранится структура отчёта, его дизайн и логика.

Входные данные отчёта — это параметры и источник данных (data source).

Параметры — это входные аргументы. По сути это переменные языка Java. Их значения неизменны во всём отчёте. Например, если нужно в заголовке отчёта на каждой странице выводить один и тот же текст, который генерируется перед показом отчёта, то можно передать его в отчёт как параметр.

Источник данных — это коллекция записей, каждая из которых представляет набор полей (переменных языка Java).

Для вывода текста в отчётах используются два основных компонента: Text Field (динамическое поле) и Static Text (статическое поле). Динамическое поле используется для вывода значения параметров или полей источника данных, а статическое — для вывода постоянного текста.

Отчёты состоят из секций, которые также называются bands (полосы). Секции следуют одна за другой строго по вертикали. Каждая секция принадлежит к определённому типу, который влияет на её отображение в отчёте:

  • Title — только в начале отчёта;
  • Page Header — вверху каждой страницы;
  • Column Header — в начале столбца отчёта;
  • Detail — для каждой записи в источнике данных;
  • Column Footer — в конце столбца отчёта;
  • Page Footer — внизу каждой страницы;
  • Last Page Footer — внизу последней страницы (вместо Page Footer);
  • Summary — в конце отчёта;
  • No Data — вместо всех остальных секций, если источник данных не содержит записей;
  • Background — на заднем плане каждой страницы.

Примечание: изменить количество столбцов в отчёте можно с помощью свойства Column Count. В Jaspersoft Studio изменить это свойство можно с помощью диалогового окна Page Format, которое вызывается из панели свойств отчёта.

Пример шаблона:

jasper-notes-bands-template

В этом шаблоне 8 секций, из них 4-я сверху — Detail. Поля, в которых записаны строки «Title», «Field 1:», «Field 2:», «Record number:» и «Summary» — статические, остальные — динамические. Как видно, в динамических полях допустимо использовать конструкции языка Java.

Для примера в отчёт передано следующее содержимое источника данных:

<root>
	<datasource>
		<field1>value 1-1</field1>
		<field1>value 1-2</field1>
	</datasource>
	<datasource>
		<field1>value 2-1</field1>
		<field2>value 2-2</field2>
	</datasource>
	<datasource>
		<field1>value 3-1</field1>
		<field2>value 3-2</field2>
	</datasource>
	<datasource>
		<field1>value 4-1</field1>
		<field2>value 4-2</field2>
	</datasource>
	<datasource>
		<field1>value 5-1</field1>
		<field2>value 5-2</field2>
	</datasource>
	<datasource>
		<field1>value 6-1</field1>
		<field2>value 6-2</field2>
	</datasource>
	<datasource>
		<field1>value 7-1</field1>
		<field2>value 7-2</field2>
	</datasource>
	<datasource>
		<field1>value 8-1</field1>
		<field2>value 8-2</field2>
	</datasource>
	<datasource>
		<field1>value 9-1</field1>
		<field2>value 9-2</field2>
	</datasource>
	<datasource>
		<field1>value 10-1</field1>
		<field2>value 10-2</field2>
	</datasource>
</root>

В результате сгенерирован отчёт следующего вида:

jasper-notes-bands-report

Если нужно вывести в отчёте номер странице, номер записи, количество записей и т.д., можно использовать переменные.

Пример показа общего количества записей и количества записей на странице. Шаблон отчёта:

jasper-notes-variables-template

Результат:

jasper-notes-variables-report-1jasper-notes-variables-report-2

Особенности вёрстки

Обычная ситуация — когда в отчёте встречаются текстовые поля, размер которых может увеличиваться, если текст в них не умещается.

Рассмотрим отчёт такого вида:

jasper-notes-stretch-template

Допустим, что первое динамическое поле может растягиваться по высоте. Чтобы размер поля автоматически подстраивался под текст, нужно установить у поля свойство Stretch With Overflow = true (иначе при показе отчёта часть текста, которая не уместится внутри поля, просто пропадёт).

Однако установки одного только этого свойства в данном случае недостаточно, как видно из результата построения отчёта:

jasper-notes-stretch-report-1

Поле, растянувшись, перекрывает другие поля. Для решения этой проблемы существует свойство Position Type. Оно определяет, как элемент располагается на форме относительно границ формы или остальных элементов. Значение по умолчанию — Fix Relative To Top, то есть расстояние от элемента до верхней границы секции фиксировано. Попробуем установить для 3-х нижних полей значение Fix Relative To Bottom. Результат:

jasper-notes-stretch-report-2

Дело в том, что высота секции увеличивается вместе с высотой 2-го сверху поля. 3 поля, которые расположены ниже, привязаны к нижней границе секции — поэтому они сдвигаются вниз, и вёрстка отчёта не нарушается.

Можно усложнить пример, заставив 2-е динамическое поле также растянуться по высоте:

jasper-notes-stretch-report-3

Чтобы решить новые проблемы с вёрсткой, можно установить для 3-х нижних полей значение Position Type — Float.

jasper-notes-stretch-report-4

Как видно, установка такого значения этого свойства заставляет элементы правильно располагаться друг относительно друга.

Таблицы

Если в отчёте должна быть таблица, то первым делом необходимо её создать, добавив на форму элемент Table.

Для таблицы будет создан новый dataset. В этом dataset необходимо обозначить все поля, которые будут отображаться в таблице — аналогично полям отчёта.

Данные для таблицы берутся из отдельного источника данных. В свойствах таблицы в редакторе есть поле JRDatasource expression, которое обозначает, как должны быть получены данные для таблицы. Можно передать их в отчёт, например, как параметр, и тогда JRDatasource expression может быть указан так: $P{tableDataSource} .
Соответственно, при построении отчёта надо передать в него параметр «tableDataSource» типа net.sf.jasperreports.engine.JRDataSource . Если же нужно строить различные таблицы для каждой записи в источнике данных отчёта, то, очевидно, источник данных таблицы должен быть передан как поле источника данных отчёта.

Далее приведён пример таблицы в шаблоне отчёта.

jasper-notes-table-template

Секции таблицы — это почти то же самое, что и секции отчёта. В каждой секции находятся n элементов типа column, где n — количество столбцов в таблице. Внутри элемента column (который, вообще говоря, является ячейкой таблицы) можно создать одно или несколько текстовых полей.

В этом примере в dataset таблицы была также создана группа, у которой указан expression: $F{field1}  — это группа по полю field1. При создании группы визуальный редактор автоматически создаёт в таблице секции Group Header и Group Footer. Группы полезны, если записи в таблице необходимо сгруппировать по значению одного из полей.

Важно: в источнике данных записи, относящиеся к одной и той же группе, должны быть расположены подряд, без пропусков, иначе группа будет разбита на несколько частей. Это ограничение JasperReports.

В отчёт передано следующее содержимое источника данных:

<root>
	<datasource>
		<field1>first group</field1>
		<field2>value 1-1</field2>
		<field3>value 1-2</field3>
	</datasource>
	<datasource>
		<field1>first group</field1>
		<field2>value 2-1</field2>
		<field3>value 2-2</field3>
	</datasource>
	<datasource>
		<field1>first group</field1>
		<field2>value 3-1</field2>
		<field3>value 3-2</field3>
	</datasource>
	<datasource>
		<field1>second group</field1>
		<field2>value 4-1</field2>
		<field3>value 4-2</field3>
	</datasource>
	<datasource>
		<field1>third group</field1>
		<field2>value 5-1</field2>
		<field3>value 5-2</field3>
	</datasource>
	<datasource>
		<field1>third group</field1>
		<field2>value 6-1</field2>
		<field3>value 6-2</field3>
	</datasource>
	<datasource>
		<field1>third group</field1>
		<field2>value 7-1</field2>
		<field3>value 7-2</field3>
	</datasource>
	<datasource>
		<field1>third group</field1>
		<field2>value 8-1</field2>
		<field3>value 8-2</field3>
	</datasource>
	<datasource>
		<field1>third group</field1>
		<field2>value 9-1</field2>
		<field3>value 9-2</field3>
	</datasource>
	<datasource>
		<field1>third group</field1>
		<field2>value 10-1</field2>
		<field3>value 10-2</field3>
	</datasource>
	<datasource>
		<field1>third group</field1>
		<field2>value 11-1</field2>
		<field3>value 11-2</field3>
	</datasource>
</root>

Получился такой отчёт:

jasper-notes-table-report-1jasper-notes-table-report-2

В JasperReports нельзя объединять ячейки таблиц по горизонтали. Вместо этого можно создать видимость объединения ячеек, разместив в одном столбце по горизонтали несколько текстовых полей и особым образом настроив их границы. В частности, в следующем примере в одной ячейке создано 3 текстовых поля, и у 2-х правых добавлена видимая граница слева. Таблица выглядит так, будто у неё 3 столбца, хотя формально у неё 1 столбец.

Используя этот метод, можно столкнуться с трудностями, если данные не умещаются в текстовых полях:

jasper-notes-table-span-report-1

Для решения этой проблемы достаточно изменить у текстовых полей, рамки которых нужно дотянуть до нижней границы строки, значения свойства Stretch Type на Relative To Band Height. Тогда эти поля будут автоматически растягиваться по высоте строки:

jasper-notes-table-span-report-2

Пользовательские переменные

Для решения некоторых задач необходимо использовать пользовательские переменные. Переменные создаются в разделе Variables в обозревателе отчёта в редакторе. Самые важные свойства переменных:

  • Name — имя переменной;
  • Value Class Name — тип переменной, например java.lang.Integer ;
  • Calculation — агрегатная функция;
  • Expression — выражение;
  • Initial Value Expression — исходное значение;
  • Increment Type — периодичность вычисления агрегатной функции;
  • Reset Type — периодичность установки исходного значения.

Подробнее можно прочитать здесь: http://community.jaspersoft.com/wiki/variables.

К примеру, пусть необходимо построить отчёт, в котором секция detail для одной записи растягивается на несколько страниц, и необходимо начинать нумерацию заново для каждой записи. Для получения номеров страниц можно создать переменную, заданную следующим образом:

Name: detailPageNumber
Value Class Name: java.lang.Integer
Expression: $V{PAGE_COUNT} == 1 ? 1 : $V{detailPageNumber} + 1

Остальные свойства — по умолчанию.

Примечание: переменная PAGE_COUNT возвращает количество записей, показанных на странице. Если запись занимает несколько страниц отчёта, то на первой из этих страниц переменная возвращает 1, а на последующих — 0.

Подотчёты

Можно размещать внутри отчёта другие отчёты. Для этого нужно создать элемент типа Subreport.

Шаблон подотчёта передаётся с помощью свойства элемента Expression. Например, шаблон можно передать как параметр главного отчёта типа net.sf.jasperreports.engine.JasperReport .

Параметры и источник данных можно передать в подотчёт с помощью свойств Parameters Map Expression и Data Source Expression.

Компиляция и отображение

Перед тем, как отчёт может быть построен и отображён, его шаблон должен быть скомпилирован из исходного файла .jrxml в файл .jasper. Можно компилировать шаблоны с помощью Apache Ant с помощью задачи следующего вида:

<path id="jasperClasspath">
    <fileset dir="${application.dir}/lib">
        <include name="jasperreports-6.0.0.jar"/>
        <include name="commons-logging-1.1.1.jar"/>
        <include name="commons-digester-2.1.jar"/>
        <include name="commons-collections-3.2.1.jar"/>
        <include name="commons-beanutils-1.9.2.jar"/>
        <include name="groovy-all-2.0.1.jar"/>
    </fileset>
</path>

<path id="runClasspath"/>

<taskdef name="jrc" classname="net.sf.jasperreports.ant.JRAntCompileTask">
    <classpath refid="jasperClasspath"/>
</taskdef>

<delete dir="${application.dir}/build/reports"/>
<mkdir dir="${application.dir}/build/reports"/>
<jrc
    srcdir="${application.dir}/reports"
    destdir="${application.dir}/build/reports"
    tempdir="${application.dir}/build/reports"
    keepjava="true"
    xmlvalidation="true">
    <classpath refid="runClasspath"/>
    <include name="**/*.jrxml"/>
</jrc>

Если при компиляции шаблона возникают ошибки, возможно, что необходимо установить в настройках отчёта свойство Language = groovy.

Для отображения отчёта в GUI Swing можно использовать примерно такой код:

// items - коллекция записей
JRDataSource dataSource = new JRBeanCollectionDataSource(items);

Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put("parameter1", "value");

JasperReport report = (JasperReport) JRLoader.loadObjectFromFile("path/report1.jasper");
JasperPrint jasperPrint = JasperFillManager.fillReport(report, parameters, dataSource);

JFrame frame = new JFrame("Report window title");
frame.getContentPane().add(new JRViewer(jasperPrint));
frame.pack();
frame.setVisible(true);

Полезные ссылки

  1. Jaspersoft Business Intelligence
  2. Jaspersoft Community
  3. JasperReports — Ant Compile Sample
  4. How to display JasperReports Viewer inside a JPanel/JFrame?