YARG — open-source библиотека для генерации отчётов

    Практически каждый разработчик, создающий информационные системы, сталкивается с необходимостью формирования различных отчетов и печатных форм. Это характерно и для большинства приложений разработанных на нашей платформе. Например, в системе, над которой я работаю в настоящее время, их 264. Для того чтобы не писать каждый раз логику формирования отчетов с нуля, мы разработали специальную библиотеку (под катом будет объяснено, почему нам не подошли существующие). Называется она YARG — Yet Another Report Generator.
    YARG позволяет:
    • Генерировать отчет в формате шаблона или конвертировать результат в PDF;
    • Создавать шаблоны отчетов в привычных и распространенных форматах: DOC, ODT, XLS, DOCX,XLSX, HTML;
    • Создавать сложные XLS и XLSX шаблоны: с вложенными областями данных, графиками, формулами и т.д.;
    • Использовать в отчетах изображения и HTML-разметку;
    • Хранить структуру отчетов в формате XML;
    • Запускать standalone приложение для генерации отчетов, что делает возможным использование библиотеки вне Java-экосистемы (например для генерации отчетов в PHP);
    • Интегрироваться с IoC-фреймворками (Spring, Guice).

    Эта библиотека используется в платформе CUBA в качестве основы для движка отчетов. Мы развиваем ее с 2010 года, но совсем недавно решили сделать ее открытой, и выложили ее код на GitHub с лицензией Apache 2.0.
    Данная статья призвана привлечь к ней внимание сообщества.


    В основе библиотеки лежит простая идея разделения выборки данных и отображения данных в готовый отчет (data layer & presentation layer). Выборка данных описывается разнообразными скриптами, а отображение данных настраивается прямо в документах-шаблонах. При этом, для того, чтобы создать шаблон не требуются специальные средства, достаточно иметь под рукой Open Office или Microsoft Office.

    Отчет состоит из так называемых полос. Полоса одновременно является и набором данных и областью в шаблоне, куда эти данные отображаются (связывает data layer и presentation layer).

    Рассмотрим для начала пример в стиле Hello World.

    Очень простой пример


    Представим, что у нас есть фирма и нам нужно вывести список всех сотрудников фирмы, с указанием должности сотрудника.
    Мы создаем полосу отчета c именем Staff, в которой указываем, что данные загружаются SQL запросом
    select name, surname, position from staff

    Java code
    ReportBuilder reportBuilder = new ReportBuilder();
    ReportTemplateBuilder reportTemplateBuilder = new ReportTemplateBuilder()
            .documentPath("/home/haulmont/templates/staff.xls")
            .documentName("staff.xls")
            .outputType(ReportOutputType.xls)
            .readFileFromPath();
    reportBuilder.template(reportTemplateBuilder.build());
    BandBuilder bandBuilder = new BandBuilder();
    ReportBand staff= bandBuilder.name("Staff")
            .query("Staff", "select name, surname, position from staff", "sql")
            .build();
    reportBuilder.band(staff);
    Report report = reportBuilder.build();
    
    Reporting reporting = new Reporting();
    reporting.setFormatterFactory(new DefaultFormatterFactory());
    reporting.setLoaderFactory(
            new DefaultLoaderFactory().setSqlDataLoader(new SqlDataLoader(datasource)));
    
    ReportOutputDocument reportOutputDocument = reporting.runReport(
            new RunParams(report), new FileOutputStream("/home/haulmont/reports/staff.xls"));
    

    Далее мы создаем xls-шаблон, в котором отмечаем именованный регион Staff и расставляем алиасы в ячейках.

    Примеры посложнее рассматриваются ниже.

    Немного истории


    Несколько лет назад у нас возникла потребность в массовом создании отчетов в одном из наших проектов. Нужно было создавать отчеты в формате XLS и DOC, а также конвертировать результат из DOC и XLS в PDF. Нам требовалось, чтобы библиотека:
    1. позволяла создавать отчеты (по крайней мере, шаблоны отчетов) обычным пользователям;
    2. поддерживала загрузку данных из различных источников;
    3. поддерживала различные форматы шаблонов (XLS, DOC, HTML);
    4. поддерживала конвертацию отчетов в PDF;
    5. была расширяемой (позволяла быстрое добавление новых способов загрузки данных и новых форматов шаблонов);
    6. легко встраивалась в различные IoC контейнеры.

    Сначала мы пытались использовать JasperReports, но он, во-первых, не умеет создавать DOC отчеты (есть платная библиотека для этого), во-вторых, его возможности по генерации XLS отчетов сильно ограничены (не получится использовать графики, формулы, форматы ячеек), и, в-третьих, создание шаблонов требует определенного навыка и специальных инструментов, а для описания загрузки данных нужно писать Java-код. Существовало также много библиотек, концентрирующихся на каком-то конкретном формате, но единой библиотеки мы не нашли.
    Поэтому мы решили создать механизм, позволяющий единообразно описывать отчеты, независимо от типа шаблона и способа загрузки данных.

    Первые шаги


    Для работы с XLS уже тогда существовало много разных библиотек (POI-HSSF, JXLS и т.д.) и было решено использовать Apache POI, как самую на тот момент популярную. А вот для работы с DOC файлами такого разнообразия не наблюдалось. Вариантов было совсем немного: использовать UNO Runtime — API для интеграции с сервером Open Office или работать с DOC файлами через COM- объекты. Проект POI-HWPF тогда находился в зачаточном состоянии (недалеко ушел он и сейчас). Мы решили использовать интеграцию с Open Office, потому что увидели много положительных отзывов от людей, которые успешно интегрировались с Open Office на совершенно разных языках (Python, Ruby, C#).
    Если с POI-HSSF все было более или менее просто (за исключением полного отсутствия возможности работы с графиками), то с UNO Runtime нам пришлось испытать множество проблем.
    1. Отсутствует внятный API для работы с таблицами. Например, чтобы скопировать строку таблицы, нужно использовать системный буфер обмена (выделяя строку, копируя и вставляя ее в нужное место).
    2. Для каждой генерации отчета порождается процесс Open Office (и уничтожается после печати). Изначально мы использовали библиотеку bootstrapconnector для порождения процессов, но вскоре убедились, что во многих случаях она оставляет процесс в живых (в зависшем состоянии) или вообще не пытается процесс завершить, что приводило к коллапсу системы через какое-то время. Нам пришлось переписать логику запуска и уничтожения процессов Open Office, воспользовавшись наработками ребят, написавших jodconverter.
    3. UNO Runtime (и сам Open Office сервер) имеет проблемы с потокобезопасностью, из-за чего под нагрузкой сервер может зависнуть или внезапно остановиться из-за внутренней ошибки. Это привело к тому, что пришлось делать механизм повторного запуска отчетов (если отчет не напечатался — попробовать напечатать его еще раз). Это, естественно, сказывается на скорости работы данного вида отчетов.


    Docx4j


    Долгое время мы использовали только XLS и DOC шаблоны, но затем было решено поддержать также XLSX и DOCX. Выбор пал на библиотеку DOCX4J, которая к тому времени набрала популярность.
    Важным достоинством этой библиотеки для нас стало то, что она предоставляет низкоуровневый доступ к структуре документа (фактически оперируя с XML). С одной стороны это несколько усложнило код и логику, а с другой открыло почти безграничные возможности по управлению документом, так как любые операции над ним были теперь возможны.
    Еще более серьезным достоинством стала возможность отказаться от запуска Open Office для генерации DOCX-отчетов.

    Пример посложнее


    Представим, что у нас есть книжный магазин. Давайте попробуем с помощью нашей библиотеки сделать отчет, выводящий в XLS список магазинов и список книг проданных в каждом из магазинов.
    Представим также, что мы (владельцы магазина) совсем не знаем язык программирования Java, но на наше счастье наш системный администратор знаком с SQL, и у нас даже есть база данных, содержащая информацию обо всех продажах.
    В первую очередь давайте создадим шаблон отчета в формате xls. Сразу отметим полосы отчета с помощью именованных регионов.

    Затем опишем загрузку данных с помощью SQL.
    
    select shop.id as "id", shop.name as "name", shop.address as "address" 
    from store shop
    
    select book.author as "author", book.name as "name", book.price as "price",  count(*) as "count" 
    from book book where book.store_id = ${Shop.id} 
    group by book.author, book.name, book.price
    

    Теперь мы должны описать отчет с помощью XML.
    <?xml version="1.0" encoding="UTF-8"?>
    <report name="report">
        <templates>
            <template code="DEFAULT" documentName="bookstore.xls" documentPath="./test/sample/bookstore/bookstore.xls" outputType="xls" outputNamePattern="bookstore.xls"/>
        </templates>
        <rootBand name="Root" orientation="H">
            <bands>
                <band name="Header" orientation="H"/>
                <band name="Shop" orientation="H">
                    <bands>
                        <band name="Book" orientation="H">
                            <queries>
                                <query name="Book" type="sql">
                                    <script>
                                        select book.author as "author", book.name as "name", book.price as "price",  count(*) as "count" from book  where book.store_id = ${Shop.id} group by book.author, book.name, book.price
                                    </script>
                                </query>
                            </queries>
                        </band>
                    </bands>
                    <queries>
                        <query name="Shop" type="sql">
                            <script>
                                select shop.id as "id", shop.name as "name", shop.address as "address" from store shop
                            </script>
                        </query>
                    </queries>
                </band>
            </bands>
            <queries/>
        </rootBand>
    </report>
    

    Запустив отчет из командной строки, мы получим следующий документ

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

    Еще пример


    Теперь представим, что наш магазин получил крупный заказ и нам нужно выставить счет заказчику. Попробуем создать отчет, в котором в качестве шаблона используется документ DOCX, а результат конвертируется в PDF. Загрузку данных для разнообразия опишем Groovy-скриптом.
    <?xml version="1.0" encoding="UTF-8"?>
    <report name="report">
        <templates>
            <template code="DEFAULT" documentName="invoice.docx" documentPath="./test/sample/invoice/invoice.docx" outputType="pdf" outputNamePattern="invoice.pdf"/>
        </templates>
        <formats>
            <format name="Main.date" format="dd/MM/yyyy"/>
            <format name="Main.signature" format="${html}"/>
        </formats>
        <rootBand name="Root" orientation="H">
            <bands>
                <band name="Main" orientation="H">
                    <queries>
                        <query name="Main" type="groovy">
                            <script>
                                return [
                                  [
                                   'invoiceNumber':99987,
                                   'client' : 'Google Inc.',
                                   'date' : new Date(),
                                   'addLine1': '1600 Amphitheatre Pkwy',
                                   'addLine2': 'Mountain View, USA',
                                   'addLine3':'CA 94043',
                                   'signature':<![CDATA['<html><body><b><font color="red">Mr. Yarg</font></b></body></html>']]>
                                ]]
                            </script>
                        </query>
                    </queries>
                </band>
                <band name="Items" orientation="H">
                    <queries>
                        <query name="Main" type="groovy">
                            <script>
                                return [
                                    ['name':'Java Concurrency in practice', 'price' : 15000],
                                    ['name':'Clear code', 'price' : 13000],
                                    ['name':'Scala in action', 'price' : 12000]
                                ]
                            </script>
                        </query>
                    </queries>
                </band>
            </bands>
            <queries/>
        </rootBand>
    </report>
    

    Можно заметить, что Groovy-скрипт возвращает список ассоциативных массивов в качестве результата (если точнее — List<Map<String, Object>). Таким образом, каждый элемент списка представляет собой строку с именованными данными (ключ — имя параметра, значение — параметр).
    Теперь создадим шаблон счета. В таблицу сверху поместим имя и адрес клиента, а также дату выставления счета.
    Далее создадим таблицу со списком товаров, за которые выставляется счет. Для того чтобы таблица 2 была привязана к списку товаров, вставим в первую ячейку специальный маркер (##band=Items).

    Запустив отчет, мы увидим следующее.


    Интеграция и расширение функциональности


    Библиотека изначально проектировалась для расширения и интеграции в различные приложения. Примером такой интеграции может служить использование YARG в платформе CUBA. В качестве IoC-фреймворка мы используем Spring. Давайте посмотрим как YARG может встраиваться в Spring.

    <bean id="reporting_lib_Scripting" class="com.haulmont.reports.libintegration.ReportingScriptingImpl"/>
    <bean id="reporting_lib_GroovyDataLoader" class="com.haulmont.yarg.loaders.impl.GroovyDataLoader">
        <constructor-arg ref="reporting_lib_Scripting"/>
    </bean>
    <bean id="reporting_lib_SqlDataLoader" class="com.haulmont.yarg.loaders.impl.SqlDataLoader">
        <constructor-arg ref="dataSource"/>
    </bean>
    <bean id="reporting_lib_JpqlDataLoader" class="com.haulmont.reports.libintegration.JpqlDataDataLoader"/>
    <bean id="reporting_lib_OfficeIntegration"
          class="com.haulmont.reports.libintegration.CubaOfficeIntegration">
        <constructor-arg value="${cuba.reporting.openoffice.path?:/}"/>
        <constructor-arg>
            <list>
                <value>8100</value>
                <value>8101</value>
                <value>8102</value>
                <value>8103</value>
            </list>
        </constructor-arg>
        <property name="displayDeviceAvailable">
            <value>${cuba.reporting.displayDeviceAvailable?:false}</value>
        </property>
        <property name="timeoutInSeconds">
            <value>${cuba.reporting.openoffice.docFormatterTimeout?:20}</value>
        </property>
    </bean>
    <bean id="reporting_lib_FormatterFactory"
          class="com.haulmont.yarg.formatters.factory.DefaultFormatterFactory">
        <property name="officeIntegration" ref="reporting_lib_OfficeIntegration"/>
    </bean>
    <bean id="reporting_lib_LoaderFactory" class="com.haulmont.yarg.loaders.factory.DefaultLoaderFactory">
        <property name="dataLoaders">
            <map>
                <entry key="sql" value-ref="reporting_lib_SqlDataLoader"/>
                <entry key="groovy" value-ref="reporting_lib_GroovyDataLoader"/>
                <entry key="jpql" value-ref="reporting_lib_JpqlDataLoader"/>
            </map>
        </property>
    </bean>
    <bean id="reporting_lib_Reporting" class="com.haulmont.yarg.reporting.Reporting">
        <property name="formatterFactory" ref="reporting_lib_FormatterFactory"/>
        <property name="loaderFactory" ref="reporting_lib_LoaderFactory"/>
    </bean>
    

    Основной bean в данном описании — reporting_lib_Reporting. Он предоставляет доступ к основной функциональности библиотеки — созданию отчетов. Для нормального функционирования необходимо определить фабрику форматтеров (работающих с различными типами документов — DOCX, XLSX, DOC и т.д.) и фабрику загрузчиков (загружающих данные). Также, если вы собираетесь использовать DOC отчеты, необходимо задать бин reporting_lib_OfficeIntegration, который отвечает за интеграцию с Open Office (с помощью которого обрабатываются DOC и ODT отчеты).
    Следует заметить, что для добавления, например, нового загрузчика не нужно переопределять никаких классов библиотеки, достаточно добавить его в описание свойства dataLoaders в бине reporting_lib_LoaderFactory. Что мы в принципе и сделали, добавив jpql загрузчик данных (<entry key=«jpql» value-ref=«reporting_lib_JpqlDataLoader»/>).
    Для более серьезных изменений можно наследовать библиотечные классы или создавать свои с нуля, реализуя предоставленные интерфейсы. Практически вся функциональность библиотеки связана через интерфейсы и легко расширяется.

    Standalone режим


    Еще одной особенностью библиотеки YARG является то, что ее можно использовать как standalone приложение для генерации отчетов. Таким образом, имея на компьютере установленную JRE, вы можете генерировать отчеты из командной строки. Например, у вас есть серверное приложение на PHP и вы хотите генерировать XLS-отчеты. Вам достаточно создать XLS-шаблон, XML-описание отчета и после этого вы с помощью простой консольной команды сможете генерировать отчет.
    Пример команды:
    yarg -rp ~/report.xml -op ~/result.xls “-Pparam1=20/04/2014”


    Заключение


    В качестве заключения приведу несколько скриншотов UI, который предоставляет платформа CUBA для создания отчетов на движке YARG:

    Фрагменты редактора отчета





    Мастер создания отчетов






    И пример отчета с графиками:

    Отчет с графиками
    Шаблон отчета с графиком и диаграммой:


    Готовый отчет с графиком и диаграммой


    Haulmont
    117,00
    Корпоративные решения любой сложности на Java
    Поделиться публикацией

    Комментарии 42

      0
      А есть ли возможность отлавливать действия пользователя в отчете? Напримере отчета по книжному магазину, пользватель делает даблклик по книги а мы ему показываем приход-расход по данной книги в магазине.
        0
        Отчеты генерируются в разных форматах. Если у Вас будет xls или doc отчет — такое сделать будет проблематично (скорее всего невозможно). Если же отчет в формате HTML — всегда можно javascript дописать, который это будет делать.
          0
          А если встроить макрос в xls или doc, который будет запускаться по клику в ячейке и выполнять подгрузку данных?
            0
            Думаю так сделать можно, но подгрузка данных уже будет осуществляться именно макросом, а не библиотекой. В каком-то смысле это противоречит самой логике библиотеки — на момент формирования документа все данные должны быть загружены. Но теоретически никаких препятствий для этого нет.
              0
              Можно попробовать сделать следующим образом:
              1. Сформировать все движения по всем книгам на одном листе
              2. На втором листе построить сводную таблицу (PivotTable) по книгам

              При двойном клике на книге — ексель будет показывать все данные с первого листа по этой книге.
        0
        Имеется ли возможность сгенерировать полноценный документ в DOC (ODT) с произвольным контентом (текст разбитый на главы, таблицы, изображения) и разными стилями страниц? Или все-таки он может только автозамены делать из БД?
          0
          1. Вы создаете полноценный шаблон, с главами, таблицами, картинками и т.д.
          2. Вставляете алиасы в те места куда должен подставиться текст
          3. Есть возможность вставлять картинки в алиасы
          4. Есть возможность вставить html, в котором также могут быть таблицы и картинки, и который будет отображаться в Word и Open Office Writer

          Я верно понял Ваш вопрос?
            0
            Нет. Я имею ввиду ситуацию, когда количество таблиц, глав текста и т.д. не известно заранее и нет возможности с помощью обычной подстановки создать документ(отчет), в этом случае можно использовать YARG?
              0
              Можно, если вы будете сами генерировать html кусок (содержащий таблицы) скажем groovy скриптом и этот кусок будет подставляться в алиас. Если честно мы пока не часто сталкиваемся с отчетами, похожими на то, что Вы описали. Если Вы опишете подробнее задачу, я, возможно, смогу дать более развернутый ответ.
                0
                Предположим я составляю docx отчет по человеку из соц сети. У него есть сколько-то друзей, по каждому другу я хочу вывести в отчет небольшую статистику, пусть это будет заголовок с его ФИО и табличка со списком общих друзей, если же общих друзей нет, то я не хочу выводить эту табличку.
                  0
                  Можно, генерировать html-таблицу groovy-скриптом. Если друзей нет, просто пустую таблицу вставлять. Второй путь — сделать таблицу с друзьями без заголовка, то есть если друзей не будет — не будет ни одной строки в таблице.
                    0
                    Но мне нужен docX а не html:) И вы, наверное, не совсем меня поняли, если у человека 200 друзей, я хочу в одном отчете получить 200 заголовков и 200 таблиц — по каждому другу. Тут вопрос в том, можно ли привязывать не только таблицу к списку но и кусок документа, содержащий в себе другие элементы.
                    У себя я решаю похожую задачу, используя Apache POI, понятно, что с шаблонизатором было бы поудобнее)
                      0
                      Я имел ввиду, что html-кусок вставляется в docx и выглядит как часть документа. Такая возможность есть в библиотеке.

                      Тут вопрос в том, можно ли привязывать не только таблицу к списку но и кусок документа, содержащий в себе другие элементы.


                      Внутри ячейки таблицы могут находиться любые элементы, в том числе и другие таблицы. То есть будет таблица, в каждой строке которой будет контент связанный с одним другом.
                        0
                        xdocreport что я приводил ниже решит эту проблему.
                          0
                          Если не критично, чтобы именно docx, и .odt тоже подойдёт (который, по сути, то же самое только с другим бантиком), посмотрите на appy.pod
                          Это «шаблонизатор» для Python. И там как раз можно целые куски документа оборачивать в условия и/или циклы.
                        0
                        Или же Вам стоит использовать xls/xlsx отчеты. Есть возможность генерировать из них pdf.
                        0
                        Можно ли с помощью YARG автоматизировать создание например Спецификации по ЕСКД?

                        Пример тут: ГОСТ 2.106-96 Приложение Б (страница 33)

                        Как сделать так, чтобы скрипт определял по каким правилам заполнять каждую ячейку таблицы? Просто тут столбец «Наименование» используется и для вывода наименования изделий, и для вывода наименования групп элементов. При чем между группами должны быть еще пустые строки (на примере это не видно).
                          0
                          А можете пояснить — какие данные нужно вставлять в спецификацию?
                            0
                            Кажется я понял. Если использовать docx, придется наверное вставлять html-разметку для групп чтобы текст был подчеркнут, и проставлен alignment (чтобы по центру надпись отображалась).
                              0
                              Скорее всего даже проще нужно было бы сделать — каждая строка таблицы начинается с названия группы, значит можно разделить 2 алиаса — название группы и список под ней, и стил названия задать какой нужно сразу.
                          0
                          Xdocreport ваш друг. Он позволяет в шаблоне документов использовать шаблонизаторы. В том числе различные условия прописывать для генерации.
                            0
                            Довольно интересная штука, спасибо. Посмотрю. Возможно пригодится.
                              0
                              Я до него использовал как раз таки Docx4j сейчас предпочитаю использовать его, функционала больше.
                                0
                                В docx4j меня привлекла возможность также работать с xlsx и довольно активное развитие.
                                Xdocreport интересен, но я не уверен, что он все наши требования сможет выполнить.
                                Он может растущие таблицы как то организовать? А вставку картинок? Вставку html? Заранее спасибо за ответ (его код я пока не успел посмотреть, поэтому спрашиваю Вас).
                                  0
                                  В docx4j меня привлекла возможность также работать с xlsx и довольно активное развитие.

                                  xdocreport тоже умеет плюс еще умеет работать с odt.

                                  Он может растущие таблицы как то организовать?

                                  Да. Сам такое делал.
                                  А вставку картинок?
                                  Вставку html?

                                  Насколько помню по документации да.
                                    0
                                    В документации xdocreport не упоминается о возможности работы с xlsx.
                                      0
                                      Ха и точно я же использовал jxls
                      0
                      Сколько я понял это похоже на FastReport. Извините если что то не увидел, но источником для заполнения может быть не SQL запрос, а модель/массив моделей, Map?
                        0
                        Можно, если Вы используете groovy-скрипт для загрузки данных, из него Вы возвращаете как раз список Map. В нашей платформе мы реализовали расширение, которое позволяет использовать аннотированные jpa-сущности в качестве источника данных.
                        0
                        Искал в своё время что-то похожее для генерации отчётов в PDF из Python.
                        Чтобы шаблон можно было просто «нарисовать» в MS Word / LibreOffice, а отчёт генерировался в PDF на основании модели из Python.
                        Нашёл appy.pod, который, по сути, всё это и делает.
                        Но расстраивает его зависимость от LibreOffice сервера для конвертации в PDF (отчёты в ODT/ODS генерируются без каких либо зависимостей).
                        Ещё в appy.pod не очень удобный / переносимый способ указания маркеров — через специальные поля (с которыми, по сути, можно работать только в LibreOffice).
                          0
                          У нас есть возможность конвертировать docx в pdf без OpenOffice. Другое дело, что с ним pdf-ки практически идентичны docx, а без него бывают расхождения. Если нет требования тотального соответствия — можно использовать этот вариант (docx -> pdf).
                          У нас есть пользователи, которые из php-приложения вызывают библиотеку в standalone-режиме. У них тоже была задача создавать docx и конвертировать в pdf. Ее они решили.
                          0
                          Вот так совпадение
                            0
                            Я правильно понимаю что вы используете Docx4j для генерации отчета?
                              0
                              Для генерации docx/xlsx отчетов — да. Также поддерживаются отчеты xls, doc, html(freemarker) — они естественно генерируются с помощью других библиотек.
                              0
                              а чем вам POI не угодил для xlsx? Раз уж вы используету POI-HSSF для генерации xlx, используйте POI-XSSF для xslx. У этих модулей общие интерфейсы, так что код будет один и тот же.
                              В XSSF тоже можно ковыряться в низкоуровневом XML если уж вам этого хочется.
                              Кроме того, в POI есть модуль SXSSF (S спереди означает streaming). В HSSF и XSSF модель документа строится в памяти и в случае больших репортов получаются довольно развесистые структуры которые жрут память. В SXSSF данные пишутся сразу в файл. Часть функциональности при этом теряется, зато объем памяти практически константый.
                                0
                                У POI чудовищный размер.
                                  0
                                  Насколько я знаю — в HSSF/XSSF нет полноценной поддержки графиков (или по крайней мере не было на момент написания соответствующего кода), а это для нас очень важная фича.
                                    0
                                    с графика, действительно, есть над чем поработать.
                                    Стандартный воркэраунд в XSSF — это создать шаблон с графиком а данные заливать через API.
                                  0
                                  Интересный фреймворк, поразбирался, но не нашел один момент про колонки.

                                  Есть возможность делать динамические колонки (т.е. из данных берем содержимое и кол-во заголовков и столбцов)?

                                  Аналогично, есть ли возможность делать полудинамические колонки (т.е. набор колонок известен, они заданы в дизайне, но могут в зависимости от параметров шаблона скрываться (например, группировка по разным полям))?
                                    0
                                    Добрый день.

                                    Для создания «динамических» колонок существует несколько способов:

                                    1) Вертикальная полоса (растет вправо). Это решение подходит, если у Вас фиксированное число строк. Вы можете, например, сделать в xls и xlsx 2 вертикальных полосы, одна из которых будет содержать заголовки колонок, а другая — собственно данные.

                                    2) Вертикальная полоса вложенная в горизонтальную. Это решение подходит, если Вам заранее неизвестно число строк. Так как полосы образуют иерархическую структуру, вы можете объявить горизонтальную полосу, вложенную в нее вертикальную, и уже в вертикальной полосе решать, какие данные показывать.

                                    Если Вам будет интересно, мы сможем добавить пример на гитхабе.

                                    По поводу «полудинамических» колонок — на данный момент такой возможности нет, в будущем может появиться, если будут заинтересованные пользователи.
                                    0
                                    Это все круто, а что если у меня есть List или на крайний случай Map, и использовать sql запросы или xml у меня нет нужды? Тем более что в java проектах зачастую используется какая-то orm. как мне занести в xslx данные минуя xml?
                                      0
                                      Добрый день.

                                      Во-первых, xml не обязателен для создания отчета. Вы можете выполнить все действия используя только Java API. Как пример можно взять тест.

                                      Во-вторых, Вы можете реализовать свой собственный ReportDataLoader, который будет отвечать вашим требованиям. Например в нашей платформе CUBA есть DataLoader, который позволяет в отчете как источник данных использовать OpenJpa-сущность. DataLoader может возращать вообще любый данные, главное чтобы они были представлены как список ассоциативных массивов (List<Map<String, Object>>).

                                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                    Самое читаемое