Примеры отчетов
Пример XLS-отчета
Данный пример основан на демо-приложении Library. Следуйте инструкциям, чтобы настроить проект, а затем создайте объекты и экраны.
В этом примере мы сгенерируем отчет для автора книги. При наличии автора в отчете будут указаны его книги, издатель каждой книги, в каком отделе библиотеки хранилась книга и сколько книг хранилось в каждом отделе. Готовый отчет выглядит следующим образом:
-
Figure 2. Структура данных отчета
Рассмотрим полосы отчета.
-
Полоса header – заголовок отчета. Содержит набор данных с Groovy-скриптом, выводящим значения внешних параметров отчета:
[['authorName' : (params['author'].firstName + ' ' + params['author'].lastName)]]
-
Полоса book выводит список книг путем выполнения следующего SQL-запроса:
select b.name as book_name, b.id as book_id from JMXRPR_BOOK b join JMXRPR_AUTHORS_BOOKS ba on ba.book_id = b.id join JMXRPR_AUTHOR a on a.id = ba.author_id where a.id = ${author}
В данном запросе используется внешний параметр отчета –
author
. Параметр имеет тип Entity, однако в SQL-запросах его можно напрямую сравнивать с полями-идентификаторами сущностей, преобразование будет выполнено автоматически. -
Вложенная в book полоса publisher выводит издателей книги путем выполнения следующего SQL-запроса:
select p.name as publisher, bp.year_, p.id as publisher_id from JMXRPR_BOOK_PUBLICATION bp join JMXRPR_PUBLISHER p on p.id = bp.publisher_id where bp.book_id = ${book.book_id}
В данном запросе в качестве параметра используется поле родительской полосы –
book_id
. Таким образом осуществляется связь между родительской и дочерней полосами. -
Вложенная в publication полоса publisher выводит издания книги путем выполнения следующего SQL-запроса:
select ld.name as department, sum(bi.book_count) as amount from JMXRPR_BOOK_INSTANCE bi join JMXRPR_BOOK_PUBLICATION bp on bp.id = bi.book_publication_id join JMXRPR_LIBRARY_DEPARTMENT ld on ld.id = bi.library_department_id where bp.publisher_id = ${publisher.publisher_id} and bp.book_id = ${book.book_id} group by ld.name
В данном запросе в качестве параметров используются поля обоих родительских полос –
book_id
иpublisher_id
.
-
-
Параметры отчета.
На вкладке Parameters and Formats объявлен один внешний параметр отчета –
Author
:Figure 3. Параметры отчетаЭтот параметр запрашивается у пользователя при запуске отчета. Выбор автора производится через экран
Author.browse
, имеющийся в приложении. -
Шаблоны отчета.
На вкладке Templates определен один шаблон формата XLS, загруженный из файла BooksByAuthor.xls
Figure 4. Шаблоны отчета -
Локализация названия отчета.
На вкладке Localization задано название отчета для русской локали:
ru = Книги по автору
Вызовите отчет на исполнение из общего списка в экране Reports → Run Reports.
Пример перекрестного отчета
Данный пример основан на демо-приложении Library. Следуйте инструкциям, чтобы настроить проект, а затем создайте объекты и экраны.
В этом примере мы создадим перекрестный отчет для отделов библиотеки, чтобы показать, сколько книг каждый отдел приобретал каждый месяц. Отчет расширяется как по вертикали, так и по горизонтали и агрегирует количества книг по каждому отделу и каждому месяцу:
Для создания отчета выберите ориентацию полосы Crosstab на вкладке Report structure редактора отчетов. При выборе этой ориентации к полосе автоматически добавляются три набора данных:
-
<band_name>
_dynamic_header – данные из этого набора заполняют отчет значениями слева направо, то есть он ведет себя, как вертикальная полоса с заголовками столбцов матрицы. -
<band_name>
_master_data – данные из этого набора заполняют отчет значениями сверху внизу, то есть он ведет себя, как горизонтальная полоса с заголовками строк матрицы. -
<band_name>
– набор данных, названный так же, как полоса, в которой он создан. Этот набор содержит данные для заполнения ячеек матрицы.
Создадим перекрестный отчет для сущности BookInstance
из демо-приложения Library со следующей структурой:
-
Структура данных отчета. Есть три набора данных:
-
bi_dynamic_header
возвращает список названий месяцев:bi_dynamic_header datasetimport java.text.DateFormatSymbols List result = new ArrayList() DateFormatSymbols dateFormatSymbols = DateFormatSymbols.getInstance(Locale.ENGLISH) for (i in 0..dateFormatSymbols.months.length - 1) { result.add(["header_id" : i + 1, "month_name" : dateFormatSymbols.months[i]]) } return result
-
bi_master_data
возвращает имена и идентификаторы отделов библиотеки, выбранных пользователем в качестве внешнего параметра отчета:bi_master_data datasetselect name as name, id as department_id from JMXRPR_LIBRARY_DEPARTMENT where id in (${selected_departments})
-
Набор данных
bi
генерирует данные для заполнения ячеек матрицы, то есть сумму книг за конкретный месяц и отдел. Он используетbi_master_data@department_id
(идентификатор покупателя) как вертикальную координату ячейки иbi_dynamic_header@header_id
(название месяца) как горизонтальную координату, а затем заполняет ячейку суммой значенийamount
.В примере ниже мы использовали два дополнительных внешних параметра:
start_date
иend_date
, которые определяют временной диапазон заказов. Мы рекомендуем использовать перекрестную валидацию значений введенных параметров, чтобы избежать ошибок, вызванных неправильным диапазоном дат.bi datasetselect bi.library_department_id as bi_master_data@department_id, month(bi.created_date) as bi_dynamic_header@header_id, sum(bi.book_count) as "amount" from JMXRPR_BOOK_INSTANCE bi where bi.created_date >= ${start_date} and bi.created_date<= ${end_date} and bi.library_department_id in (${bi_master_data@department_id}) and month(bi.created_date) in (${bi_dynamic_header@header_id}) group by bi.library_department_id,month(bi.created_date) order by bi.library_department_id,month(bi.created_date)
-
-
Параметры отчета.
На вкладке Parameters and Formats объявлены внешние параметры отчета –
selected_departments
,start_date
,end_date
:Figure 7. Параметры отчетаЭти параметры запрашиваются у пользователя при запуске отчета. Выбор отдела производится через экран
jmxrpr_LibraryDepartment.browse
, имеющийся в приложении. -
Шаблон отчета.
Теперь создадим шаблон отчета, используя Microsoft Office или LibreOffice.
DepartmentBooks.xls – это пример шаблона, который выводит список
Departments
по вертикали иBooks
для каждого отдела по горизонтали, сгруппированный по месяцам создания книг.Данный шаблон отчета содержит именованные области для всех трех наборов данных перекрестной полосы, а также именованную область для заголовка столбца:
<band_name>_header
. В нашем случае этоbi_header
.
Запустить отчет можно из общего браузера на экране Reports → Run Reports.
Пример отчета JasperReports
Данный пример основан на демо-приложении Library. Следуйте инструкциям, чтобы настроить проект, а затем создайте объекты и экраны.
Создадим JRXML-шаблон, который выводит список публикаций книг, доступных в выбранном отделе:
-
Figure 9. Структура данных отчета
Рассмотрим полосы отчета.
-
Header – заголовок отчета. Она содержит набор данных с Groovy-скриптом, выводящим значение внешнего параметра отчета:
[['library_department_name' : params['library_department'].name]]
-
Полоса Data выводит список книг в выбранном отделе путем выполнения следующего Groovy-скрипта:
import reports.ex2.entity.LiteratureType def result = [] def ltList = dataManager.load(LiteratureType).all().list(); ltList.each(lt->{ def count = dataManager.loadValue("select sum(bi.bookCount) from jmxrpr_BookInstance bi where bi.libraryDepartment = :department and bi.bookPublication.book.literatureType = :lt ", Long) .parameter("department", params['library_department']).parameter("lt", lt) .one(); def refCount = dataManager.loadValue("select sum(bi.bookCount) from jmxrpr_BookInstance bi where bi.libraryDepartment = :department and bi.bookPublication.book.literatureType = :lt and bi.isReference = true", Long) .parameter("department", params['library_department']).parameter("lt", lt) .one(); result.add(['literature_type_name': lt.name, 'books_instances_amount': count, 'reference_books_instances_amount': refCount]) }); return result;
В данном запросе используется внешний параметр отчета –
library_department
. Параметр имеет тип Entity, однако его можно напрямую сравнивать с полями-идентификаторами сущностей, преобразование будет выполнено автоматически.
-
-
Параметры отчета.
На вкладке Parameters and Formats объявлен один внешний параметр отчета –
Department
:Figure 10. Параметры отчетаЭтот параметр запрашивается у пользователя при запуске отчета. Выбор отдела производится через экран
jmxrpr_LibraryDepartment.browse
, имеющийся в приложении. -
Шаблон отчета.
Создайте новый JRXML-файл (или скачайте BookAvailability.jrxml) со следующим содержимым:
BookAvailability.jrxml<?xml version="1.0" encoding="UTF-8"?> <!-- Created with Jaspersoft Studio version 6.4.0.final using JasperReports Library version 6.4.1 --> <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="books" pageWidth="595" pageHeight="842" whenNoDataType="AllSectionsNoDetail" columnWidth="535" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20"> <property name="template.engine" value="tabular_template"/> <property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/> <style name="Table_TH" mode="Opaque" backcolor="#066990"> <box> <topPen lineWidth="0.5" lineColor="#000000"/> <bottomPen lineWidth="0.5" lineColor="#000000"/> </box> </style> <style name="Table_CH" mode="Opaque" forecolor="#FFFFFF" backcolor="#06618F" hTextAlign="Center" fontSize="12"> <box> <topPen lineWidth="0.5" lineColor="#000000"/> <bottomPen lineWidth="0.5" lineColor="#000000"/> </box> </style> <style name="Table_TD" mode="Opaque" backcolor="#FFFFFF" hTextAlign="Center"> <box> <topPen lineWidth="0.5" lineColor="#000000"/> <bottomPen lineWidth="0.5" lineColor="#000000"/> </box> </style> <subDataset name="Data"> <field name="literature_type_name" class="java.lang.String"/> <field name="books_instances_amount" class="java.lang.Long"/> <field name="reference_books_instances_amount" class="java.lang.Long"/> </subDataset> <field name="library_department_name" class="java.lang.String"/> <title> <band height="72"> <frame> <reportElement mode="Opaque" x="-20" y="-20" width="595" height="92" backcolor="#006699"/> <staticText> <reportElement x="20" y="10" width="555" height="30" forecolor="#FFFFFF"/> <textElement textAlignment="Center"> <font size="20" isBold="true"/> </textElement> <text><![CDATA[Book availability in department]]></text> </staticText> <textField> <reportElement x="20" y="50" width="555" height="30" forecolor="#FFFFFF"/> <box> <pen lineWidth="1.0" lineColor="#FFFFFF"/> <topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> <leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> <bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> <rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> </box> <textElement textAlignment="Center" verticalAlignment="Middle"> <font fontName="SansSerif" size="20" isBold="true"/> </textElement> <textFieldExpression><![CDATA[$F{library_department_name}]]></textFieldExpression> </textField> </frame> </band> </title> <detail> <band height="204"> <componentElement> <reportElement x="0" y="4" width="555" height="200" forecolor="#FFFFFF"> <property name="com.jaspersoft.studio.layout" value="com.jaspersoft.studio.editor.layout.VerticalRowLayout"/> <property name="com.jaspersoft.studio.table.style.table_header" value="Table_TH"/> <property name="com.jaspersoft.studio.table.style.column_header" value="Table_CH"/> <property name="com.jaspersoft.studio.table.style.detail" value="Table_TD"/> <property name="net.sf.jasperreports.export.headertoolbar.table.name" value=""/> <property name="com.jaspersoft.studio.components.autoresize.proportional" value="true"/> </reportElement> <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"> <datasetRun subDataset="Data"> <dataSourceExpression><![CDATA[$P{REPORTING}.dataset("Data")]]></dataSourceExpression> </datasetRun> <jr:column width="188"> <jr:columnHeader style="Table_CH" height="30"> <staticText> <reportElement x="0" y="0" width="188" height="30" forecolor="#FFFFFF"/> <box> <pen lineColor="#FFFFFF"/> </box> <textElement textAlignment="Center" verticalAlignment="Middle"> <font fontName="SansSerif" size="12" isBold="true"/> </textElement> <text><![CDATA[Literature Type]]></text> </staticText> </jr:columnHeader> <jr:detailCell style="Table_TD" height="30"> <textField> <reportElement x="0" y="0" width="188" height="30"/> <textElement textAlignment="Center" verticalAlignment="Middle"> <font fontName="SansSerif" size="12"/> </textElement> <textFieldExpression><![CDATA[$F{literature_type_name}]]></textFieldExpression> </textField> </jr:detailCell> </jr:column> <jr:column width="186"> <jr:columnHeader style="Table_CH" height="30"> <staticText> <reportElement x="0" y="0" width="186" height="30" forecolor="#FFFFFF"/> <textElement textAlignment="Center" verticalAlignment="Middle"> <font fontName="SansSerif" size="12" isBold="true"/> </textElement> <text><![CDATA[Book Amount]]></text> </staticText> </jr:columnHeader> <jr:detailCell style="Table_TD" height="30"> <textField> <reportElement x="0" y="0" width="186" height="30"/> <textElement textAlignment="Center" verticalAlignment="Middle"> <font size="12"/> </textElement> <textFieldExpression><![CDATA[$F{books_instances_amount}]]></textFieldExpression> </textField> </jr:detailCell> </jr:column> <jr:column width="181"> <jr:columnHeader style="Table_CH" height="30"> <staticText> <reportElement x="0" y="0" width="181" height="30" forecolor="#FFFFFF"/> <textElement textAlignment="Center" verticalAlignment="Middle"> <font fontName="SansSerif" size="12" isBold="true"/> </textElement> <text><![CDATA[Reference Book Amount]]></text> </staticText> </jr:columnHeader> <jr:detailCell style="Table_TD" height="30"> <textField isBlankWhenNull="false"> <reportElement x="0" y="0" width="181" height="30" forecolor="#000000"/> <textElement textAlignment="Center" verticalAlignment="Middle"> <font size="12"/> </textElement> <textFieldExpression><![CDATA[$F{reference_books_instances_amount}]]></textFieldExpression> </textField> </jr:detailCell> </jr:column> </jr:table> </componentElement> </band> </detail> <pageFooter> <band height="17"> <textField> <reportElement mode="Opaque" x="0" y="4" width="515" height="13" backcolor="#E6E6E6"/> <textElement textAlignment="Right"/> <textFieldExpression><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression> </textField> <textField evaluationTime="Report"> <reportElement mode="Opaque" x="515" y="4" width="40" height="13" backcolor="#E6E6E6"/> <textFieldExpression><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression> </textField> <textField pattern="M/d/yy"> <reportElement x="0" y="4" width="280" height="13"/> <textFieldExpression><![CDATA[new java.util.Date()]]></textFieldExpression> </textField> </band> </pageFooter> </jasperReport>
Таблица в этом шаблоне привязана к дочернему источнику данных subDataset. Элемент
title
обращается к данным полосы Header напрямую. Вы можете заранее посмотреть, как будет выглядеть отчет, открыв шаблон в визуальном редакторе JasperReports.Загрузите новый шаблон в приложение, выбрав любой тип вывода, и сделайте его шаблоном по умолчанию:
Figure 11. Редактор шаблона
Запустить отчет можно из общего браузера на экране Reports → Run Reports.
Пример отчета HTML/PDF
Данный пример основан на демо-приложении Library. Следуйте инструкциям, чтобы настроить проект, а затем создайте объекты и экраны.
Создадим отчет кратких описаний книг с альбомной ориентацией страниц, нумерацией, а также фиксированными заголовком и подвалом на каждой странице, которые мы настроим через правила и свойства CSS. Формат вывода отчета – HTML с конвертацией в PDF:
-
Структура отчета
Создайте простой отчет без параметров. Запрос JPQL возвращает список всех книг с их локальными атрибутами:
name
andsummary
.Figure 13. Структура данных отчета -
Шаблон отчета.
Теперь создайте файл шаблона. Определите в нем блоки заголовка и подвала, которые должны выводиться на каждой странице итогового документа PDF. Также используйте свойство CSS
page-break-before
:always
, которое будет создавать разрыв страницы перед каждым новым блоком информации о книге.Используйте теги FreeMarker для вставки данных в тело отчета. См. полную документацию по FreeMarker.
<body> <h1>Books report</h1> <!-- Custom HTML header --> <div class="header"> Library book summaries </div> <!-- Custom HTML footer --> <div class="footer"> Address: William Road </div> <#assign books=Root.bands.Books /> <#list books as book> <div class="custom-page-start" style="page-break-before: always;"> <h2>Book</h2> <p>Name: ${book.fields.title}</p> <p>Summary: ${book.fields.summary}</p> </div> </#list> </body>
-
Правила CSS
Используйте следующий код CSS для разметки страницы PDF:
div.header { display: block; text-align: center; position: running(header); width: 100%; } div.footer { display: block; text-align: center; position: running(footer); width: 100%; }
Также используйте следующий CSS-код для настройки отобажения страницы в формате PDF и отступов для основного содержимого отчета, чтобы избежать наложения с заголовком и подвалом:
body { font: 12pt Georgia, "Times New Roman", Times, serif; line-height: 1.3; padding-top: 50px; } @page { /* switch to landscape */ size: landscape; /* set page margins */ margin: 0.5cm; @top-center { content: element(header); } @bottom-center { content: element(footer); } @bottom-right { content: counter(page) " of "counter(pages); } } .custom-page-start { margin-top: 50px; }
В итоге получился файл BookSummary.html со следующим содержанием:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Invoice</title> <style type="text/css"> body { font: 12pt Georgia, "Times New Roman", Times, serif; line-height: 1.3; padding-top: 50px; } div.header { display: block; text-align: center; position: running(header); width: 100%; } div.footer { display: block; text-align: center; position: running(footer); width: 100%; } @page { /* switch to landscape */ size: landscape; /* set page margins */ margin: 0.5cm; @top-center { content: element(header); } @bottom-center { content: element(footer); } @bottom-right { content: counter(page) " of "counter(pages); } } .custom-page-start { margin-top: 50px; } </style> </head> <body> <h1>Books report</h1> <!-- Custom HTML header --> <div class="header"> Library book summaries </div> <!-- Custom HTML footer --> <div class="footer"> Address: William Road </div> <#assign books=Root.bands.Books /> <#list books as book> <div class="custom-page-start" style="page-break-before: always;"> <h2>Book</h2> <p>Name: ${book.fields.title}</p> <p>Summary: ${book.fields.summary}</p> </div> </#list> </body> </html>
-
Создавая шаблон отчета, мы выберем тип шаблона Freemarker:
Figure 14. Редактор шаблонаЗапустить отчет можно из общего браузера на экране Reports → Run Reports.
HTML отчет с шаблонизатором Groovy
Данный пример основан на демо-приложении Library. Следуйте инструкциям, чтобы настроить проект, а затем создайте объекты и экраны.
Давайте создадим отчет, который выводит список книжных публикаций для выбранного города. Формат вывода по умолчанию – HTML:
-
Создайте отчет с набором данных JPQL:
Figure 16. Структура данных отчетаПолоса
BookPublications
выводит список публикаций путем выполнения следующего JPQL запроса:BookPublications datasetselect b.name as "book", p.name as "publisher" from jmxrpr_BookPublication bp left join bp.book b left join bp.publisher p where bp.town.id = ${town}
В запросе используется внешний параметр отчета –
town
. Параметр имеет тип Entity, однако его можно напрямую сравнивать с полями-идентификаторами сущностей, преобразование будет выполнено автоматически. -
Задайте параметр отчета:
На вкладке Parameters and Formats объявлен один внешний параметр отчета –
Town
:Figure 17. Параметр отчетаЭтот параметр запрашивается у пользователя при запуске отчета. Выбор города производится через экран
jmxrpr_Town.browse
, имеющийся в приложении. -
Создайте шаблон отчета:
Создайте новый HTML-файл (или скачайте PublicationByTown.html) со следующим содержимым:
PublicationsTemplate<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru"> <head> <title> Publications by town </title> <style type="text/css"> body { font: 12pt Georgia, "Times New Roman", Times, serif; line-height: 1.3; padding-top: 30px; } tbody tr { height: 40px; min-height: 20px } </style> </head> <body> <h1>Publications, published in <% out << "${Root.fields.town.name}" %> </h1> <% def bookPublications=Root.bands.BookPublications.fields %> <table class="report-table" border="1" cellspacing="2"> <thead> <tr> <th>Book</th> <th>Publisher</th> </tr> </thead> <tbody> <% bookPublications.title.eachWithIndex{ elem, index -> out << "<tr><td> ${bookPublications.book[index]} </td><td> ${bookPublications.publisher[index]} </td></tr>" } %> </tbody> </table> </body> </html>
Для формирования заголовка отчета используется значение входного параметра:
${Root.fields.town.name}
.Ниже определена переменная
bookPublications
:<% def bookPublications=Root.bands.BookPublications.fields %>
Эта переменная используется в теле таблицы для вывода полей отчета.
<% bookPublications.title.eachWithIndex{ elem, index -> out << "<tr><td> ${bookPublications.book[index]} </td><td> ${bookPublications.publisher[index]} </td></tr>" } %>
Загрузите новый шаблон в приложение, выбрав формат вывода HTML, установите переключатель Template type в значение Groovy template и сделайте его шаблоном по умолчанию:
Figure 18. Редактор шаблона отчета
Запустить отчет можно из общего браузера на экране Reports → Run Reports.