报表示例

XLS 报表

本示例基于 Library(图书馆) 应用程序,请按照 说明 设置应用程序并创建实体和视图。

在本示例中,我们将创建关于书籍作者的一个报表。给定一个作者,报表中列举他的所有书籍、每本书的出版商,以及该书本保存在图书馆的哪个部门,还有每个部门中保存了多少本。结果如下:

sample1 result
  1. 报表数据结构

    sample1 structure

    报表带区如下:

    • header 带区,报表头。包含带有 Groovy 脚本的数据集,该脚本输出报表 外部参数

      return [['authorName' : (params['author'].firstName + ' ' + params['author'].lastName)]]
    • book 带区通过执行以下 SQL 查询输出书籍列表:

      select b.name as book_name, b.id as book_id
      from BOOK b
          join BOOK_AUTHOR_LINK ba on ba.book_id = b.id
          join AUTHOR a on a.id = ba.author_id
      where a.id = ${author}

      此查询使用外部报表参数 - author。该参数是 Entity 类型,但在 SQL 查询中,可以直接将其与实体标识符字段进行比较;类型转换会自动完成。

    • publisher 带区是 book 的子带区,通过执行以下 SQL 查询输出图书出版商:

      select p.name as publisher, bp.year_, p.id as publisher_id
      from BOOK_PUBLICATION bp
          join PUBLISHER p on p.id = bp.publisher_id
      where bp.book_id = ${book.book_id}

      此查询使用父带区字段 book_id 作为参数。以这种方式指定了父带区和子带区之间的依赖关系。

    • publication 带区是 publisher 带区的子带区,通过执行以下 SQL 查询输出图书出版物:

      select ld.name as department, sum(bi.book_count) as amount
      from BOOK_INSTANCE bi
          join BOOK_PUBLICATION bp on bp.id = bi.book_publication_id
          join LIBRARY_DEPARTMENT ld on ld.id = bi.library_department_id
      where bp.publisher_id = ${publisher.publisher_id} and bp.book_id = ${book.book_id}
      group by ld.name

      此查询使用父带区字段作为参数 - book_idpublisher_id

  2. 报表 参数

    Parameters(参数) 标签页声明了一个报表的外部参数 - Author

    sample1 param

    运行报表时,用户必须输入此参数。书籍作者是通过应用程序中的 Author.list 视图进行选择的。

  3. 报表 模板

    Templates(模板) 标签页包含一个 XLS 模板,从 BooksByAuthor.xls 加载。

    sample1 template

可以从 Reports(报表)Run Report(运行报表) 视图运行该报表。

交叉报表

本示例基于 Library(图书馆) 应用程序,请按照 说明 设置应用程序并创建实体和视图。

本示例中,我们将创建一个图书馆部门的交叉报表,列举图书馆每个部门每个月买多少本书。报表内容会向水平和垂直方向填充,并为每个部门计算每个月的数量:

crosstab result

创建交叉报表时,请在报表详情视图的 区域 标签页上选择 Crosstab(双向) 带区方向。选择此方向将自动添加三个数据集:

  1. <band_name>_dynamic_header - 这个数据集的数据将向右复制,类似于包含表格列标题的垂直带区。

  2. <band_name>_master_data - 这个数据集的数据向下复制,类似于包含表格行标题的水平带区。

  3. <band_name> - 与其所属带区名称相同的数据集,是实现单元格矩阵的主内容带区。

这些数据集可以是任何支持的数据集类型:SQLJPQLGroovy 等。

例如,对于 Library 示例程序中 BookInstance 实体的交叉报表具有下列结构:

