Примеры отчетов
Пример 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 возвращает список всех книг с их локальными атрибутами:
nameandsummary.
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.