Содержание
Данный документ является руководством по созданию отчетов в системах, разработанных на платформе CUBA.
Руководство предназначено для разработчиков и администраторов CUBA-приложений. Для успешной работы с генератором отчетов требуется как минимум понимание принципов работы реляционных баз данных и умение писать запросы на языке SQL. В некоторых случаях данные для отчетов удобнее извлекать с помощью языков JPQL или Groovy, поэтому знакомство с ними является полезным.
Настоящее Руководство, а также другая документация по платформе CUBA доступны по адресу www.cuba-platform.ru/manual.
Ядром генератора отчетов платформы является фреймворк YARG, распространяемый по свободной лицензии Apache 2.0. Документация по фреймворку доступна по адресу github.com/Haulmont/yarg/wiki.
Если у Вас имеются предложения по улучшению данного руководства, обратитесь пожалуйста в службу поддержки по адресу ru.cuba-platform.com/support/topics.
При обнаружении ошибки в документации укажите, пожалуйста, номер главы и приведите небольшой участок окружающего текста для облегчения поиска.
Создание отчета в системе заключается в создании двух взаимосвязанных элементов: шаблона визуального представления и описания извлекаемых для отчета данных. Шаблон создается в формате XLS(X), DOC(X), ODT, HTML внешними средствами, а описание данных отчета производитсяв экране дизайнера отчетов.
Сгенерированный отчет в зависимости от заданных при описании параметрови исходного шаблона может быть выдан в форматах PDF, XLS(X), DOC(X), HTML.
Структура данных, выводимых отчетом, может быть либо описана в дизайнере отчета путем создания полос, запросов и других элементов, либо запрограммирована в классе Java, реализующим специальный интерфейс. Отчет может принимать параметры от пользователя, либо из вызывающего кода. Для отчета можно задать, каким пользователям он доступен, и в каких экранах системы он должен появляться.
Основные компоненты генератора отчетов приведены на следующей диаграмме:
Рассмотрим вкладку Report structure редактора отчета.
В верхней части находятся поля ввода общих свойств отчета:
Основным элементом структуры данных отчета является иерархия полос - Report bands.
Полоса отчета характеризуется следующими параметрами:
Каждая полоса включает в себя один или несколько наборов данных - Datasets. Наборы данных при выполнении отчета представлют собой списки строк, а каждая строка - список полей, то есть пар имя-значение. Полоса выводится в отчет столько раз, сколько строк в ее самом длинном наборе данных. Имена полей указываются в шаблоне отчета, и при выводе полосы имена заменяются на соответствующие значения. При формировании наборов данных можно использовать внешние параметры отчета, а также поля других полос - это позволяет делать полосы связанными.
В каждом отчете присутствует корневая полоса Root. В ней можно создавать наборы данных и ссылаться на их поля из других полос, однако использовать полосу Root в шаблоне нельзя.
Имя набора данных в колонке Dataset name не имеет значения и служит только для удобства пользователя.
Рассмотрим возможные типы наборов данных.
SQL - набор данных формируется выполнением SQL-запроса к базе данных. Поля результирующего набора запроса желательно снабдить алиасами с помощью оператора as
. Для исключения возможного преобразования базой данных регистра символов алиасы желательно заключить в двойные кавычки:
select u.name as "userName", u.login as "userLogin" from sec_user u
В запросе можно использовать входные параметры отчета и поля родительских полос. К параметрам нужно обращаться по имени, заключенному в конструкцию ${}
, например ${dateFrom}
. К полям родительской полосы нужно обращаться аналогично, добавляя имя полосы перед именем поля: ${band1.field1}
.
Пример SQL-запроса с параметром groupId
, полученным из родительской полосы group
, и внешним параметром active
:
select u.name as "userName", u.login as "userLogin" from sec_user u where u.group_id = ${group.groupId} and u.active = ${active} and u.delete_ts is null
В запросы на SQL необходимо вручную включать условия фильтрации мягко удаленных записей.
JPQL - набор данных формируется выполнением JPQL-запроса к базе данных. Поля результирующего набора запроса необходимо снабдить алиасами с помощью оператора as
. В JPQL-запросе можно использовать входные параметры отчета и поля родительских полос аналогично описанному для SQL-запроса.
Пример JPQL-запроса с параметром groupId
, полученным из родительской полосы group
, и внешним параметром active
:
select u.name as userName, u.login as userLogin from sec$User u where u.group.id = ${group.groupId} and u.active = ${active}
Запросы на JPQL автоматически поддерживают мягкое удаление и возвращают только неудаленные записи.
Groovy - набор данных формируется выполнением Groovy-скрипта. Скрипт должен возвращать объект типа List<Map<String, Object>>
. Элемент этого списка, то есть объект типа Map<String, Object>
соответствует одной записи набора данных.
В скрипт передаются следующие объекты:
params
- мэп внешних параметров отчета. Пример получения значения параметра:
def active = params['active']
parentBand
- родительская полоса в виде объекта типа com.haulmont.yarg.structure.BandData
. Через этот объект методом getParameterValue()
можно получить значение поля родительской полосы, например:
def groupId = parentBand.getParameterValue('groupId')
persistence
- объект типа com.haulmont.cuba.core.Persistence
, позволяющий управлять транзакциями и получать ссылку на EntityManager
. Например:
def tx = persistence.createTransaction() try { def em = persistence.getEntityManager() def query = em.createQuery('select g from sec$Group g') ... tx.commit() } finally { tx.end() }
metadata
- объект типа com.haulmont.cuba.core.global.Metadata
, позволяющий обращаться к метаданным приложения. Например:
def metaClass = metadata.getClassNN('sec$User')
transactional
- метод, принимающий на вход замыкание, которое нужно выполнить в новой транзакции. Параметром замыкания становится текущий EntityManager
. Пример использования:
transactional { em -> def query = em.createQuery('select g from sec$Group g') ... }
Для обращения к любым бинам Spring среднего слоя можно использовать статические методы класса AppBeans
, например:
def dataWorker = com.haulmont.cuba.core.global.AppBeans.get('cuba_DataWorker')
Пример Groovy-скрипта извлечения пользователей по группе, выводимой в родительской полосе и по внешнему параметру active
:
def result = [] transactional { em -> def query = em.createQuery('select u from sec$User u where u.group.id = ?1 and u.active = ?2') query.setParameter(1, parentBand.getParameterValue('groupId')) query.setParameter(2, params['active']) query.resultList.each { user -> result.add(['userLogin': user.login, 'userName': user.name]) } } return result
Entity - набор данных состоит из одной строки и формируется по атрибутам одного экземпляра сущности и связанных с ним сущностей.
Источником данных является внешний параметр типа Entity, который должен быть описан на вкладке Parameters and Formats. Значение в поле Entity parameter name должно соответствовать алиасу параметра.
Шаблон отчета должен содержать поля с именами атрибутов сущности. Атрибуты, используемые в шаблоне, необходимо указать в специальном окне, вызываемом кнопкой Entity attributes.
List of entities - набор данных формируется по списку экземпляров сущности.
Источником данных является внешний параметр типа List of entities, который должен быть описан на вкладке Parameters and Formats. Значение в поле Entity parameter name должно соответствовать алиасу параметра.
Шаблон отчета должен содержать поля с именами атрибутов сущности. Атрибуты, используемые в шаблоне, необходимо указать в специальном окне, вызываемом кнопкой Entity attributes.
Для одного отчета на вкладке Templates редактора отчета может быть создано несколько шаблонов, и один из них должен быть выбран как шаблон по умолчанию на вкладке Report structure.
Рассмотрим форму добавления шаблона:
Шаблоны XLSX и XLS создаются с помощью Microsoft Office или OpenOffice / LibreOffice.
Для каждой полосы отчета в шаблоне должен быть определен регион с именем полосы. Именованные регионы создаются путем выделения нужного диапазона ячеек и ввода имени в поле в левом верхнем углу приложения. Для редактирования уже созданных именованных регионов в Microsoft Office используется команда меню Formulas -> Name Manager, а в OpenOffice команда Insert -> Names -> Manage.
Полосы выводятся в том порядке, в котором заданы в структуре отчета.
Горизонтальные полосы могут содержать вложенные полосы. Поэтому для вложенных полос необходимо создавать именованные регионы непосредственно под регионами, соответствующими родительским полосам.
Поля наборов данных полосы размечаются в шаблоне с помощью строк вида ${field_name}
, где field_name - имя поля. Например:
Ячейки могут содержать форматирование и сразу несколько полей внутри.Для вывода картинок или формул их нужно целиком поместить в соответствующий именованный регион.
Шаблон ODT создается с помощью OpenOffice / LibreOffice, для создания шаблонов DOC и DOCX можно использовать как OpenOffice, так и Microsoft Office.
Шаблон данного типа включает в себя текст документа и опционально одну или несколько таблиц. В тексте документа выводятся данные из первых строк произвольных полос. В таблицу можно выводить произвольное количество строк некоторой полосы.
Для вывода поля в тексте документа необходимо использовать строку вида ${band_name.field_name}
, где band_name
- имя полосы, field_name
- имя поля.
Для вывода данных в таблицу она должна быть привязана к некоторой полосе. Это делается путем указания в первой ячейке таблицы строки вида ##band=band_name
, где band_name
- имя полосы. Поля в таблице размечаются строками вида ${field_name}
, где field_name
- имя поля связанной с таблицей полосы. Для обращения к полям других полос в таблице можно использовать префикс с именем полосы, как это делается в полях текста документа. В одной ячейке таблицы можно выводить несколько полей.
Таблица должна содержать либо одну, либо две строки. Если строк в таблице две, то поля связанной полосы должны находиться во второй строке. В первую заносится маркер с именем связанной полосы и, при необходимости, статический текст и поля других полос.
Например, для вывода отчета, состоящего из двух полос: Book и Authors, первая из которых выводит название и жанр книги, а вторая список авторов этой книги, шаблон может выглядеть следующим образом:
Шаблон HTML задается в файле c расширением .html в кодировке UTF-8
(без BOM
). Для размещения данных необходимо использовать тэги FreeMarker (документация по FreeMarker находится по адресу freemarker.org/docs).
Модель документа FreeMarker имеет следующую структуру:
Band { bands [ bandName : [ band, .. ], .. ] fields [ fieldName : fieldValue, .. ] }
Например, для доступа к полю name
в полосе band
в нулевой строке выборки нужно использовать следующее выражение:
Root.bands.band[0].fields.name
Для удобства можно использовать переменные:
<#assign headerRow = Root.bands.Header[0]> <p>Date: ${headerRow.fields.reportDate}</p>
Пример шаблона для вывода отчета, состоящего из двух полос: Book и Authors, первая из которых выводит название и жанр книги, а вторая список авторов этой книги:
<!doctype html> <html> <head></head> <body> <#assign book = Root.bands.Book[0] /> <#assign authors = Root.bands.Authors /> <p>Name: ${book.fields.name}</p> <p>Genre: ${book.fields.literatureType.name}</p> <table border="1" cellpadding="5" cellspacing="0" width="200"> <thead> <tr> <td>First name</td> <td>Last name</td> </tr> </thead> <tbody> <#list authors as author> <tr> <td>${author.fields.firstName}</td> <td>${author.fields.lastName}</td> </tr> </#list> </tbody> </table> </body> </html>
Более сложный пример. Имеем структуру полос следующего вида:
Root { HeaderBand { query = return [[ "name" : "Column1" ],[ "name" : "Column2" ]] } Band1 { query = return [ ["field1" : "Value 11", "field2" : "Value 12"], ["field1" : "Value 21" , "field2" : "Value 22"] ] } Band2 { query = return [[ "header" : "Header1" ], [ "header" : "Header2" ]] SubBand1 { query = return [["header" : 'SubHeader1'] , [ "header" : 'SubHeader2' ]] } } }
Обращение к полю:
<!doctype html> <html> <head> <title> Simple template </title> </head> <body> <#assign Tree1 = Root.bands.Band2> <h1> Header </h1> <p> ${Tree1[1].bands.SubBand1[0].fields.header} </p> </body> </html>
Список:
<!doctype html> <html> <head> <title> List </title> </head> <body> <#assign Table1Header = Root.bands.HeaderBand> <#if Table1Header?has_content> <ol> <#list Table1Header as header> <li> ${header.fields.name} </li> </#list> </ol> </#if> </body> </html>
Таблица:
<!doctype html> <html> <head> <title> Table </title> </head> <body> <#assign Table1Header = Root.bands.HeaderBand> <#assign Table1 = Root.bands.Band1> <table border="1" cellpadding="5" cellspacing="0" width="200"> <thead> <tr> <#list Table1Header as header> <td> ${header.fields.name} </td> </#list> </tr> </thead> <tbody> <#list Table1 as row> <tr> <td> ${row.fields.field1} </td> <td> ${row.fields.field2} </td> </tr> </#list> </tbody> </table> </body> </html>
Многоуровневый список:
<!doctype html> <html> <head> <title> Multi-level list </title> </head> <body> <#assign Tree1 = Root.bands.Band2> <ul> <#list Tree1 as item> <li> <h2> ${item.fields.header} </h2> <#if item.bands.SubBand1?has_content> <ul> <#list item.bands.SubBand1 as subitem> <li> <h3> ${subitem.fields.header} </h3> </li> </#list> </ul> </#if> </li> </#list> </ul> </body> </html>
===== Преобразование HTML в PDF
Отчеты, имеющие формат шаблона HTML и формат вывода PDF, не всегда корректно отображают шрифты. Для решения этой проблемы добавьте в конфигурационный каталог блока Middleware (в стандартном варианте развертывания tomcat/conf/app-core) подкаталог cuba/fonts с необходимыми .ttf-шрифтами. Кроме того, можно использовать имеющиеся в операционной системе шрифты путем указания пути к ним в свойстве приложения cuba.reporting.fontsDir.
Для решения проблемы со шрифтами на сервере Ubuntu необходимо выполнить следующее:
Установить пакет ttf-mscorefonts-installer:
$ sudo apt-get install ttf-mscorefonts-installer
Установить свойство приложения cuba.reporting.fontsDir:
cuba.reporting.fontsDir = /usr/share/fonts/truetype/msttcorefonts
В HTML-шаблонах использовать явное указание шрифтов, например так:
<html> <head> <style type="text/css"> * { font-family: Times New Roman; } </style>
==== Шаблон, определяемый классом
Шаблоны, определяемые классом используются в тех случаях, когда выбирать данные с помощью SQL, JPQL или Groovy слишком сложно или невозможно. Например, в случаях, когда отчет представляет собой результат объединения нескольких других отчетов.
Класс, определяющий шаблон должен реализовывать интерфейс com.haulmont.yarg.formatters.CustomReport
. В классе необходимо определить метод createReport()
, возвращающий массив байтов и принимающий на вход параметры:
report
- описатель отчета типа com.haulmont.yarg.structure.Report
.rootBand
- данные корневой полосы типа com.haulmont.yarg.structure.BandData
.params
- мэп внешних параметров отчета.Ниже приведен пример простого шаблона, определяемого классом. Он формирует HTML-документ с названием выбранной в параметре отчета книги:
package com.sample.library.report; import com.haulmont.yarg.formatters.CustomReport; import com.haulmont.yarg.structure.BandData; import com.haulmont.yarg.structure.Report; import com.sample.library.entity.Book; import java.util.Map; public class BookReport implements CustomReport { @Override public byte[] createReport(Report report, BandData rootBand, Map<String, Object> params) { Book book = (Book) params.get("book"); String html = "<html><body>"; html += "<p>Name: " + book.getName() + "</p>"; html += "</body></html>"; return html.getBytes(); } }
Шаблон-диаграмма доступен, если проект приложения включает базовый проект charts. Результирующая диаграмма выводится в экране Reports → Show Charts веб-приложения.
Поддерживаются два типа диаграмм: круговая и серийная. Каждый тип имеет свой набор параметров, настраиваемый в экране редактирования шаблона.
Круговая диаграмма:
Серийная диаграмма:
Для серийной диаграммы необходимо задать описание как минимум одного ряда:
==== Соответствие типа шаблона типу вывода
Шаблон / Вывод |
XLSX |
XLS |
DOCX |
DOC |
ODT |
|
HTML |
Chart |
XLSX |
+ |
+ 1 | ||||||
XLS |
+ |
+ 1 | ||||||
DOCX |
+ |
+ 2 |
+ | |||||
DOC |
+ |
+ 1 | ||||||
ODT |
+ |
+ 1 | ||||||
HTML |
+ |
+ | ||||||
Chart |
+ |
1 - для вывода требуется установка OpenOffice.
2 - в зависимости от значения свойства приложения cuba.reporting.openoffice.docx.useOfficeForPdfConversion вывод может осуществляться либо через OpenOffice, либо без него. В последнем случае необходимо обеспечить наличие нужных шрифтов, как описано в .
Внешние параметры передаются извне при запуске отчета и могут использоваться в наборах данных в качестве условий. Все внешние параметры становятся полями каждой полосы отчета, поэтому их можно непосредственно использовать в шаблоне как поля наборов данных. Если какой-либо набор данных выводит одноименное поле, оно маскирует внешний параметр в данной полосе и в отчете используется значение поля набора данных.
Для описания внешних параметров служит вкладка Parameters and Formats редактора отчета. Рассмотрим форму добавления параметра:
Вкладка Properties:
На вкладке Localization можно определить названия параметра для различных локалей. Для этого в отдельных строках текстового поля следует ввести пары имя_локали = имя_параметра
, например:
ru = Книга
Для любого поля, выводимого отчетом, можно задать форматирование на вкладке Parameters and Formats редактора отчета. Рассмотрим форму добавления формата:
Book.name
.java.text.DecimalFormat
, для дат - java.text.SimpleDateFormat
.Форматы позволяют вставлять в документ изображения и HTML-блоки.
${image:<Width>x<Height>}
, например ${image:200x300}
.${html}
в качестве строки форматирования. В выходном значении тэги верхнего уровня до <body>
включительно могут быть опущены. При необходимости произойдет автоматическое дополнение недостающих тегов верхнего уровня. Кодировка всех блоков UTF-8
. CSS и атрибут style
не поддерживаются.=== Разграничение прав доступа к отчетам
На вкладке Roles and Screens редактора отчетов можно определить права пользователей на доступ к отчету, а также принадлежность отчета экранам системы.
Если в списке ролей для отчета указана хотя бы одна роль, то данный отчет будет доступен только пользователям с этой ролью. Если ни одна роль не указана, отчет доступен всем.
Список экранов позволяет определить, в каких экранах данный отчет доступен при использовании действий RunReportAction, TablePrintFormAction или EditorPrintFormAction. Если ни один экран не указан, отчет доступен из любых экранов.
=== Локализация названия отчета
Название отчета можно локализовать, то есть в списке отчетов для запуска отображать название на языке, с которым пользователь вошел в систему. Для этого в редакторе отчета необходимо перейти на вкладку Localization и в отдельных строках текстового поля ввести пары имя_локали = название_отчета
, например:
en = Books by author ru = Книги по автору
В данном разделе рассматриваются способы запуска созданных отчетов на выполнение.
=== Запуск из общего списка отчетов
Простейший способ запуска отчетов - из общего списка, доступного в экране Reports -> Run Reports. Для этого у пользователя должно быть право на открытие данного экрана. В списке будут присутствовать все отчеты, доступные пользователю в соответствии с его ролью. Если для отчета заданы внешние параметры, они будут запрошены при запуске отчета в специальной форме.
Отчеты можно запускать из произвольных экранов системы, используя специальные действия и связанные с ними кнопки или элементы контекстного меню компонентов. При этом кроме доступности отчета в соответствии с ролью пользователя проверяется также его принадлежность данному экрану.
Рассмотрим типы действий и примеры их использования.
com.haulmont.reports.gui.actions.RunReportAction
- действие, отображающее список всех доступных отчетов. При выборе пользователем отчета из списка отображается форма ввода параметров (если они заданы), и отчет запускается на исполнение.
Пример использования действия совместно с кнопкой, объявленной в XML-дескрипторе экрана:
XML-дескриптор
<layout> <table id="bookTable"> ... <buttonsPanel id="buttonsPanel"> ... <button id="reportButton" icon="icons/reports-print.png"/> </buttonsPanel> </table>
Контроллер
@Inject private Button reportButton; @Override public void init(Map<String, Object> params) { reportButton.setAction(new RunReportAction("report", this)); }
messages.properties
report = Report
com.haulmont.reports.gui.actions.TablePrintFormAction
- действие, связанное с таблицей, отображающей список экземпляров сущности. Действие отбирает только те отчеты, которые имеют внешний параметр типа Entity или List of entities, и тип сущности параметра совпадает с типом сущности, отображаемой таблицей. Если в результате отбора доступен только один отчет, он сразу запускается на выполнение. Если доступно несколько отчетов, их список предлагается пользователю.
В отчет передается значение внешнего параметра по следующим правилам:
Пример использования с кнопкой и контекстным меню таблицы:
XML-дескриптор
<layout> <table id="bookTable"> ... <buttonsPanel id="buttonsPanel"> ... <button id="reportButton" icon="icons/reports-print.png"/> </buttonsPanel> </table>
Контроллер
@Inject private Button reportButton; @Inject private Table bookTable; @Override public void init(Map<String, Object> params) { TablePrintFormAction action = new TablePrintFormAction("report", this, bookTable); bookTable.addAction(action); reportButton.setAction(action); }
messages.properties
report = Report
com.haulmont.reports.gui.actions.EditorPrintFormAction
- действие, связанное с экраном редактирования экземпляра сущности. Действие отбирает только те отчеты, которые имеют внешний параметр типа Entity или List of entities, и тип сущности параметра совпадает с типом редактируемой сущности. Если в результате отбора доступен только один отчет, он сразу запускается на выполнение. Если доступно несколько отчетов, их список предлагается пользователю.
В отчет передается значение внешнего параметра - экземпляр редактируемой сущности. Если тип параметра - List of entities, то передается список из одного элемента.
Пример использования с кнопкой, размещенной рядом со стандартными кнопками OK и Cancel:
<layout expand="windowActionsBox"> ... <hbox id="windowActionsBox" spacing="true"> <iframe id="windowActions" screen="editWindowActions"/> <button id="reportButton"/> </hbox> </layout>
Контроллер
@Inject private Button reportButton; @Override public void init(Map<String, Object> params) { reportButton.setAction(new EditorPrintFormAction("report", this, null)); }
messages.properties
report = Report
Рассмотрим устройство одного отчета в приложении-примере Библиотека, исходные тексты которого доступны по адресу www.cuba-platform.com/download.
Для импорта отчета откройте экран Reports -> Reports и нажмите кнопку Import. Выберите файл Reports.zip в корневом каталоге проекта. В таблице появятся два отчета, один из которых - Books by author. Данный отчет выводит список публикаций книг по автору, группируя их по названию книги и издателю. Формат вывода - XLS.
Структура данных отчета.
Рассмотрим полосы отчета.
Полоса header - заголовок отчета. Содержит набор данных с Groovy-скриптом, выводящим значения внешних параметров отчета:
[['authorName' : (params['author'].firstName + ' ' + params['author'].lastName)]]
Полоса book выводит книги путем выполнения следующего SQL-запроса:
select b.name as book_name, b.id as book_id from library_book b join library_book_author_link ba on ba.book_id = b.id join library_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 library_book_publication bp join library_publisher p on p.id = bp.publisher_id where bp.book_id = ${book.book_id}
В данном запросе в качестве параметра используется поле родительской полосы - book_id
. Таким образом осуществляется связь между родительской и дочерней полосами.
Вложенная в publisher полоса publication выводит издания книги путем выполнения следующего SQL-запроса:
select ld.name as department, count(bi.id) as amount from library_book_instance bi join library_book_publication bp on bp.id = bi.book_publication_id join library_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:
Этот параметр будет запрошен у пользователя при запуске отчета. Выбор автора будет производиться через экран library$Author.lookup
, имеющийся в приложении.
Шаблоны отчета.
На вкладке Templates определен один шаблон формата XLS, загруженный из файла BooksByAuthor.xls:
Локализация названия отчета.
На вкладке Localization задано название отчета для русской локали:
ru = Книги по автору
Вызвать отчет на исполнение можно из общего списка в экране Reports -> Run Reports.
Мастер создания отчетов - это визуальный инструмент, который позволяет быстро создавать структуру данных и шаблон отчета. Для вызова мастера в экране Reports нажмите Create -> Using wizard.
Мастер позволяет создавать отчеты трех типов:
Процесс создания любого отчета состоит из трех этапов:
Созданный отчет можно доработать обычным способом в редакторе, и запустить либо через общий список отчетов, либо с помощью действий TablePrintFormAction
и EditorPrintFormAction
.
Рассмотрим работу мастера на примере тестового приложения Библиотека, доступного для загрузки по нажатию на кнопку Samples в окне выбора проекта CUBA Studio.
=== Отчет по экземпляру сущности
Допустим, что мы хотим получить сведения об отдельно взятом издании книги, то есть экземпляре сущности library$BookPublication
.
Для этого необходимо запустить мастер создания отчетов и на первом этапе указать детали отчета:
library$BookPublication
.Publication details
.Затем нужно выбрать тип построения отчета - Report for single entity. Этот тип построения означает, что отчет будет создаваться по одной сущности.
После этого необходимо нажать на кнопку Next и в отобразившемся окне выбрать атрибуты сущности BookPublication
и связанных с ней сущностей, которые будут включены в отчет (Publication.Book.Name
, Publication.Publisher.Name
, Publication.Year
и Publication.City.Name
). Для этого выбираем их в левой колонке и переносим в правую колонку нажатием на кнопку или двойным кликом.
Атрибуты будут отображаться в отчете в том порядке, в котором они выбраны на этом этапе. Для того чтобы изменить порядок отображения, перемещайте атрибуты при помощи кнопок /.
После нажатия на кнопку ОК произойдет переход ко второму этапу - редактированию регионов отчета.
Отобразишийся экран содержит список именованных регионов - полос шаблона отчета, в которых будут отображаться данные. Мастер позволяет добавить в шаблон несколько регионов, позволяющих отображать разные наборы данных в виде простого текста.
При необходимости набор атрибутов сущности, загружаемых в регион шаблона отчета, можно отредактировать, нажав на ссылку со списком атрибутов в описании региона. Также можно добавить новый регион, нажав на кнопку Add simple region.
Если в сущности есть атрибуты-коллекции, появится также кнопка Add tabulated region, позволяющая добавить регион для отображения данных в виде таблицы.
В обоих случаях отобразится окно выбора атрибутов сущности library$BookPublication
, позволяющее добавить или удалить атрибуты из набора.
На этом этапе можно посмотреть, как отчет будет выглядеть с текущим набором данных, нажав на кнопку Run и выбрав экземпляр сущности library$BookPublication
.
После настройки регионов можно переходить к третьему этапу - сохранению отчета. На этом этапе можно просмотреть готовый шаблон отчета, изменить название и формат файла вывода. Доступны три типа: DOCX, HTML, PDF.
После нажатия на кнопку Save откроется стандартный редактор отчета, в котором при необходимости можно произвести более тонкую настройку шаблона и структуры данных. После завершения редактирования нажмите Save and close в редакторе отчета.
Отчет будет добавлен в группу отчетов General в браузере отчетов, откуда его можно запустить кнопкой Run.
Дополнительно мы можем сделать так, чтобы чтобы отчет о деталях публикации запускался из браузера публикаций. Для этого необходимо добавить в XML-дескрипторе bookpublication-browse.xml
к таблице публикаций кнопку Print details для запуска отчета:
<groupTable id="bookPublicationTable" ... <buttonsPanel> ... <button id="printDetails" caption="msg://printDetails"/>
После чего необходимо добавить к ней в контроллере экрана действие TablePrintFormAction
для запуска отчета:
@Inject private Button printDetails; @Override public void init(Map<String, Object> params) { TablePrintFormAction action = new TablePrintFormAction("report", this, bookPublicationTable); bookPublicationTable.addAction(action); printDetails.setAction(action); }
После этого можно запускать отчет по любой публикации, выбирая ее в таблице и нажимая на кнопку Print details
Готовый отчет выглядит следующим образом:
=== Отчет по списку экземпляров сущности
Мастер отчетов позволяет создавать два вида отчетов по списку экземпляров сущности:
Рассмотрим первый тип отчета. Допустим, что нам необходимо получить список экземпляров книг, находящихся в библиотеке (сущность library$BookInstance
) с их названиями и отделами библиотеки, в которых они находятся.
На первом этапе необходимо указать детали отчета:
library$BookInstance
.Book items location
.Затем нужно выбрать тип построения отчета - Report for list of entities и нажать Next.
В соответствии с условием задачи, в окне выбора атрибутов необходимо выбрать BookItem.Publication.Book.Name
, BookItem.LibraryDepartment.Name
.
Нажмем ОК для перехода ко второму этапу - редактированию регионов отчета.
Шаблон отчета по списку сущностей может содержать только один регион, выводящий данные в виде таблицы. Добавлять новые регионы нельзя, но можно отредактировать набор данных в существующем, нажав на ссылку со списком атрибутов, либо удалить существующий регион и создать его заново, для чего наверху станет активной кнопка Add tabulated region.
В данном случае, менять ничего не нужно. Нажмем Next -> Save для сохранения отчета. В редакторе отчетов отчет будет выглядеть следующим образом:
После сохранения отчет можно запускать из браузера отчетов.
Дополнительно мы можем добавить кнопку запуска отчета в экран просмотра экземпляров книг, открывающийся из браузера публикаций по кнопке Show items. Для этого установим в XML-дескрипторе экрана bookinstance-browse.xml
для таблицы экземпляров книг (bookInstancesTable
) атрибут multiselect=true
и добавим код кнопки:
<table id="bookInstanceTable" multiselect="true"> ... <buttonsPanel> ... <button id="printList" caption="msg://printList"/>
После этого инжектируем в контроллере компонент Button
:
@Inject private Button printList;
После этого внутри переопределенного метода init()
добавим следующий код:
TablePrintFormAction action = new TablePrintFormAction("report", this, bookInstanceTable); bookInstanceTable.addAction(action); printList.setAction(action);
Теперь отчет можно запускать из браузера экземпляров книг, выбирая экземпляры для отчета в таблице и нажимая на кнопку Print list. Опция Print selected экспортирует выбранные экземпляры, опция Print all - все экземпляры, выбранные текущим фильтром.
Готовый отчет будет выглядеть следующим образом:
=== Отчет по экземплярам сущности, отобранным при помощи запроса
Теперь рассмотрим второй тип отчета - отчет по списку сущностей, выбранных с помощью запроса. Для этого усложним задачу: отчет должен содержать в себе список экземпляров книг (с именами и названиями отделов), добавленных после определенной даты.
Как и в предыдущем случае, начнем с того, что зададим детали отчета:
library$BookInstance
.Recently added book items.
Затем нужно выбрать тип построения отчета - Report for list of entities, selected by query.
Выбранный тип отчета позволит нам автоматически отобрать список сущностей, соответствующих определенному запросу. Для того чтобы задать этот запрос, необходимо нажать на ссылку Set query, появившуюся внизу.
Отобразится окно выбора условий запроса, которое во многом аналогично соотвествующему окну универсального фильтра. Оно позволяет добавлять условия, объединять их в группы AND/OR и настраивать их параметры.
Для добавления нового условия запроса нужно нажать на кнопку Add. Отобразится окно выбора атрибутов сущности library$BookInstance
, в котором необходимо выбрать атрибут Created at
. Атрибут будет добавлен в дерево условий запроса и в панели справа отобразятся его свойства. Выберем оператор запроса (>=
).
После сохранения запроса необходимо нажать Next и перейти к выбору атрибутов сущности library$BookInstance
, которые будут включены в отчет. В соответствии с условием задачи, перенесем в правую колонку атрибуты BookItem.Publication.Book.Name
, BookItem.LibraryDepartment.Name
. Нажмем ОК для перехода ко второму этапу.
Нажмем Next -> Save для сохранения отчета. В отобразившемся редакторе готовый отчет будет выглядеть следующим образом:
В редакторе можно усложить структуру отчета, добавив новые полосы и наборы данных, а также настроить дизайн шаблона отчета, сделать локализацию отчета или определить настройки прав доступа.
К примеру, перейдем на вкладку Parameters and Values. В списке Parameters выберем и изменим имя параметра запроса: Date
вместо стандартного CreateTs1
.
Наконец, добавим в экран просмотра списка отделов библиотеки кнопку Report, позволяющую запустить данный отчет.
Для этого внесем в XML-дескриптор экрана librarydepartment-browse.xml
реализацию кнопки:
<table id="libraryDepartmentTable" ... <buttonsPanel id="buttonsPanel"> ... <button id="reportBtn" caption="msg://reportBtn"/> </buttonsPanel> </table>
После чего в контроллере инжектируем компонент Button
:
@Inject private Button reportBtn;
и в переопределенном методе зададим для кнопки действие RunReportAction
:
reportBtn.setAction(new RunReportAction("report", this));
В браузере отделов библиотеки появится кнопка Report, по нажатию на которую открывается список всех доступных в системе отчетов. Для того чтобы запустить наш отчет, необходимо выбрать в списке Recently added book items, указать дату и нажать Run report.
Готовый отчет выглядит следующим образом:
Генератор отчетов использует пакет OpenOffice / LibreOffice для вывода отчетов в форматах PDF и DOC. Ниже рассмотрена установка и настройка данного пакета на компьютере, содержащем сервер приложения.
Установка и настройка OpenOffice для Microsoft Windows
cuba.reporting.openoffice.path = C:/Program Files (x86)/OpenOffice.org 3/program
*Установка и настройка LibreOffice на сервере Ubuntu *
Установить пакет libreoffice, например, командой
$ sudo apt-get install libreoffice
cuba.reporting.openoffice.path = /usr/lib/libreoffice/program
Caused by: java.awt.HeadlessException: No X11 DISPLAY variable was set, but this program performed an operation which requires it
, или же просто завершаться без сообщений об ошибках. Для устранения проблемы установите свойство приложения cuba.reporting.displayDeviceUnavailable:cuba.reporting.displayDeviceUnavailable = true
Для диагностики ошибок при старте LibreOffice можно выполнить следующую команду:
$ strace -e trace=signal /usr/lib/libreoffice/program/soffice.bin --headless --accept="socket,host=localhost,port=8100;urp" --nologo --nolockcheck
В данном разделе в алфавитном порядке описаны свойства приложения, имеющие отношение к генератору отчетов.
Позволяет запускать OpenOffice / LibreOffice в серверной операционной системе без оконного интерфейса.
Значение по умолчанию: false
Используется в блоке Middleware.
Путь к каталогу со шрифтами для конвертации HTML в PDF.
Например: cuba.reporting.fontsDir = C:/Windows/Fonts
Используется в блоке Middleware.
Включает использование OpenOffice для вывода отчета с DOCX шаблоном в PDF, что значительно увеличивает точность конвертации.
Значение по умолчанию: false
Используется в блоке Middleware.