crosstab structure
  1. 报表数据 结构。有三个数据集:

    • bi_dynamic_header 数据集将返回月份的名称:

      import java.text.DateFormatSymbols
      
      List result = new ArrayList()
      DateFormatSymbols dateFormatSymbols = DateFormatSymbols.getInstance(Locale.ENGLISH)
      for (i in 0..dateFormatSymbols.months.length - 1) {
          result.add(["header_id" : i + 1, "month_name" : dateFormatSymbols.months[i]])
      }
      return result
    • bi_master_data 数据集返回用户选择的图书馆部门的名称和 ID,这些数据以 外部报表参数 的形式提供:

      select name as name, id as department_id
      from LIBRARY_DEPARTMENT
      where id in (${selected_departments})
    • bi 数据集为矩阵单元格提供数据,数据内容为部门每月购进的书本总数。使用 bi_master_data@department_id(部门 ID)作为单元格的垂直坐标,使用 bi_dynamic_header@header_id(月份名称)作为单元格的水平坐标,并用 amount 值填充对应的矩阵单元格。

      在下面的示例中,报表还有两个外部参数:start_dateend_date 用于定义书籍实例创建日期的范围。最好使用 交叉参数验证 来确保参数值在合理的范围。

      select bi.library_department_id as bi_master_data@department_id,
             month(bi.created_date) as bi_dynamic_header@header_id,
             sum(bi.book_count) as "amount"
      from BOOK_INSTANCE bi
      where bi.created_date >= ${start_date} and bi.created_date<= ${end_date}
      and bi.library_department_id in (${bi_master_data@department_id})
      and month(bi.created_date) in (${bi_dynamic_header@header_id})
      group by bi.library_department_id,month(bi.created_date)
      order by bi.library_department_id,month(bi.created_date)
  2. 报表 参数

    Parameters(参数) 标签页包含声明的 3 个报表外部参数 - selected_departmentsstart_dateend_date

    crosstab external params

    当运行报表时,用户需要输入这些参数。可以通过应用程序的 LibraryDepartment.list 视图选取部门。

  3. 报表 模板

    可以使用 Microsoft OfficeLibreOffice 创建 XLS 报表模板。

    模板示例:DepartmentBooks.xls,垂直方向上输出 Departments,水平方向输出按月份统计的书籍数量。

    报表模板包含交叉带区的所有三个数据集对应的 命名区域 以及列标题的命名区域: <band_name>_header。在这个例子中,是 bi_header

可以在通用报表列表视图 Reports(报表)→ *Run Reports(运行报表) 运行。

JasperReports 报表

本示例基于 Library(图书馆) 应用程序,请按照 说明 设置应用程序并创建实体和视图。

本示例中,我们将创建一个 JRXML 报表展示某个部门内图书出版物的列表:

