5.5.1.4. JasperReport-шаблоны (.jrxml)

JasperReport-шаблон — zip-архив с разметкой отчёта и, при необходимости, со скомпилированными скриптлетами и собственными библиотеками. В отличие от остальных форматов, логика шаблона пишется на Java: подстановки и агрегаты вычисляются выражениями Jasper, а более сложные вычисления выносятся в скриптлет.

Шаблоны редактируются в Jaspersoft® Studio 6.20 и хранятся в базе данных вместе с остальными печатными формами.

5.5.1.4.1. Состав архива

Содержимое

Назначение

main.jrxml

Главный файл шаблона. Имя фиксировано и задаётся константой JRUtils.TEMPLATE_MAIN_FILE_NAME; с него начинается компиляция.

прочие *.jrxml

Подотчёты, подключаемые из главного файла.

*.class

Скомпилированные скриптлеты. Ищутся и в корне архива, и в каталоге bin — туда их складывает Jaspersoft® Studio 6.20.

*.jar

Собственные библиотеки шаблона. Перед заполнением распаковываются рядом с архивом и добавляются в загрузчик классов скриптлетов.

Скомпилированный шаблон кэшируется: при повторном построении отчёта компиляция .jrxml не выполняется.

5.5.1.4.2. Скриптлеты

Скриптлет объявляется в шаблоне и вызывается через параметр $P{<имя скриптлета>_SCRIPTLET}:

<jasperReport name="detail" scriptletClass="SpelloutScriptlet">
    <scriptlet name="Spellout" class="SpelloutScriptlet"/>
    ...
    <textFieldExpression>
        <![CDATA[$P{Spellout_SCRIPTLET}.numberToStrRu($V{nQtyBase})]]>
    </textFieldExpression>
</jasperReport>

Класс скриптлета загружается отдельным загрузчиком, родителем которого выступает загрузчик сервера приложений. Поэтому скриптлету доступны библиотеки самого сервера, а не только те, что лежат в архиве шаблона.

5.5.1.4.3. Пропись чисел и сумм

Для прописи в загрузчике сервера лежат две библиотеки: ru.bitec:numbertostr (пропись числа) и com.github.javadev:moneytostr (пропись денежной суммы, вызывается через обёртку ru.bitec.numbertostr.MoneyToStr).

Метод

Результат

NumberToStr.spellout(Locale, BigDecimal)

Число прописью набором правил локали по умолчанию: 8421.54 → «восемь тысяч четыреста двадцать одна целая пятьдесят четыре сотых».

NumberToStr.spelloutCardinalFeminine(Locale, BigDecimal)

Число прописью женским родом: 21 → «двадцать одна» вместо «двадцать один».

MoneyToStr.spellout(BigDecimal, Currency, Language, PennyShowType)

Денежная сумма: 8421.54 → «восемь тысяч четыреста двадцать один рубль 54 копейки».

Параметры MoneyToStr.spellout:

Параметр

Значения

Currency

RUR, UAH, USD, EUR

Language

RUS, UKR, ENG

PennyShowType

NUMBER — копейки цифрами, TEXT — копейки прописью, NONE — без копеек

5.5.1.4.3.1. Точность

Библиотека печатает то значение, которое ей передали: величина не округляется и не подгоняется под точность double. Ограничение ровно одно — словарь разрядов, которым она располагает:

  • дробная часть длиннее одиннадцати знаков округляется (HALF_UP): для более мелких разрядов слов нет, последний — «стомиллиардная»;

  • число, у которого целая часть достигла 1018, печатается цифрами целиком: словарь разрядов кончился, а смешивать цифры и слова в одной строке нельзя.

5.5.1.4.3.2. Что передавать на вход

Warning

Передача числа, прошедшего через double, искажает пропись: дробное значение в double хранится приближённо, и это приближение читается словами.

new BigDecimal("12345678.9")   двенадцать миллионов … восемь целых девять десятых
new BigDecimal(12345678.9)     двенадцать миллионов … восемь целых девяносто
                               миллиардов тридцать семь стомиллиардных

Библиотека такой вход не вычищает и печатает ровно то значение, которое получила. По цифрам в форме расхождение не видно — там число выглядит правильно, расходится только пропись.

Точность сохраняется при следующих условиях:

  • колонка в базе — точный десятичный тип (numeric), не double precision и не real, и в запросе шаблона она не приводится к плавающему типу;

  • поле и итоговая переменная объявлены как java.math.BigDecimal, не java.lang.Double;

  • значение передаётся в скриптлет напрямую, без new BigDecimal(...) вокруг него.

<field name="nqtybase" class="java.math.BigDecimal"/>
<variable name="nQtyBase" class="java.math.BigDecimal" calculation="Sum">
    <variableExpression><![CDATA[$F{nqtybase}]]></variableExpression>
</variable>

Note

Функция макроязыка NumberToStrRUS(attr) из TXT- и Excel-шаблонов — независимая реализация внутри сервера. Она работает только с целыми числами: дробное значение приводит к ошибке построения отчёта.

5.5.1.4.4. Пример

Скриптлет:

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);
    }
}

Шаблон — итог по количеству прописью:

<scriptlet name="Spellout" class="SpelloutScriptlet"/>

<field name="nqtybase" class="java.math.BigDecimal"/>
<variable name="nQtyBase" class="java.math.BigDecimal" calculation="Sum">
    <variableExpression><![CDATA[$F{nqtybase}]]></variableExpression>
</variable>

<textField>
    <textFieldExpression>
        <![CDATA["Итого: " + $P{Spellout_SCRIPTLET}.numberToStrRu($V{nQtyBase})]]>
    </textFieldExpression>
</textField>

Результат для итога 8816.22:

Итого: восемь тысяч восемьсот шестнадцать целых двадцать две сотых

See also