Библиотека отчетов JasperReports

JasperReports — это Java-библиотека от группы Jaspersoft Community, которая позволяет на основе jrxml-шаблонов (JasperReports XML) и набора данных из различных источников, включая JDBC, создавать отчёты в различных форматах. Отчёты могут быть представлены как на экране, так и выведены на принтер или в файл.

Возможности JasperReports

  • поддержка различных источников данных :
    • JDBC, XML, CSV, JavaBeans, Hibernate;
    • собственных источников данных на основе интерфейса JRDataSource.
  • экспорт в различные форматы данных :
    • PDF, HTML, XHTML, RTF, ODT, CSV, XML;
    • XLS, XLSX, DOCX.
  • использование скриплетов (scriptlets), которые могут быть вызваны до или после определённых этапов генерации отчётов;
  • использование динамических языков JavaScript и Groovy при формировании отчёта;
  • формирование диаграмм с использованием библиотеки JFreeChart;
  • формирование подотчётов (subreports) с неограниченной глубиной вложенности;
  • реализация кросстаблиц (crosstabs).

Графические редакторы jrxml-шаблонов JasperReports

JasperReports формирует отчёты на основе jrxml-шаблонов и набора данных. Для создания jrxml-шаблона используются различные графические редакторы.

iReport Designer
 графический редактор отчётов в виде отдельного приложения. Обеспечивает создание сложных отчетов, содержащих диаграммы, изображения, вложенные отчеты, перекрестные таблицы и многое другое. Для доступа к данным может использовать JDBC, TableModels, JavaBeans, XML, Hibernate, CSV, а также нестандартные источники. Позволяет выводить отчеты в PDF, RTF, XML, XLS, CSV, HTML, XHTML, DOCX.
JasperSoft Studio
  дизайнер отчётов для JasperReports в виде отдельного приложения или в виде plugin'а для Eclipse. Обеспечивает создание и просмотр отчетов, формирование запросов, сложных выражений, макетирование визуальных компонентов типа диаграмм, карт, таблиц, кросстаблиц и многое другое. Для доступа к данным может использовать JDBC, JavaBeans, CSV, Hibernate, Jaspersoft Domain, JSON, NoSQL, XML.
DynamicReports
  свободно распространяемый инструмент динамического создания отчетов на основе JasperReports. Позволяет быстро создавать отчеты и документы, которые могут быть отображены на экране, отправлены на печать или экспортированы в различные известные форматы PDF, Excel, Word. Скачать приложение и примеры с исходными кодами можно на сайте разработчика DynamicReports.

Дистрибутив JasperReports

Скачать библиотеку JasperReports и ее компоненты можно с сайта производителя Jaspersoft Community. Дополнительно к библиотеке необходимы еще зависимости. Следующий список зависимостей был использован в представленном ниже примере с библиотекой jasperreports-5.6.1.jar :

  • com.lowagie.text-2.1.7.jar
  • commons-digester-2.1.jar
  • commons-logging-1.2.jar
  • jasper-compiler-jdt-5.5.9
  • org.apache.commons.beanutils.jar
  • org.apache.commons.collections.jar

Структура jrxml-шаблона

Шаблон отчёта JasperReports — это файл .jrxml, описывающий структура отчёта, его дизайн и логику.

Входными данными отчёта являются параметры и источник данных (data source). К параметрам относятся входные аргументы, которые являются по сути переменными приложения Java. Их значения не изменяются в отчёте и могут быть отображены как в заголовке отчёта, так в колонтитулах на каждой странице.

Для вывода информации в отчёт используют динамическое поле TextField и статическое поле StaticText. Динамическое поле используется для параметров или полей источника данных, а статическое — для постоянного текста.

Отчёты состоят из секций (band), следующие одна за другой строго по вертикали. Каждая секция принадлежит к определённому типу, который влияет на её отображение в отчёте :

Title заголовок в начале отчёта;
Page Header верхний колонтитул на каждой страницы;
Column Header заголовки столбцов отчёта;
Detail область данных;
Column Footer итоговая секция столбца отчёта;
Page Footer нижний колонтитул на каждой страницы;
Last Page Footerнижний колонтитул на последней страницы (вместо Page Footer);
Summary итоговая секция отчёта;
No Data вместо всех секций при отсутствии данных;
Background задний план на каждой странице.

