Опенсорс-решение для автоматизации отчетности
Разработчикам сайтов и мобильных приложений часто нужно управлять подготовкой PDF-страниц к выводу на печать или их отправкой клиентам на почту.
У PDF-файлов есть полный контроль над отображением текста и графическими изображениями на странице. К сожалению, библиотеки для генерации динамически заполняющихся PDF-файлов не входят в стандартный инструментарий PHP, JS (Web), Java или Swift (Android и iOS соответственно). В этой статье хочу вам рассказать об опенсорс-решении для генерации PDF-файлов.
JasperReports — это открытая Java-библиотека для генерации динамически заполняющихся файлов. В ней есть много инструментов для создания сложных отчетных форм, в том числе в формате PDF, но также доступны и другие форматы: RTF, DOCX, HTML, XLS, XLS, CSV и XML. Иными словами, достаточно разработать одну форму, сделать одну верстку — и можно будет экспортировать его в любой из вышеперечисленных форматов.
Есть еще хорошие библиотеки, например PDFLib (коммерческая версия) для PHP и ее версия с открытыми исходными кодами PDFLib-Lite. Правда, библиотека довольно дорогая, а облегченная версия распространяется только в исходных кодах, и при ее установке в среде разработки это ограничение может стать проблемой.
PDFbox — еще одна библиотека Java с открытым исходным кодом для работы с документами PDF. Она позволяет создавать новые PDF-документы, управлять существующими документами с возможностью извлекать контент из них. Но у нее нет UI (User Interface), в отличие от JasperReports.
Думаю, JasperReports особо полезен в больших проектах, связанных с отчетностью и не только в PDF-формате. Здесь есть все необходимое, чтобы внедрить ее в ваш проект: простое создание сложных отчетных форм, UI для удобной верстки, серверное приложение и простая интеграция с фронтом.
В статье я раскрою следующие темы:
- Установка среды разработки и серверного приложения.
- Создание PDF-файла автоматически заполняющегося из базы данных.
- Интеграция серверного приложения с фронтендом для получения созданного PDF.
JaspersoftStudio — среда разработки на основе Eclipse со встроенной Java-библиотекой JasperReports, где разрабатываются динамические или статичные PDF-файлы: например, билеты, квитанции, договора, аналитические чарты и другие.
JasperServer — это серверное приложение, куда из JaspersoftStudio деплоятся и хранятся файлы. К ним можно получить доступ из мобильного или веб-приложения. В JasperServer есть UI, с его помощью можно просматривать отчеты, создавать учетные записи для разных пользователей и давать им соответствующие доступы. Также можно настроить рассылку на электронную почту (Scheduler).
Настраиваем рабочую среду и серверное приложение
Скачать и установить приложения можно по ссылкам выше. После сетапа двух приложений необходимо установить соединение из рабочей среды к серверному приложению.
Servers → Create JasperReports Server Connection → Указать предпочитаемое имя сервера, URL, логин и пароль. Нажмите Test Connection, чтобы проверить, что соединение с сервером установлено. Если видите надпись Successful — едем дальше.
Создаем динамически заполняющийся PDF и публикуем его
Мы установили среду разработки, сервер и наладили соединение между ними. Теперь давайте создадим примитивный динамически заполняющийся PDF-файл, который при его запуске (генерации) будет брать данные из PostgreSQL, и задеплоим его на серверное приложение.
В первую очередь следует прикрутить к рабочей среде источник данных (в нашем случае — PostgreSQL), откуда PDF будет брать данные. Затем приступим к разработке нашего первого PDF-файла.
Data Adapters → Create Data Adapter → Database JDBS Connection и указываем данные соединения:
- JDBC Driver — PostgreSQL (org.postgresql.Driver). Если нет драйвера вашего СУБД, можно установить нужный драйвер во вкладке Driver Classpath.
- JDBC URL — он состоит их хоста, порта и названия БД.
- Username и password — логпасс от вашей учетной записи СУБД.
Нажимаем на уже знакомую нам кнопку Test и при успешном соединении (Successful) с БД — Finish.
Из этой БД PDF будет заполняться в рабочей среде. Так как мы планируем задеплоить наш первый PDF-файл еще и на сервер, то давайте прикрутим тот же источник данных к серверному приложению:
Data Sources → Add Resource → Data Source и повторяем все из пункта выше.
Теперь можно приступать к созданию PDF. Исходники в JasperReports хранятся в формате JRXML — это XML с зашитыми тегами и атрибутами, с которыми работает API JasperReports.
Нажимаем File → New → Jasper Report → Blank A4 → Указываем имя JRXML-файла → Finish.
После создания нового проекта вы увидите следующую картину:
Семь разных блоков — для каждого блока прописано свое поведение, отличающееся от других. Более подробно об этом можно почитать в документации. Нажав на Source можно увидеть структуру этих блоков:
Итак, давайте удалим пять лишних блоков и оставим только два: Title и Detail. В этом нам поможет кнопка Delete (Windows) или Backspace (OS X).
Теперь добавим два элемента. Добавить новый элемент можно двумя способами: прописать контейнер в XML-структуре (кнопка Source) либо перетащить нужный элемент из правого верхнего окна Pallette — Static Text, где будут названия полей и Text Field, внутрь которого зашьем переменные поля, вытащенные из БД:
Запрос в БД можно написать в теге queryString либо нажать на кнопку DataSet and Query editor dialog. После этого откроется новое окно, где необходимо выбрать источник данных (1), написать запрос (2) и объявить переменные поля. Кнопка Read Fields (3) прочитает все поля автоматически при валидном запросе. Чтобы просмотреть данные, нужно нажать на Data preview (4).
Отлично! Мы получили четыре поля с типом String, теперь можем совершать с ними практически любые манипуляции. Для примера мы просто выведем их списком и пропишем небольшую логику.
Напечатаем названия нужных полей в Static Text элементах и поместим их в контейнер Title. Переменные поля укажем в Text Field элементах в контейнере Detail, так как они будут множиться. Наш PDF будет выводить имя, город и адрес электронной почты. Чтобы не было совсем скучно, давайте в Text Field элементе пропишем простую логику, используя четвертое поле — пол клиента, Sex.
Сделаем следующее: если клиент — женщина, то перед именем будем добавлять Mrs., если мужчина — Mr. Для этого используем тернарный оператор Java:
.equals( "male" )?"Mr. "+$F:"Mrs. "+$F]]>
Нажав на Preview рядом с кнопкой Source, можно увидеть результат:
Как видно на скриншоте, PDF успешно собрался: забрал все значения и применил логику, правильно проставив Mrs. и Mr.
Еще заведем входной параметр City, чтобы была возможность фильтровать данные по городам. Это можно сделать либо нажав Parameters → Create Parameter в окне Outline, либо добавив новый тег parameter с атрибутами name и class:
Осталось только добавить параметр в SQL-запрос:
SELECT Id, name, sex, city, email FROM users WHERE city = $P
Передадим в параметр City значение San Francisco (о том, как это сделать, расскажу в следующем пункте) и нажмем Data Preview для просмотра результата.
PDF собрался, успешно отфильтровав данные. Едем дальше
Так как у нас уже есть динамически заполняющийся PDF-файл, можем задеплоить его на сервер для дальнейшей интеграции с нашими фронтенд-приложениями. Для этого нажимаем кнопку Publish Report to JasperReports Server → двойным кликом открываем сервер → Выбираем серверную папку, куда нужно загрузить PDF (в нашем случае — reports) → Next → Data Source from Repository → выбираем источник данных, который создали ранее на серверном приложении → Finish.
Интеграция с фронтендом
В JasperReports API входит своя RESTful-реализация для взаимодействия клиента с сервером — REST v2. Если вам она не подходит, можете использовать простой протокол доступа к объектам — SOAP.
Мы рассмотрим REST v2.
Доступны основные четыре метода для действий CRUD (Create-Read-Update-Delete): GET (получить), POST (добавить, изменить, удалить), PUT (добавить, заменить), DELETE (удалить). Вся подробная информация имеется в документации по ссылкам выше.
Мы рассмотрим более распространенный и актуальный для этой статьи метод GET.
http://:/jasperserver[pro]/rest_v2/reports/path/to/report.?
Выше — синхронный запрос, с помощью которого можно получить выходные данные файла (готовый PDF) в одном запросе-ответе (с асинхронным вызовом можно ознакомиться здесь).
Думаю, с хостом и портом все понятно, а /reports/path/to/report — это URI того файла, который вызывается. Так как мы задеплоили исходник PDF-файла (Example.jrxml) в серверную папку reports, заполненный вариант URI будет таким: /reports/reports/Example.
format — это формат (в нашем случае PDF).
arguments — параметры.
Выше мы добавили параметр City, его и передадим в запросе со значением San Francisco для фильтрации данных по этому городу.
Если вызов делается не с авторизованной зоны, нужно добавить еще два параметра/атрибута: j_username и j_password (логпасс для авторизации). По умолчанию логин и пароль на сервере — jasperadmin.
Таким образом, получаем следующий URL:
http://localhost:8080/jasperserver/rest_v2/reports/reports/Example.PDF?city=San Francisco&j_username=jasperadmin&j_password=jasperadmin
Так мы получим уже сформированный PDF. Например, при вызове этого URL через адресную строку браузера файл должен скачаться автоматически.
Может возникнуть необходимость отобразить PDF картинкой. Например, если клиент хочет просто просмотреть файл, можно показать документ в PNG-формате, если же хочет скачать его, то в PDF.
На примере Java с использованием библиотеки PDFbox рассмотрим, как можно из внешнего приложения сгенерировать и забрать PDF-файл, а затем сконвертировать его в PNG.
Ниже — класс PullPDF с одним методом, принимающим в качестве аргумента URL-адрес.
import java.awt.image.BufferedImage; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.URL; import java.util.Base64; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.rendering.ImageType; import org.apache.pdfbox.rendering.PDFRenderer; import org.apache.pdfbox.tools.imageio.ImageIOUtil; public class PullPDF < public String convertPDF2PNG(String valuefromParam) throws IOException < BufferedInputStream input_file = new BufferedInputStream(new URL(valuefromParam).openStream()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); try < PDDocument document = PDDocument.load(input_file); PDFRenderer pdfRenderer = new PDFRenderer(document); for (int page = 0; page < document.getNumberOfPages(); ++page) < BufferedImage bim = pdfRenderer.renderImageWithDPI(page, 300, ImageType.RGB); ImageIOUtil.writeImage(bim, "png", baos); baos.flush(); byte[] encodedBytes = Base64.getEncoder().encode(baos.toByteArray()); valuefromParam = new String(encodedBytes); >> catch (Exception e) < >return valuefromParam; > >
Можно получить тот же результат, используя, например, Spring Framework. Но я постарался показать универсальный способ, который можно применить и в Android, и в вебе при работе с Java.
Заключение
Если вы хотите автоматизировать генерацию простого чека для интернет-магазина и у вас ограничено время на его создание, то я рекомендую использовать нативный инструментарий вашего проекта или знакомый вам фреймворк. Поскольку затраты времени на установку JasperReports, ознакомление с документацией для разработки более комплексных отчетных форм, могут не оправдать себя. В остальных случаях JasperReports — хорошее опенсорс-решение для автоматизации отчетности.
- Блог компании TINKOFF
- Open source
- Java
- Разработка под e-commerce
- Статистика в IT
Вопросы с меткой [jasperreports]
Руководство по использованию метки jasperreports отсутствует.
44 вопроса
Новые Текущие Конкурсные Неотвеченные Ещё
- Конкурсные 0
- Неотвеченные
- Цитируемые
- Рейтинг
- Неотвеченные (мои метки)
230 показов
Непонятная ошибка при печати из JasperReport
Печатаю в консольном приложении через JasperReport-6 несколько тысяч заданий в день на разные сетевые принтеры. Периодически вылетает ошибка: Ошибка:No suitable print service found. net.sf.
задан 18 фев 2016 в 7:04
100 показов
Как получить доступ к корневому элементу из листа в листе JSON
Есть JSON файл такой структуры: < "person" < "someElement" : "test", "operationsList": [ < "date": 1505980686916, "sendersLastName": "last", ".
задан 12 ноя 2017 в 19:43
Некорректная форма отчета при выгрузке с JasperServer
Для генерации отчета использую CROSSTAB. Отчет выгружается в xlsx. Как видно на изображении, заголовок отчета состоит из нескольких столбцов, причем последний столбец разбит на 3 строки. При выгрузке .
задан 21 авг 2020 в 7:55
JasperReport перевод на docx
В проекте пытаюсь Hello World на docx перевести с помощью jasperReport
задан 15 авг 2018 в 3:41
jasperreports и термопринтер
За основу взял этот пример и решил шаблон сделать с помощью jasperreports и отдельно создал класс который работает уже с шаблоном. List
задан 24 июл 2018 в 17:42
614 показов
Создание отчётов в JasperReports Server
Сейчас я строю отчёты с помощью JasperReports Server следующим образом: в Jaspersoft Studio создаю шаблон отчёта (.jrxml файл) создаю отчёт в JasperReports Server, указываю в качестве источника этот, .
задан 13 дек 2017 в 9:32
759 показов
Скрипт для просчета формулы jasper report
Как преобразовать данную переменную из string’a в double, для последующего ее умножения и деления. net.homecredit.tools.Ft.formatCurrency( new Double( ($F
задан 21 мая 2013 в 13:42
2k показов
Ошибка «Cannot find java.exe» при установке iReport
В задании нужно сначала при помощи iReport сделать макет отчёта для запроса к базе данных, затем сделать аналогичный макет для запроса через jdbc, с которым я тоже ещё только собираюсь начать .
задан 18 авг 2014 в 19:42
382 показа
JasperReports вывести в Excel числа как числа
Привет! Есть SpringMVC проект, есть данные, которые по клику на кнопку выкачиваются в Excel файл. Данные могут быть как число, так и текст, поэтому предыдущий программист сохранял все данные как .
задан 4 янв 2017 в 14:25
6k показов
Экспорт из Java в doc/docx
Нужно создать из java приложения несколько страничек в ворде. Страницы будут содержать картинки и текст. Без графиков и т.п. Идеалом было бы в красивом и оформленном шаблоне менять текст и картинки. .
задан 17 дек 2011 в 13:39
252 показа
Динамическая подстановка запроса в JasperReports
Новичок в JR, пытаюсь разобраться. Есть приложение, которое выводит данные из БД в зависимости от выбранных условий (отмеченных флагов), причем комбинаций этих условий очень много. В JR Studio .
задан 31 окт 2017 в 12:54
467 показов
Как связать файл отчета с Jasper под Spring MVC?
Пишу на Java с использованием Spring MVC. Хочу создать файл отчета в формате PDF(именно файл, а не форму). В WEB-INF у меня лежит папка jrxml c report.jrxml. Использую Jasper, но не могу связать .
задан 11 ноя 2014 в 8:38
49 показов
Система для печати чеков на складе по печатным формам из 1С
Не хватает опыта решить задачу: Есть БД 1С стоит в ЦОД. К ней доступ закрыт извне, можно к ней подключиться только на месте каким-то сервером, или еще чем. Есть удаленный склад. На нем работники у .
задан 22 мар в 22:29
Ошибка при построении отчета Jasper: Property ‘idrkk’ has no getter method
Возникает ошибка Property ‘idrkk’ has no getter method in class ‘class DataSetApprovalOfBankDocMPNew$ReportRow’ хотя gettеr объявлен для idrkk. В чем может быть проблема? idrkk получаю в методе .
задан 25 фев в 10:07
455 показов
Как убрать лишнее пустое пространство между band в JasperReports?
Разрабатываю отчёт в Jasper для заполнения его в Java. Поместил шапку таблицы в title band, контент в details band и итоговую часть в summary band (это всё разные таблицы). Во всех трёх используется .
# Установка Jaspersoft Studio
Загрузите программное обеспечение Jaspersoft Studio (! версия 6.4.0). Для этого перейдите по ссылке и выберите инсталлятор соответствующий вашей операционной системе https://sourceforge.net/projects/jasperstudio/files/JaspersoftStudio-6.4.0/
# Шаблон отчета. Описание секций
Создадим отчет, соответствующий странице свойств запущенного экземпляра процесса
Отчет будет содержать общую информацию о процессе (имя определения, номер экземпляра, версия, когда запущен, статус), раздел активных заданий, ролей и переменных.
Откройте установленный Jaspersoft Studio и создайте новый отчет
Выберите шаблон “Blank A4” и нажмите Далее
Введите название отчета, например “processDetails” и нажмите Finish
Откроется рабочая область Jaspersoft Studio
Выбранный ранее шаблон “Blank A4” содержит следующие секции
- “Title” – заголовок отчета, отображается только на первой странице
- “Page Header” – секция, которая отображается на каждой странице
- “Column Header” – отображение в начале столбца отчета. Не будем использовать данную секцию, кликните по ней левой клавишей мыши и нажмите клавишу Delete.
- “Detail” – отображается для каждой записи в источнике данных.
- “Column Footer” – секция для отображения данных в конце столбца отчета. Не будет использоваться, удалите ее.
- “Page Footer” – секция для отображения данных внизу каждой страницы.
Добавьте в отчет еще две секции Detail. Для этого кликните правой клавишей мыши по разделу Detail и выберите пункт “Add detail band”
Сохраните отчет (используйте комбинацию клавиш Ctrl+S или соответствующую иконку панели инструментов)
# Работа над заголовком отчета
В качестве входного параметра для формирования отчета будет использоваться Id экземпляра БП.
Перейдите в раздел “Parameters” и создайте новый параметр
В “Properties” введите название параметра – “ProcessId”
Id экземпляра БП это целочисленное значение, поэтому в качестве типа задайте “java.lang.Long”
Перейдите в палитру элементов и перетащите “Text field” в секцию заголовка (Title)
“Text field” – элемент для отображения строки формирующейся динамически
# Источник данных
Отобразим в заголовке: ID экземпляра процесса и имя его определения.
Для получения этой информации необходимо настроить источник данных.
Кликните по корневому элементу “processDetails” в панели “Outline”, справа отобразится панель с настройками.
Нажмите кнопку “Edit query, filter and sort”
SQL запрос для получения имени определения процесса по id экземпляра БП выглядит следующим образом:
SELECT BPM_PROCESS.ID, BPM_PROCESS_DEFINITION_PACK.NAME FROM BPM_PROCESS INNER JOIN BPM_PROCESS_DEFINITION ON BPM_PROCESS.DEFINITION_ID = BPM_PROCESS_DEFINITION.ID INNER JOIN BPM_PROCESS_DEFINITION_PACK ON BPM_PROCESS_DEFINITION.PACK_ID = BPM_PROCESS_DEFINITION_PACK.ID WHERE BPM_PROCESS.ID= $P
Добавьте этот запрос в окно “Texts”
Запрос возвращает название определения БП. Нажмите “Add” и добавьте новое поле. Введите имя – NAME, тип “java.lang.String”
Перейдите на вкладку Parameters и определите входной параметр ProcessId типа java.lang.Long
# Выражение для заголовка
Теперь можно использовать полученное в результате запроса поле Name в ранее добавленном элементе “Text Field” секции Title
Дважды кликните по нему мышью, откроется окно редактора выражений.
В Fields и Parameters должны присутствовать добавленные ранее поле Name и параметр ProcessId, которые можно использовать в выражении.
"Report on the process '"+ $F + "' (id=" + $P.toString() + ")"
Для добавления в выражение поля или параметра, выделите его в соответствующем списке и дважды кликните по нему мышью.
Для преобразования параметра ProcessId (типа Long) в его строковое представление, используйте метод toString()
Таким образом в заголовке отчета будет отображаться динамически сформированная строка, содержащая id процесса и имя его определения.
# Настройка стиля отображения заголовка
Выделите “Text field” заголовка и перейдите в панель Properties. Здесь можно настроить внешний вид элемента или применить стиль.
В разделе Color задайте цвет текста (Forecolor) и цвет фона (Backcolor)
Используйте шрифт “DejaVu Sans”. Это даст возможность корректно отображать кириллицу в отчетах формата pdf.
Задайте выравнивание текста и его размер.
# Секция детальной информации по экземпляру процесса
В секции Detail1 отобразим id, имя, дату запуска, дату завершения, версию и статус процесса.
# Источник данных
Для получения этих значений необходимо создать новый источник данных.
Перейдите в окно “Outline”, вызовите контекстное меню на корневом элементе и выберите “Create DataSet”
Дайте имя источнику – “processInfo”, создаем пустой источник (опция empty dataset)
Перейдите в настройки processInfo и нажмите “Edit query, filter and sort options”.
В секцию “Texts” добавьте следующий sql запрос на получение информации о процессе по его id
SELECT
BPM_PROCESS.ID, BPM_PROCESS_DEFINITION_PACK.NAME, BPM_PROCESS.START_DATE, BPM_PROCESS.END_DATE, BPM_PROCESS_DEFINITION.VERSION, BPM_PROCESS.EXECUTION_STATUS
FROM
INNER JOIN BPM_PROCESS_DEFINITION ON BPM_PROCESS.DEFINITION_ID = BPM_PROCESS_DEFINITION.ID INNER JOIN BPM_PROCESS_DEFINITION_PACK ON BPM_PROCESS_DEFINITION.PACK_ID = BPM_PROCESS_DEFINITION_PACK.ID WHERE
Добавьте возвращаемые поля, установите их тип как показано на рисунке ниже.
# Элемент List
Отобразим информацию о процессе с помощью элемента List.
Для этого перейдите в палитру графических элементов, выделите List и перетащите его в секцию Detail1.
Будет предложено выбрать источник данных.
Выберите ранее созданный processInfo
Дважды кликните по добавленному List, будет открыта форма для редактирования.
Расположите на форме уже известные элементы “Static text” и “Text Field” как показано на рисунке ниже.
Дважды кликните по каждому добавленному “Static Text” и введите названия параметров процесса,
В элементы “Text Field” добавьте поля, соответствующие возвращаемым полям запроса “processInfo”
Обратите внимание на конструкции вида
$F == null ? «» :$F
В приведенном выше примере, выполняется проверка статуса (EXECUTION_STATUS), если значение не задано (равно NULL) то будет отображаться пустая строка “”, иначе значение статуса.
Используйте такие конструкции в полях, которые могут быть не заполнены. В данном случае это “Статус” и “Дата завершения процесса’.
В запросе processInfo присутствует входной параметр processId, его требуется передать в элемент List
Выделите List, перейдите в его параметры на вкладку DataSet и нажмите кнопку Parameters
В появившемся окне нажмите Add и выберите из списка параметр processId.
Задайте для него выражение вида
# Настройка стиля отображения
Кликните на элементе Styles, окна “Outline”, и выберите “Create Style”
Создайте два стиля:
1). PropertyName – для элементов с названиями параметров
2). PropertyValue – для элементов, отображающих значения параметров
Выделите созданный стиль и перейдите в настройки (Окно Properties).
Задайте цвет фона, выберите шрифт (используйте Deja Vu Sans) и его размер
Также можно задать отступы, выравнивание текста, границы элементов и т.д.
Далее необходимо применить созданный стиль к элементам отвечающим за вывод названия параметра и его значения в List.
Выделите элемент, перейдите в его свойства, и на вкладке “Appearance” в выпадающем списке Style выберите соответствующий стиль
Элемент List примет вид:
# Активные задачи
Выведем информацию по активным задачам процесса в виде таблицы с колонками:
- Состояние
- Роль
- Исполнитель
- Время создания
- Срок окончания
- Фактическая длительность
- Осталось до окончания
# Источник данных
Создайте новый источник данных “processTasks”
Используйте следующий sql запрос для получения данных об активных задачах:
SELECT
BPM_TASK.NAME as TASK_NAME, BPM_TASK.CREATE_DATE, BPM_TASK.DEADLINE_DATE, EXECUTOR.NAME as EXECUTOR_NAME, BPM_SWIMLANE.NAME as SWIMLANE_NAME
FROM
INNER JOIN EXECUTOR ON BPM_TASK.EXECUTOR_ID = EXECUTOR.ID INNER JOIN BPM_SWIMLANE ON BPM_TASK.SWIMLANE_ID = BPM_SWIMLANE.ID WHERE
Добавьте возвращаемые поля TASK_NAME , CREATE_DATE, DEADLINE_DATE, EXECUTOR_NAME, SWIMLANE_NAME, а также параметр ProcessId
Как видно из запроса и состава возвращаемых полей, здесь отсутствуют такие данные как фактическая длительность задачи и оставшееся время до ее окончания. Эти данные являются вычисляемые исходя из текущего времени и значений полей “Дата создания задачи” (CREATE_DATE), “Срок окончания” (DEADLINE_DATE).
“Фактическая длительность” = CREATE_DATE – “Текущее время”
“Осталось до окончания” = “Текущее время” – DEADLINE_DATE
Создайте новый параметр — DTNow, который будет содержать текущее время
Используйте тип “java.util.Date”
Кликните на иконке напротив строки “Default Value Expression”
new Date()
Опция “Is For Prompting” не должна быть установлена, т.к. данный параметр не используется в качестве входного параметра запроса
Кроме того, для вычисления интервалов между датами, а также приведения дат к единому (с отображением в RunaWFE) формату, потребуется использование еще одного параметра DataFormatter класса ru.runa.wfe.report.ReportFormatter
Для использования класса ReportFormatter, в проект необходимо добавить библиотеку Файл:Wfe-core-4.3.0-SNAPSHOT.jar
Откройте настройки проекта
Выделите “Java Build Path” и перейдите на вкладку “Libraries”
Нажмите “Add External JARs” и выберите jar файл
Теперь создайте новый параметр с именем DataFormatter, класса ru.runa.wfe.report.ReportFormatter
Значение по умолчанию задайте в виде строки
new ru.runa.wfe.report.ReportFormatterImpl()
Вернитесь к источнику processTasks, откройте вкладку параметров, добавьте DTNow и DataFormatter
# Таблица «Активные задачи»
Добавьте из палитры графических элементов таблицу (элемент Table)
Используйте ранее созданный источник “processTasks”
Дважды кликните по таблице для переход в режим редактирования.
Поочередно выделите и удалите“Column Footer” и “Table Footer”
Создайте 8 колонок
Сгруппируйте колонки в заголовке и растяните полученную таблицу на всю область
Расположите элементы “Static text” и введите названия колонок
В колонках для значений расположите элементы “Text Field”
Используйте следующие выражения для полей:
- Исполнитель
- Время создания
$P.timeMultilineFormat().dateTime($F)
- Срок окончания
$P.timeMultilineFormat().dateTime($F)
- Фактическая длительность
$P.timeMultilineFormat().interval($F,$P)
- Осталось до окончания
$P.timeMultilineFormat().interval($P,$F)
Для полей формата Timestamp используется DataFormatter, позволяющий преобразовать значение в единый с RunaWFE формат отображения. С помощью метода interval(StartDate, EndDate) рассчитывается интервал между двумя заданными датами.
Параметры DTNow, DataFormatter и ProcessId должны быть переданы в DataSet таблицы активных заданий.
# Стили таблицы
Вместе с таблицей автоматически создаются стили:
Отредактируйте их и примените к заголовку, ячейкам с названиями параметров, ячейкам значений:
# Секция информации о ролях
Создайте новый источник данных processExecutors
Для получения ролей экземпляра БП используйте следующий sql запрос\
SELECT BPM_SWIMLANE.NAME as SWIMLANE_NAME, EXECUTOR.NAME as EXECUTOR_NAME FROM BPM_SWIMLANE INNER JOIN EXECUTOR ON BPM_SWIMLANE.EXECUTOR_ID = EXECUTOR.ID WHERE BPM_SWIMLANE.PROCESS_ID= $P
Расположите в секции Detail2 таблицу для отображения ролей экземпляра БП, в качестве источника данных используйте processExecutors
Добавьте следующие выражения для полей Роль и Исполнитель:
$F == null ? «» : $F
Примените для таблицы стили
# Таблица переменных процесса
Создайте новый источник данных для получения значений переменных экземпляра БП
SELECT BPM_VARIABLE.NAME, BPM_VARIABLE.STRINGVALUE FROM BPM_VARIABLE WHERE PROCESS_ID= $P
Создайте таблицу для отображения значений переменных экземпляра БП, аналогично таблицы ролей и расположите ее в секции Detail3
Используйте выражения для полей “Variable Name” и “Value”
$F == null ? «» : $F
# Область Page Footer
Расположите в “подвале” отчета два элемента “Text Field” с выражениями вида:
«Page » + $V
» of » + $V
- PAGE_NUMBER – номер текущей страницы
- PAGE_COUNT – количество страниц в отчете
# Компиляция отчета
Выделите файл отчета (расширение jrxml), вызовите контекстное меню и выберите пункт “Compile Report”
Если отчет не содержит ошибок, то будет сгенерирован файл с расширением jasper, который можно загрузить на сервер RunaWFE.
# Загрузка и выполнение отчета
Откройте “Отчеты”, нажмите Загрузить.
Выберите файл отчета (расширение .jasper) и заполните обязательные поля.
Введите название выводимое пользователю для параметра ProcessId
Выберите тип Integer, установите опцию обязательности параметра.
Нажмите “Загрузить”, отчет появится в списке
Введите id экземпляра БП, данные которого хотим получить в отчете и выберите Тип отчета
Ниже приведены примеры сформированных отчетов:
# Файлы отчета по данным экземпляра БП
Пример разработанного по данному руководству отчета доступен по следующим ссылкам
Актуальные версии демо отчёта для Релиза 4.5.0
Работа с отчетностью в системе управления данными
Всем привет! В этой статье мы хотим рассказать о том, каким образом мы в платформе «Юнидата» формируем отчетность. Любая работа с данными неизбежно ведет к построению специализированных отчетов, в которых пользователи могут эффективно эти данные обрабатывать и принимать на их основе бизнес-решения.
Как выбирали систему построения отчетности
Создавать модуль построения отчетов в платформе – задача нетривиальная и дорогостоящая, поэтому возникла необходимость поиска подходящего инструментария для построения отчетов. Главными нашими критериями были:
- Бесплатное использование ПО в коммерческих проектах с открытым исходным кодом
- Инструмент для построения данных должен работать с основными форматами источников данных, а так же напрямую БД.
- Использование языка Java для построения отчетов
- ПО должно быть поддерживаемым и обновляемым c поддержкой обратной совместимости
- Редактор построения отчетов должен быть удобным и понятным
- Инструмент должен позволять создавать шаблоны отчетов всех основных форматов: excel, csv, pdf, html, и т.д
- Богатые возможности визуализации и построения дашбордов.
Мы провели исследование части наиболее известных open-source систем построения отчетов, и результаты нашего исследование мы собрали в таблицу, которой хотим поделиться.
Наименование
Производитель
Лицензия
Возможности и достоинства
Недостатки
The Business Intelligence and Reporting Tools (BIRT)
Eclipse Public License
Последняя версия 4.5.0 (Июнь 24, 2015) т.е. проект живой;
Есть визуальный редактор отчетов в среде разработки Eclipse IDE;
Сконструированные отчеты BIRT сохраняются в XML и имеют доступ к целому ряду различных источников данных, включая хранилище данных JDO, JFire, Plain Old Java Object, SQL, database, Web Service и XML;
Содержит технологию построения графиков, которая полностью интегрирована в дизайнер отчетов и может использоваться автономно для интеграции графиков в приложение;
Сырой и неудобный редактор;
Ставится отдельным web-приложением;
Для использования необходим Eclipse;
Отчеты, созданные в разных версиях несовместимы;
GNU Lesser General Public License
Последняя версия 6.2.2 (6 мая 2016 года)отчёты могут выводиться на экран, принтер, либо в форматы PDF, RTF,HTML, XLS, CSV и XML;
Использование динамических языков JavaScript и Groovy при реализации логики отчета;
Реализация диаграмм (charts) на основе библиотеки JFreeChart;
Реализация подотчётов (subreports) с неограниченной глубиной вложенности;
Реализация кросстаблиц (crosstabs);
Pentaho Reporting JFreeReport
Pentaho Community Edition (CE): Apache version 2.x; Pentaho Enterprise Edition (EE): Commercial License
Гибкое позиционирование элементов дашборда на макете;
Развитые инструменты визуализации отчетов;
Возможность вывода отчетов в форматах HTML, Excel, csv, xml, PDF, текстовых форматах;
Мало информации о применении;
Все основные фичи реализованы в коммерческой версии от Hitachi Group Company;
Apache 2.0 License
Генерировать отчет в формате шаблона или конвертировать результат в PDF;
Создавать шаблоны отчетов в привычных и распространенных форматах: DOC, ODT, XLS, DOCX,XLSX, HTML;
Создавать сложные XLS и XLSX шаблоны: с вложенными областями данных, графиками, формулами и т.д.;
Использовать в отчетах изображения и HTML-разметку;
Хранить структуру отчетов в формате XML;
Запускать standalone приложение для генерации отчетов, что делает возможным использование библиотеки вне Java-экосистемы (например для генерации отчетов в PHP);
Интегрироваться с IoC-фреймворками (Spring, Guice).
Нет внятного редактора;
Есть UI, который предоставляет платформа CUBA;
Как видно из нашего небольшого исследования, наиболее подходящим инструментом для нас стал JasperReports. В пользу этого open-source инструмента говорит наличие весьма удобного визуального редактора проектирования отчетов, богатого набора визуализаций, включая кросстаблицы, а самое главное — наличие REST API. Проектирование макетов отчетов в JasperReports не требует особых глубоких знаний, а результаты проекта сохраняются в xml-формат. Так же мы ориентируемся на опыт коллег, например, наши партнеры КРОК в своей статье https://habr.com/ru/company/croc/blog/244085/ рекомендуют использовать Jasper. «JasperSoft наибольшим образом подходит для построения фиксированной отчетности. Интересны любой компании, которой необходимы инструменты анализа данных». Конечно, у jasper есть определенные проблемы, когда требуется сделать гибкий шаблон, например, когда необходимо сделать гибкий вывод полей в таблице, но в нашей практике мы сталкиваемся как правило с фиксированными отчетами, которые обозначает заказчик.
Взаимодействие клиент-сервер с Jasper reports
Мы полагаем, что может быть интересным то, как именно мы встраиваем jasper отчеты непосредственно в платформу без лишних запросов к Jasper Server. JasperReports Server – это основной компонент системы. Его задача — хранить отчеты, которые будут встраиваться в платформу, а так же предоставлять возможность просмотра отчетов напрямую через специальный интерфейс. Вот пример как это выглядит в платформе
При построении отчетов наша задача состоит в том, чтобы получить от пользователя параметры отчета, собрать на основе переданных параметров данные из источников, построить визуализацию данных, и готовую визуализацию данных интегрировать в виде iframe на интерфейс или выгрузить в файл. Описание данного механизма представлена ниже на схеме.
Для того, чтобы получить отчет необходима авторизация в Jasper Server. Авторизация происходит путем передачи пары логин/пароль, а в ответ Jasper создает сессию и сохраняет session_id в куках. В обычном случае для того, чтобы напрямую взаимодействовать с JasperServer из JavaScript, нам необходимо авторизоваться, получить session_id из куки и запросить сам отчет. Однако на практике мы столкнулись с проблемой, что в случае использования кластера серверов с дублированием Jasper на всех инстансах, jasper отчеты то доступны, то недоступны для пользователя. Проблема заключается в том, что балансировщик, получив запрос от клиента, запрашивает ответ с разных JasperServer, но использует session_id только одного инстанса . То есть мы авторизовались в JasperServer на первом инстансе, получили от него session_id, затем c этим же session_id мы идем на другой инстанс и получаем ошибку доступа «с сообщением «Авторизуйтесь на JasperServer». Для решения этой задачи мы используем специальный проксировщик, который по сути является расширением бэкэнда платформы и устанавливается на все ноды кластера. Так как проксировщик установлен на том же сервере, что и Jasper server, ему нет необходимости обращаться по IP к ноде, а достаточно обратиться по localhost. Таким образом, балансировщик, передавая запрос от клиента на ту или иную ноду, запрашивает у проксировщика авторизацию уже на месте и гарантировано Jasper Server вернет ответ. Ниже представлен код проксировщика.
public Response getJasperReport(@QueryParam("url") String url) throws UnsupportedEncodingException < url = url.replaceAll(";;", "&").replaceAll(" ","%20").replaceAll("\"","%22"); Client client = ClientBuilder.newClient(); Response authResponse = client .target(jasperUrlLogin) .queryParam("j_username", jasperLogin) .queryParam("j_password", jasperPassword) .request() .header("Content-Type", "application/x-www-form-urlencoded") .header("charset", "utf-8") .post(Entity.json("")); NewCookie sessionIdCookie = null; if (authResponse.getStatus() == 200) < Mapcookies = authResponse.getCookies(); sessionIdCookie = cookies.get("JSESSIONID"); > else < LOGGER.warn("Cant auth JasperServer"); return null; >String requestUrl = jasperReportUrl + url; Response response = client .target(requestUrl) .request() .cookie(sessionIdCookie) .header("Content-Type", "text/html") .get(); return response; >
Проксировщик получает на вход некий URL отчета, который собирается из параметров на клиенте. По этому URL происходит авторизация в jasperServer, далее проксировщик достает из куки session_id и уже по нему запрашивает ответ непосредственно самого отчета. Ответ от jasper приходит виде html-страницы. Именно эту html-страницу мы передаем в iframe для отрисовки на клиенте, а не url, как это обычно бывает. Таким образом мы один раз запрашиваем отчет, далее вся работа с ним идет уже непосредственно на клиенте платформы.
< xtype: 'component', margin: '20 0 0 0', reference: 'report', maxWidth: 1200, height:485, autoEl: < tag: 'iframe', src: '', frameBorder: 0, marginWidth: 0, >, listeners: < load: < element: 'el', fn: function () < var panel = this.getParent().component; panel.setLoading(false, panel.body); >> > >
Подкладываем html страницу от Jasper Server
generateReport: function () < var report_url = this.generateReportUrl('html'); if (report_url) < var panel = this.view; panel.setLoading(true, panel.body); this.getHtmlAndUpdateReport(report_url); >>
generateReportUrl — метод, который генерирует URL с нужными параметрами для отчета и session_id.
Cоздание отчета в JasperReports
Далее поговорим про непосредственно создание отчетов и дашбордов в Jasper. Создание jasper отчета состоит из набора визуализаций, скомпонованных на едином макете: Для создания макета отчета мы используем визуальный редактор JasperSoft Studio, который может быть отдельным приложением или плагином для eclipse. Подробнее об этом инструменте можно легко найти информацию в документации и открытых источниках, Нам же важно выделить то, что в данном редакторе достаточно легко можно построить дашборд, а сам редактор достаточно удобен и понятен. Достаточно выбрать нужные визуализации, перетащить их на макет, заполнить параметры и функциональные элементы. Построение дашбордов не требует навыков программирования и каждый может разобраться с ними в достаточно короткое время. Ниже пример простого отчета в JasperStudio.
После того, как создали макет отчета, переходим к построению логики самого отчета. Jasper отчет представляет xml-файл в специальном формате jrxml. Структура jrxml файла условно можно поделить на три части: в первой части определяются параметры отчета, во второй части пишется запрос к данным, в третьей части описываются функциональные блоки макета, в которых происходит обработка результатов запроса и отображение данных в макете.
Начало структуры файла: пример параметров отчета
Далее предположим, что источником данных является во второй части после параметров пишем SQL-запрос
, 'DD_MM_YYYY') - to_date($P, 'DD_MM_YYYY') + 1)) as avg_count_status FROM (SELECT T1.id,T2.status FROM public.history AS T1 LEFT JOIN (SELECT DISTINCT ON (history_id) history_id, status FROM public.track WHERE createdate >= to_date($P, 'DD_MM_YYYY') AND DATE(createdate) , 'DD_MM_YYYY') ORDER BY history_id, createdate DESC NULLS LAST ) AS T2 ON T1.id = T2.history_id WHERE T2.status IS NOT NULL AND $X AND $X AND T1.createdate >= to_date($P, 'DD_MM_YYYY') AND DATE(T1.createdate) , 'DD_MM_YYYY') AND $X ) AS T3 GROUP BY T3.status) SELECT main_table.*, round((count_status * 100) / (SELECT SUM(count_status) FROM main_table), 2) AS percent_status FROM main_table ) AS t_result order by status]]>
Стоит обратить внимание, что в запросе мы используем параметры $P, которые динамически приходят от клиента, что так же является фишкой Jasper.
Далее описывается тело всего отчета по функциональным разделам. Подробнее о описании всех разделов можно найти в документации. Ниже пример как это может выглядеть
Отдельно стоит отметить еще одну полезную функцию Jasper отчетов — это наличие подотчетов. В случае, когда мы хотим переиспользовать какой-либо отчет в другом отчете с тем же параметрами, нам не нужно писать с нуля, а достаточно обраться к готовому отчету по его идентификатору, передав новые значения параметров
Ключевым вопросом в построении отчета является передача параметров (фильтров) отчета от клиента на сервер. Для того, чтобы не отправлять пользователя на JasperServer и все параметры отчета заполнять в платформе удобным способом, Jasper предлагает использовать собственный REST API. Наличие такого мощного API было решающим аргументом в сторону выбора JasperSoft для автоматизации отчетности. Вместо того, чтобы создавать ресурсы и заполнять параметры в среде Jasper Server мы просто воспользуемся методами, которое предоставляет нам API и передадим параметры GET-запросом от клиента. API jasper позволяет не только параметризировать данные, используемые в отчетах, но и сами отчеты, что позволяет очень гибко отображать нужные дашборды
Итого
Резюмируя все выше описанное мы рекомендуем к использованию JasperSoft когда есть потребность в создании гибких отчетов согласно шаблонам заказчика. Для этого Jasper предоставляет весь необходимый инструментарий, а работать в ним достаточно просто и удобно.