sample jasper result
  1. 报表详情 标签页,定义报表名称:Books availability

  2. 切换至 带区 标签页:

    sample jasper bands

    数据带区:

    • Header band - 报表头。包含 Groovy 脚本的数据集,该脚本输出报表 外部参数 值:

      return [['library_department_name' : params['library_department'].name]]
    • Data 带区通过运行以下 Groovy 脚本输出书籍实例的列表,外部输入参数为部门:

      import com.company.library.entity.LiteratureType
      
      def result = []
      
      def ltList = dataManager.load(LiteratureType).all().list();
      ltList.each(lt->{
          def count = dataManager.loadValue("select sum(bi.bookCount) from BookInstance bi where bi.libraryDepartment = :department and bi.bookPublication.book.literatureType = :lt ", Long)
                  .parameter("department", params['library_department']).parameter("lt", lt)
                  .one();
      
          def refCount = dataManager.loadValue("select sum(bi.bookCount) from BookInstance bi where bi.libraryDepartment = :department and bi.bookPublication.book.literatureType = :lt and bi.isReference = true", Long)
                  .parameter("department", params['library_department']).parameter("lt", lt)
                  .one();
      
          result.add(['literature_type_name': lt.name,
                      'books_instances_amount': count,
                      'reference_books_instances_amount': refCount])
      });
      return result;

    此查询使用外部报表参数 - library_department。这个参数是 Entity 类型,但可以直接将其与实体标识符字段进行比较,类型转换会自动完成。

  3. 报表 参数

    Parameters(参数) 标签页包含一个报表外部参数 - Department

    sample jasper parameter

    运行报表时,用户必须输入此参数。部门是通过应用程序中的 LibraryDepartment.list 视图选择的。

  4. 报表 模板

    新建 JRXML 文件或者下载 BookAvailability.jrxml,该文件包含下列内容:

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- Created with Jaspersoft Studio version 6.4.0.final using JasperReports Library version 6.4.1 -->
    <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="books" pageWidth="595" pageHeight="842" whenNoDataType="AllSectionsNoDetail" columnWidth="535" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20">
        <property name="template.engine" value="tabular_template"/>
        <property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
        <style name="Table_TH" mode="Opaque" backcolor="#066990">
            <box>
                <topPen lineWidth="0.5" lineColor="#000000"/>
                <bottomPen lineWidth="0.5" lineColor="#000000"/>
            </box>
        </style>
        <style name="Table_CH" mode="Opaque" forecolor="#FFFFFF" backcolor="#06618F" hTextAlign="Center" fontSize="12">
            <box>
                <topPen lineWidth="0.5" lineColor="#000000"/>
                <bottomPen lineWidth="0.5" lineColor="#000000"/>
            </box>
        </style>
        <style name="Table_TD" mode="Opaque" backcolor="#FFFFFF" hTextAlign="Center">
            <box>
                <topPen lineWidth="0.5" lineColor="#000000"/>
                <bottomPen lineWidth="0.5" lineColor="#000000"/>
            </box>
        </style>
        <subDataset name="Data">
            <field name="literature_type_name" class="java.lang.String"/>
            <field name="books_instances_amount" class="java.lang.Long"/>
            <field name="reference_books_instances_amount" class="java.lang.Long"/>
        </subDataset>
        <field name="library_department_name" class="java.lang.String"/>
        <title>
            <band height="72">
                <frame>
                    <reportElement mode="Opaque" x="-20" y="-20" width="595" height="92" backcolor="#006699"/>
                    <staticText>
                        <reportElement x="20" y="10" width="555" height="30" forecolor="#FFFFFF"/>
                        <textElement textAlignment="Center">
                            <font size="20" isBold="true"/>
                        </textElement>
                        <text><![CDATA[Book availability in department]]></text>
                    </staticText>
                    <textField>
                        <reportElement x="20" y="50" width="555" height="30" forecolor="#FFFFFF"/>
                        <box>
                            <pen lineWidth="1.0" lineColor="#FFFFFF"/>
                            <topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
                            <leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
                            <bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
                            <rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
                        </box>
                        <textElement textAlignment="Center" verticalAlignment="Middle">
                            <font fontName="SansSerif" size="20" isBold="true"/>
                        </textElement>
                        <textFieldExpression><![CDATA[$F{library_department_name}]]></textFieldExpression>
                    </textField>
                </frame>
            </band>
        </title>
        <detail>
            <band height="204">
                <componentElement>
                    <reportElement x="0" y="4" width="555" height="200" forecolor="#FFFFFF">
                        <property name="com.jaspersoft.studio.layout" value="com.jaspersoft.studio.editor.layout.VerticalRowLayout"/>
                        <property name="com.jaspersoft.studio.table.style.table_header" value="Table_TH"/>
                        <property name="com.jaspersoft.studio.table.style.column_header" value="Table_CH"/>
                        <property name="com.jaspersoft.studio.table.style.detail" value="Table_TD"/>
                        <property name="net.sf.jasperreports.export.headertoolbar.table.name" value=""/>
                        <property name="com.jaspersoft.studio.components.autoresize.proportional" value="true"/>
                    </reportElement>
                    <jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd">
                        <datasetRun subDataset="Data">
                            <dataSourceExpression><![CDATA[$P{REPORTING}.dataset("Data")]]></dataSourceExpression>
                        </datasetRun>
                        <jr:column width="188">
                            <jr:columnHeader style="Table_CH" height="30">
                                <staticText>
                                    <reportElement x="0" y="0" width="188" height="30" forecolor="#FFFFFF"/>
                                    <box>
                                        <pen lineColor="#FFFFFF"/>
                                    </box>
                                    <textElement textAlignment="Center" verticalAlignment="Middle">
                                        <font fontName="SansSerif" size="12" isBold="true"/>
                                    </textElement>
                                    <text><![CDATA[Literature Type]]></text>
                                </staticText>
                            </jr:columnHeader>
                            <jr:detailCell style="Table_TD" height="30">
                                <textField>
                                    <reportElement x="0" y="0" width="188" height="30"/>
                                    <textElement textAlignment="Center" verticalAlignment="Middle">
                                        <font fontName="SansSerif" size="12"/>
                                    </textElement>
                                    <textFieldExpression><![CDATA[$F{literature_type_name}]]></textFieldExpression>
                                </textField>
                            </jr:detailCell>
                        </jr:column>
                        <jr:column width="186">
                            <jr:columnHeader style="Table_CH" height="30">
                                <staticText>
                                    <reportElement x="0" y="0" width="186" height="30" forecolor="#FFFFFF"/>
                                    <textElement textAlignment="Center" verticalAlignment="Middle">
                                        <font fontName="SansSerif" size="12" isBold="true"/>
                                    </textElement>
                                    <text><![CDATA[Book Amount]]></text>
                                </staticText>
                            </jr:columnHeader>
                            <jr:detailCell style="Table_TD" height="30">
                                <textField>
                                    <reportElement x="0" y="0" width="186" height="30"/>
                                    <textElement textAlignment="Center" verticalAlignment="Middle">
                                        <font size="12"/>
                                    </textElement>
                                    <textFieldExpression><![CDATA[$F{books_instances_amount}]]></textFieldExpression>
                                </textField>
                            </jr:detailCell>
                        </jr:column>
                        <jr:column width="181">
                            <jr:columnHeader style="Table_CH" height="30">
                                <staticText>
                                    <reportElement x="0" y="0" width="181" height="30" forecolor="#FFFFFF"/>
                                    <textElement textAlignment="Center" verticalAlignment="Middle">
                                        <font fontName="SansSerif" size="12" isBold="true"/>
                                    </textElement>
                                    <text><![CDATA[Reference Book Amount]]></text>
                                </staticText>
                            </jr:columnHeader>
                            <jr:detailCell style="Table_TD" height="30">
                                <textField isBlankWhenNull="false">
                                    <reportElement x="0" y="0" width="181" height="30" forecolor="#000000"/>
                                    <textElement textAlignment="Center" verticalAlignment="Middle">
                                        <font size="12"/>
                                    </textElement>
                                    <textFieldExpression><![CDATA[$F{reference_books_instances_amount}]]></textFieldExpression>
                                </textField>
                            </jr:detailCell>
                        </jr:column>
                    </jr:table>
                </componentElement>
            </band>
        </detail>
        <pageFooter>
            <band height="17">
                <textField>
                    <reportElement mode="Opaque" x="0" y="4" width="515" height="13" backcolor="#E6E6E6"/>
                    <textElement textAlignment="Right"/>
                    <textFieldExpression><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
                </textField>
                <textField evaluationTime="Report">
                    <reportElement mode="Opaque" x="515" y="4" width="40" height="13" backcolor="#E6E6E6"/>
                    <textFieldExpression><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
                </textField>
                <textField pattern="M/d/yy">
                    <reportElement x="0" y="4" width="280" height="13"/>
                    <textFieldExpression><![CDATA[new java.util.Date()]]></textFieldExpression>
                </textField>
            </band>
        </pageFooter>
    </jasperReport>

    这个模板中的表格与子数据集绑定。title 元素直接使用 Header 区数据。可以在 JasperReports 可视化设计器中打开模板文件来查看报表布局。

    将新模板上传到应用程序,选择任何一种输出类型,并将其设置为默认值:

    sample jasper template

