.. _gs3_jasper_template:
JasperReport-шаблоны (``.jrxml``)
==================================
JasperReport-шаблон — zip-архив с разметкой отчёта и, при необходимости,
со скомпилированными скриптлетами и собственными библиотеками. В отличие от
остальных форматов, логика шаблона пишется на Java: подстановки и агрегаты
вычисляются выражениями Jasper, а более сложные вычисления выносятся
в скриптлет.
Шаблоны редактируются в :term:`Jaspersoft® Studio 6.20` и хранятся в базе данных
вместе с остальными печатными формами.
Состав архива
-------------
.. list-table::
:header-rows: 1
:widths: 25 75
* - Содержимое
- Назначение
* - ``main.jrxml``
- Главный файл шаблона. Имя фиксировано и задаётся константой
``JRUtils.TEMPLATE_MAIN_FILE_NAME``; с него начинается компиляция.
* - прочие ``*.jrxml``
- Подотчёты, подключаемые из главного файла.
* - ``*.class``
- Скомпилированные скриптлеты. Ищутся и в корне архива, и в каталоге
``bin`` — туда их складывает :term:`Jaspersoft® Studio 6.20`.
* - ``*.jar``
- Собственные библиотеки шаблона. Перед заполнением распаковываются рядом
с архивом и добавляются в загрузчик классов скриптлетов.
Скомпилированный шаблон кэшируется: при повторном построении отчёта компиляция
``.jrxml`` не выполняется.
Скриптлеты
----------
Скриптлет объявляется в шаблоне и вызывается через параметр
``$P{<имя скриптлета>_SCRIPTLET}``:
.. code-block:: xml
...
Класс скриптлета загружается отдельным загрузчиком, родителем которого выступает
загрузчик :term:`сервера приложений <Сервер приложений>`. Поэтому скриптлету доступны
библиотеки самого сервера, а не только те, что лежат в архиве шаблона.
Пропись чисел и сумм
--------------------
Для прописи в загрузчике сервера лежат две библиотеки: ``ru.bitec:numbertostr``
(пропись числа) и ``com.github.javadev:moneytostr`` (пропись денежной суммы,
вызывается через обёртку ``ru.bitec.numbertostr.MoneyToStr``).
.. list-table::
:header-rows: 1
:widths: 55 45
* - Метод
- Результат
* - ``NumberToStr.spellout(Locale, BigDecimal)``
- Число прописью набором правил локали по умолчанию:
``8421.54`` → «восемь тысяч четыреста двадцать одна целая пятьдесят четыре сотых».
* - ``NumberToStr.spelloutCardinalFeminine(Locale, BigDecimal)``
- Число прописью женским родом:
``21`` → «двадцать одна» вместо «двадцать один».
* - ``MoneyToStr.spellout(BigDecimal, Currency, Language, PennyShowType)``
- Денежная сумма:
``8421.54`` → «восемь тысяч четыреста двадцать один рубль 54 копейки».
Параметры ``MoneyToStr.spellout``:
.. list-table::
:header-rows: 1
:widths: 25 75
* - Параметр
- Значения
* - ``Currency``
- ``RUR``, ``UAH``, ``USD``, ``EUR``
* - ``Language``
- ``RUS``, ``UKR``, ``ENG``
* - ``PennyShowType``
- ``NUMBER`` — копейки цифрами, ``TEXT`` — копейки прописью,
``NONE`` — без копеек
Точность
~~~~~~~~
Библиотека печатает то значение, которое ей передали: величина не округляется
и не подгоняется под точность ``double``. Ограничение ровно одно — словарь
разрядов, которым она располагает:
- дробная часть длиннее одиннадцати знаков округляется (``HALF_UP``): для более
мелких разрядов слов нет, последний — «стомиллиардная»;
- число, у которого целая часть достигла 10\ :sup:`18`, печатается цифрами
целиком: словарь разрядов кончился, а смешивать цифры и слова в одной строке
нельзя.
Что передавать на вход
~~~~~~~~~~~~~~~~~~~~~~
.. warning::
Передача числа, прошедшего через ``double``, искажает пропись: дробное значение
в ``double`` хранится приближённо, и это приближение читается словами.
.. code-block:: text
new BigDecimal("12345678.9") двенадцать миллионов … восемь целых девять десятых
new BigDecimal(12345678.9) двенадцать миллионов … восемь целых девяносто
миллиардов тридцать семь стомиллиардных
Библиотека такой вход не вычищает и печатает ровно то значение, которое получила.
По цифрам в форме расхождение не видно — там число выглядит правильно, расходится
только пропись.
Точность сохраняется при следующих условиях:
- колонка в базе — точный десятичный тип (``numeric``), не ``double precision``
и не ``real``, и в запросе шаблона она не приводится к плавающему типу;
- поле и итоговая переменная объявлены как ``java.math.BigDecimal``, не ``java.lang.Double``;
- значение передаётся в скриптлет напрямую, без ``new BigDecimal(...)`` вокруг него.
.. code-block:: xml
.. note::
Функция макроязыка ``NumberToStrRUS(attr)`` из :ref:`TXT- `
и :ref:`Excel-шаблонов ` — независимая реализация внутри
сервера. Она работает только с целыми числами: дробное значение приводит
к ошибке построения отчёта.
Пример
------
Скриптлет:
.. code-block:: java
import net.sf.jasperreports.engine.JRDefaultScriptlet;
import net.sf.jasperreports.engine.JRScriptletException;
import ru.bitec.numbertostr.NumberToStr;
import java.math.BigDecimal;
import java.util.Locale;
public class SpelloutScriptlet extends JRDefaultScriptlet {
public String numberToStrRu(BigDecimal npSum) throws JRScriptletException {
return NumberToStr.spellout(new Locale("ru"), npSum);
}
}
Шаблон — итог по количеству прописью:
.. code-block:: xml
Результат для итога ``8816.22``::
Итого: восемь тысяч восемьсот шестнадцать целых двадцать две сотых
.. seealso::
- :ref:`Отчеты ` — хранение шаблонов, запуск построения, события
строителя отчётов.
- :ref:`REST-сервис отчётов `.
- :java:type:`ru.bitec.gtk.core.report.CoreReportBuilder` — построение отчёта
из прикладного кода.