Пример jrxml-шаблона

Ниже рассмотрен пример создания отчета в виде файла report.pdf, формирующий следующую страницу :

Для создания JasperReport отчета был использован шаблон first_report.jrxml, формирующий обычный табличный отчет, включающий заголовок (дата и время создания отчета), наименования колонок и область данных в виде таблицы. Шаблон можно подготовить вручную, но для этого надо знать все тонкости описания каждого поля. Лучше использовать визульный редактор на первом шаге. Потом, конечно же, можно вносить небольшие изменения напрямую в jrxml-шаблон.

Создание шаблона first_report.jrxml с использованием визуального редактора рассмотрен на странице описания iReport Designer. На следующем скриншоте представлен jrxml-шаблон в приложении iReport.

Здесь мы рассмотрим jrxml-шаблон «изнутри».

Список параметров, полей и переменных

В начале отчета перед описанием заголовка определяются параметры (parameter), поля (field) JavaBean объектов и переменные (variable). В теге каждого объекта описывается тип объекта в виде атрибута class. В тексте шаблона параметр обозначается как $P{PARAM}, соответственно поле - $F{FIELD} и переменная - $V{VAR}. В фигурных скобках соответствующего объекта указывается его наименование.

<parameter name="DATE" class="java.util.Date"   />
<field name="state"    class="java.lang.String" />
<field name="item"     class="java.lang.String" />
<field name="date"     class="java.util.Date"   />
<field name="quantity" class="java.lang.Integer"/>
<field name="price"    class="java.lang.Integer"/>
<variable name="cost"  class="java.lang.Integer" >
    <variableExpression>
        <![CDATA[new Integer($F{quantity}.intValue()*
                             $F{price}.intValue())]]>
    </variableExpression>
</variable>

Параметр "DATE" передается в отчет в виде объекта типа java.util.Date и будет использован в заголовке отчета. Поля state, item, date, quantity и price относятся к JavaBean объектам набора данных и используются при формировании таблицы в секции Detail. Переменная "cost" является производным значением, определяющим стоимость товара (произведение quantity и price), и используется в секции Detail в качестве колонки таблицы.

ПРИМЕЧАНИЕ : используемая в jrxml-шаблоне аббревиатура CDATA является сокращением выражения «character data», что в переводе обозначает «символьные данные». Используется CDATA в языках разметки HTML, XHTML, XML и показывает, что определённая часть документа представляет собой символьные данные, в отличие от несимвольных или символьных, но особым образом структурированных, данных. В XML документах фрагмент, помещённый внутрь CDATA относится к содержанию элемента, которая помечена для парсера как содержащая только символьные данные, а не разметку.
В jrxml-шаблоне CDATA используется для обозначения полей $F{price}, переменных $V{sum} и параметров $P{DATA}, а также для определения выражений (см. переменные cost, sum_group, summa).

Заголовок отчета Title

Секция заголовка отчета <title> включает подсекцию <band>, в теге которой определяется размер по вертикали. В подсекцию <band> включено поле <textField>, в котором будет отображена дата формирования отчета. Тег <reportElement> подсекции определяет размер элемента. Выравнивание текста определено в теге textAlignment. Теги textFieldExpression и patternExpression определяют параметр и формат представления значения даты.

<title>
    <band height="20" splitType="Stretch">
        <textField>
            <reportElement x="0" y="0" width="492" height="20"
                   uuid="eb16ce83-eea5-4eca-b6a2-c14149019045"/>
            <textElement textAlignment="Right"/>
            <textFieldExpression>
                    <![CDATA[$P{DATE}]]>
            </textFieldExpression>
            <patternExpression>
                    <![CDATA["dd.MM.yyyy HH:mm:ss"]]>
            </patternExpression>
        </textField>
    </band>
</title>

Заголовки колонок ColumnHeader

Секция заголовка колонок <columnHeader> включает однотипное описание 6 полей (ниже в листинге представлено только два первых поля и последнее поле). Отличия в описании полей связаны только со значениями :

  • x - смещение поля от левого края секции; определяется как сумма значений 'x' и 'width' предыдущего поля (для первого поля они нулевые);
  • width - размер поля;
  • text - заголовок поля.

Следует обратить внимание на подсвечивание ячеек бледно-серым цветом. Для этого устанавливается флаг mode="Opaque" и определяется значение атрибута backcolor.