可以在通用报表列表视图 Reports(报表)→ *Run Reports(运行报表) 运行。

HTML 报表(Groovy 模板引擎)

本示例基于 Library(图书馆) 应用程序,请按照 说明 设置应用程序并创建实体和视图。

本示例创建一个展示某个城市中图书出版物列表的报表。输出格式为 HTML:

html groovy result
  1. 使用 JPQL 数据集创建报表:

    html groovy bands

    BookPublications 区域用来输出图书出版物列表,使用如下 JPQL 查询语句:

    select b.name as "book",
    p.name as "publisher"
    from BookPublication bp
    left join bp.book b
    left join bp.publisher p
    where bp.city = ${city}

    这个查询使用了外部的报表参数 - city。该参数是 Entity 类型。

  2. 报表 参数

    Parameters(参数) 标签页声明了一个报表外部参数 - City

    html groovy parameter

    当运行报表时,用户必须输入该参数。城市的选择会通过 City.list 视图进行。

  3. 创建报表 模板

    新建一个 HTML 文件包含下列内容,或者下载 PublicationByCity.html 模板:

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
    
    <head>
        <title> Publications by city </title>
        <style type="text/css">
            body {
                font: 12pt Georgia, "Times New Roman", Times, serif;
                line-height: 1.3;
                padding-top: 30px;
            }
    
            tbody tr {
                height: 40px;
                min-height: 20px
            }
        </style>
    </head>
    
    <body>
    <h1>Publications, published in <% out << "${Root.fields.city.name}" %>
    </h1>
    <% def bookPublications=Root.bands.BookPublications.fields %>
    <table class="report-table" border="1" cellspacing="2">
        <thead>
        <tr>
            <th>Book</th>
            <th>Publisher</th>
        </tr>
        </thead>
        <tbody>
        <% bookPublications.title.eachWithIndex{ elem, index ->
        out << "<tr><td> ${bookPublications.book[index]} </td><td> ${bookPublications.publisher[index]} </td></tr>"
        } %>
        </tbody>
    </table>
    </body>
    
    </html>

    输入参数的值用来生成报表标题:${Root.fields.city.name}

    bookPublications 变量定义如下:

    <% def bookPublications=Root.bands.BookPublications.fields %>

    该变量在表格体中用来显示报表字段。

    <% bookPublications.title.eachWithIndex{ elem, index ->
    out << "<tr><td> ${bookPublications.book[index]} </td><td> ${bookPublications.publisher[index]} </td></tr>"
    } %>

    上传新的模板,然后选择 HTML 输出类型,在 Template type(模板类型) 处选择 Groovy template 并设置为默认:

    html groovy template

可以在通用报表列表视图 Reports(报表)→ *Run Reports(运行报表) 运行。