Значения uid, генерируемые редактором шаблона iReport, уникальны у каждого поля. Секция <box> и элемент <textElement>, определяющие граничные обрамления и выравнивание заголовка колонки, у всех одинаковые.

<columnHeader> 
    <band height="20"> 
        <staticText> 
            <reportElement mode="Opaque" x="0" y="0"
                width="110" height="20" backcolor="#F8F8F8"
                uid="6dcf04a6-2d50-438c-a862-530dba89da06"/> 
            <box> 
                <pen       lineWidth="1.0"/> 
                <topPen    lineWidth="1.0"/> 
                <leftPen   lineWidth="1.0"/> 
                <bottomPen lineWidth="1.0"/> 
                <rightPen  lineWidth="1.0"/> 
            </box> 
            <textElement textAlignment="Center" 
                         verticalAlignment="Middle"> 
                <font isBold="true"/> 
            </textElement> 
            <text><![CDATA[Город]]> </text> 
        </staticText>
        <staticText>
            <reportElement mode="Opaque" x="110" y="0"
                width="90" height="20" backcolor="#F8F8F8" 
                uuid="81c1007d-728f-49fc-9d68-2e081df49fe9"/>
            <box> 
                <pen       lineWidth="1.0"/> 
                <topPen    lineWidth="1.0"/> 
                <leftPen   lineWidth="1.0"/> 
                <bottomPen lineWidth="1.0"/> 
                <rightPen  lineWidth="1.0"/> 
            </box> 
            <textElement textAlignment="Center" 
                         verticalAlignment="Middle"> 
                <font isBold="true"/> 
            </textElement>
            <text><![CDATA[Товар]]></text>
        </staticText>
        . . .
        <staticText>
            <reportElement mode="Opaque" x="412" y="0"
                width="99" height="20" backcolor="#F8F8F8"
                uuid="1ca79763-a681-4487-bb96-9e7e30e2d4fb"/>
            <box> 
                <pen       lineWidth="1.0"/> 
                <topPen    lineWidth="1.0"/> 
                <leftPen   lineWidth="1.0"/> 
                <bottomPen lineWidth="1.0"/> 
                <rightPen  lineWidth="1.0"/> 
            </box> 
            <textElement textAlignment="Center" 
                         verticalAlignment="Middle"> 
                <font isBold="true"/> 
            </textElement>
            <text><![CDATA[Стоимость]]></text>
        </staticText>
    </band>
</columnHeader>

Область данных Detail

Область данных <detail> практически не отличается от секции columnHeader : также определяются смещения ячеек от левой стороны секции и размер ячеек; каждая ячейка имеет граничные обрамления (секция <box>) и соответствующее выравнивание по вертикали. Дополнительно указывается отступ от левой стороны ячейки leftIndent для текстовых значений при выравнивании влево (по умолчанию), и rightIndent для числовых значений при выравнивании вправо.

Отличия касаются отображающего значения ячейки, определяемого тегом <textFieldExpression>. Дополнительно для поля даты $F{date} определен формат представления значения. Если не указать формат представления значений, то к определенной в объекте JavaBean дате добавится текущее время генерации отчета.

<detail>
    <band height="20" splitType="Stretch">
        <textField>
            <reportElement x="0" y="0" width="110" height="20" 
                uuid="1adc41ce-7c09-46fe-960a-dff145ad7e50"/>
            <box> 
                <topPen    lineWidth="1.0"/> 
                <leftPen   lineWidth="1.0"/> 
                <bottomPen lineWidth="1.0"/> 
                <rightPen  lineWidth="1.0"/> 
            </box> 
            <textElement verticalAlignment="Middle">
                    <paragraph leftIndent="5"/>
            </textElement>
            <textFieldExpression>
                    <![CDATA[$F{state}]]>
            </textFieldExpression>
        </textField>
        <textField>
            <reportElement x="110" y="0" width="90" height="20" 
                    uuid="2f5d59ad-6924-492a-b5c4-f9705cc23650"/>
            <box> 
                <topPen    lineWidth="1.0"/> 
                <leftPen   lineWidth="1.0"/> 
                <bottomPen lineWidth="1.0"/> 
                <rightPen  lineWidth="1.0"/> 
            </box> 
            <textElement verticalAlignment="Middle">
                    <paragraph leftIndent="5"/>
            </textElement>
            <textFieldExpression>
                    <![CDATA[$F{item}]]>
            </textFieldExpression>
        </textField>
        <textField pattern="DATE">
            <reportElement x="200" y="0" width="80" height="20"
                    uuid="7f824851-c67d-41c9-ba98-6ab57aa00d47"/>
            <box> 
                <topPen    lineWidth="1.0"/>
                <leftPen   lineWidth="1.0"/>
                <bottomPen lineWidth="1.0"/>
                <rightPen  lineWidth="1.0"/>
            </box> 
            <textElement textAlignment="Center"
                     verticalAlignment="Middle"/>
            <textFieldExpression>
                    <![CDATA[$F{date}]]>
            </textFieldExpression>
            <patternExpression>
                    <![CDATA["dd.MM.yyyy"]]>
            </patternExpression>
        </textField>
        . . .
    </band>
</detail>

Пример создания отчета

В качестве первого примера создания отчета JasperReport рассмотрим Eclipse проект report-generator, структура которого представлена на следующем скриншоте.

Проект включает библиотеку jasperreports-5.6.1.jar с набором зависимых модулей и следующие классы и шаблон :

DataBean.java JavaBean класс, используемый для описания данных;
Data.java модуль формирования набора данных;
ReportGenerator.java модуль формирования JasperReport отчета;
ARIAL.TTF шрифт отчета;
first-report.jrxml jrxml-шаблон отчета.

При создании отчета были выполнены следующие действия :

  1. Формирование набора данных.
  2. Определение входного параметра.
  3. Создания объекта отчета JasperReport на основе jrxml-шаблона и входного параметра.
  4. Загрузка в объект отчета данных.
  5. Вывов отчета в файл.

Листинг DataBean.java

DataBean.java используется для формирования набора данных. В класс включены 3 типа данных (String, Date, int), чтобы можно было бы их по-разному выравнимать и форматировать в отчете. Класс включает конструктор и набор методов get/set.

import java.util.Date;

public class DataBean 
{
    private   String      state;
    private   String      item;
    private   Date        date;
    private   int         quantity;
    private   int         price;

    public DataBean(String state, String item, 
                    Date date, int quantity, int price) {
        super();
        this.state    = state;
        this.item     = item;
        this.date     = date;
        this.quantity = quantity;
        this.price    = price;
    }
    public String getState() {
        return state;
    }
    public void setState(String state) {
        this.state = state;
    }
    public String getItem() {
        return item;
    }
    public void setItem(String item) {
        this.item = item;
    }
    public Date getDate() {
        return date;
    }
    public void setDate(Date date) {
        this.date = date;
    }
    public int getQuantity() {
        return quantity;
    }
    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }
    public int getPrice() {
        return price;
    }
    public void setPrice(int price) {
        this.price = price;
    }
}

Листинг Data.java

Класс формирования набора данных, который представляет собой коллекцию объектов типа DataBean.

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;

public class Data 
{
	private String  ny    = "New York"  ;
	private String  wn    = "Washington";
	private String  fl    = "Florida"   ;
	private String  pc    = "Notebook"  ;
	private String  dvd   = "DVD"       ;
	private String  book  = "Book"      ;
	private String  phone = "Phone"     ;
	
    public ArrayList<DataBean> getDataBeanList()
    {
        ArrayList<DataBean> dataBeanList = new ArrayList<DataBean>();

        dataBeanList.add(new DataBean(ny, pc   , date( 1), 1, 500));
        dataBeanList.add(new DataBean(ny, dvd  , date( 1), 5,  30));
        dataBeanList.add(new DataBean(ny, dvd  , date( 3), 2,  45));
        dataBeanList.add(new DataBean(ny, dvd  , date( 5), 4,  36));
        dataBeanList.add(new DataBean(ny, dvd  , date(18), 5,  41));
        dataBeanList.add(new DataBean(ny, book , date( 8), 2,  11));
        dataBeanList.add(new DataBean(ny, book , date(15), 8,   9));
        dataBeanList.add(new DataBean(ny, book , date(21), 6,  14));
        dataBeanList.add(new DataBean(ny, phone, date(16), 1, 200));
        dataBeanList.add(new DataBean(ny, phone, date(22), 2, 520));

        dataBeanList.add(new DataBean(wn, pc   , date(15), 1, 610));
        dataBeanList.add(new DataBean(wn, dvd  , date( 8), 4,  40));
        dataBeanList.add(new DataBean(wn, dvd  , date(16), 6,  35));
        dataBeanList.add(new DataBean(wn, dvd  , date(23), 3,  46));
        dataBeanList.add(new DataBean(wn, dvd  , date(28), 2,  42));
        dataBeanList.add(new DataBean(wn, book , date(11), 3,  12));
        dataBeanList.add(new DataBean(wn, book , date(17), 9,   8));
        dataBeanList.add(new DataBean(wn, book , date(26), 4,  14));
        dataBeanList.add(new DataBean(wn, book , date(29), 5,  10));
        dataBeanList.add(new DataBean(wn, phone, date(12), 2, 210));
        dataBeanList.add(new DataBean(wn, phone, date(29), 1, 380));

        dataBeanList.add(new DataBean(fl, pc   , date( 3), 1, 460));
        dataBeanList.add(new DataBean(fl, dvd  , date( 1), 3,  49));
        dataBeanList.add(new DataBean(fl, dvd  , date( 8), 4,  32));
        dataBeanList.add(new DataBean(fl, dvd  , date(17), 2,  47));
        dataBeanList.add(new DataBean(fl, book , date( 5), 4,  11));
        dataBeanList.add(new DataBean(fl, book , date(16), 8,   6));
        dataBeanList.add(new DataBean(fl, book , date(23), 6,  16));
        dataBeanList.add(new DataBean(fl, book , date(28), 3,  18));
        dataBeanList.add(new DataBean(fl, phone, date(12), 2, 190));
        dataBeanList.add(new DataBean(fl, phone, date(18), 1, 250));
        dataBeanList.add(new DataBean(fl, phone, date(26), 1, 201));

        return dataBeanList;
    }
    private Date date(int day) 
    {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, 2017);
        calendar.set(Calendar.MONTH, 0);
        calendar.set(Calendar.DAY_OF_MONTH, day);
        return calendar.getTime();
    }
}

Листинг ReportGenerator.java

Класс создания отчета ReportGenerator.java. Все переменные, используемые при генерации отчета, определены отдельно. Код прозрачный и особых комментарий не требуется.

import java.io.File;

import java.util.Map;
import java.util.Date;
import java.util.HashMap;
import java.util.ArrayList;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperCompileManager;

import net.sf.jasperreports.engine.xml.JRXmlLoader;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;

public class ReportGenerator
{
    private String PATH           = "F:\\projects\\report-generator";
    private String REPORT_pdf     = "\\report.pdf";
    private String REPORT_pattern = "\\jrxml\\first_report.jrxml";

    private File                        reportPattern;
    private Map<String, Object>         parameters;
    private JRBeanCollectionDataSource  beanColDataSource;
    private ArrayList<DataBean>         dataBeanList;

    private JasperDesign jasperDesign;
    private JasperReport jasperReport;
    private JasperPrint  jasperPrint ;

    public void create() throws JRException
    {
        Data dataBeanMaker = new Data();
        dataBeanList = dataBeanMaker.getDataBeanList();

        parameters = new HashMap<String, Object>();
        parameters.put("DATE", new Date());

        reportPattern = new File(PATH + REPORT_pattern);
        jasperDesign  = JRXmlLoader.load(reportPattern);
        jasperReport  = JasperCompileManager.compileReport(jasperDesign);
        jasperPrint   = JasperFillManager.fillReport(jasperReport, 
                                                     parameters, 
                                                     beanColDataSource);
        JasperExportManager.exportReportToPdfFile(jasperPrint, 
                                             PROJECT_PATH + REPORT_pdf);
    }

    public static void main(String[] args)
    {
        System.out.println("Начало генерации отчёта");
        try {
            new ReportGenerator().create();
            System.out.println("Генерация отчёта завершена");
        } catch (Exception e) {
            System.err.println("Exception : " + e);
        }
    }
}

Скачать пример

Исходные коды примера создания создания отчета с использованием библиотеки JasperReports можно скачать здесь (7.96 Кб).

Пример настройки JDBC в приложении iReport и формирование JasperReport отчета можно увидеть здесь.

  Рейтинг@Mail.ru