报表示例
XLS 报表
本示例基于 Library(图书馆) 应用程序,请按照 说明 设置应用程序并创建实体和界面。
在本示例中,我们将创建关于书籍作者的一个报表。给定一个作者,报表中列举他的所有书籍、每本书的出版商,以及该书本保存在图书馆的哪个部门,还有每个部门中保存了多少本。结果如下:
-
Figure 2. 报表数据结构
报表带区如下:
-
header 带区,报表头。包含带有 Groovy 脚本的数据集,该脚本输出报表 外部参数:
[['authorName' : (params['author'].firstName + ' ' + params['author'].lastName)]]
-
book 带区通过执行以下 SQL 查询输出书籍列表:
select b.name as book_name, b.id as book_id from JMXRPR_BOOK b join JMXRPR_AUTHORS_BOOKS ba on ba.book_id = b.id join JMXRPR_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 JMXRPR_BOOK_PUBLICATION bp join JMXRPR_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 JMXRPR_BOOK_INSTANCE bi join JMXRPR_BOOK_PUBLICATION bp on bp.id = bi.book_publication_id join JMXRPR_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_id
和publisher_id
。
-
-
报表 参数。
Parameters and Formats(参数和格式) 标签页声明了一个报表的外部参数 -
Author
:Figure 3. 报表参数运行报表时,用户必须输入此参数。书籍作者是通过应用程序中的
Author.browse
界面进行选择的。 -
报表 模板。
Templates(模板) 标签页包含一个 XLS 模板,从 BooksByAuthor.xls 加载。
Figure 4. 报表模板 -
报表名称 本地化。
Localization(本地化) 标签中包含报表名称的俄语翻译:
ru = Книги по автору
可以从 Reports(报表) → Run Reports(运行报表) 界面运行该报表。
交叉报表
本示例基于 Library(图书馆) 应用程序,请按照 说明 设置应用程序并创建实体和界面。
本示例中,我们将创建一个图书馆部门的交叉报表,列举图书馆每个部门每个月买多少本书。报表内容会向水平和垂直方向填充,并为每个部门计算每个月的数量:
创建交叉报表时,请在报表编辑界面的 报表结构 标签页上选择 Crosstab(双向) 带区方向。选择此方向将自动添加三个数据集:
-
<band_name>
_dynamic_header - 这个数据集的数据将向右复制,类似于包含表格列标题的垂直带区。 -
<band_name>
_master_data - 这个数据集的数据向下复制,类似于包含表格行标题的水平带区。 -
<band_name>
- 与其所属带区名称相同的数据集,是实现单元格矩阵的主内容带区。
例如,对于 Library 示例程序中 BookInstance
实体的交叉报表具有下列结构:
-
报表数据 结构。有三个数据集:
-
bi_dynamic_header
数据集将返回月份的名称: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,这些数据以 外部报表参数 的形式提供:bi_master_data 数据集select name as name, id as department_id from JMXRPR_LIBRARY_DEPARTMENT where id in (${selected_departments})
-
bi
数据集为矩阵单元格提供数据,数据内容为部门每月购进的书本总数。使用bi_master_data@department_id
(部门 ID)作为单元格的垂直坐标,使用bi_dynamic_header@header_id
(月份名称)作为单元格的水平坐标,并用amount
值填充对应的矩阵单元格。在下面的示例中,报表还有两个外部参数:
start_date
和end_date
用于定义书籍实例创建日期的范围。最好使用 交叉参数验证 来确保参数值在合理的范围。bi 数据集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 JMXRPR_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)
-
-
报表 参数。
Parameters and Formats(参数和格式) 标签页包含声明的 3 个报表外部参数 -
selected_departments
,start_date
,end_date
:Figure 7. 报表参数当运行报表时,用户需要输入这些参数。可以通过应用程序的
jmxrpr_LibraryDepartment.browse
界面选取部门。 -
报表 模板。
可以使用 Microsoft Office 或 LibreOffice 创建 XLS 报表模板。
模板示例:DepartmentBooks.xls,垂直方向上输出
Departments
,水平方向输出按月份统计的书籍数量。报表模板包含交叉带区的所有三个数据集对应的 命名区域 以及列标题的命名区域:
<band_name>_header
。在这个例子中,是bi_header
。
可以在通用报表浏览界面 Reports(报表)→ *Run Reports(运行报表) 运行。
JasperReports 报表
本示例基于 Library(图书馆) 应用程序,请按照 说明 设置应用程序并创建实体和界面。
本示例中,我们将创建一个 JRXML 报表展示某个部门内图书出版物的列表:
-
Figure 9. 报表数据结构
数据带区:
-
Header band - 报表头。包含 Groovy 脚本的数据集,该脚本输出报表 外部参数 值:
[['library_department_name' : params['library_department'].name]]
-
Data 带区通过运行以下 Groovy 脚本输出书籍实例的列表,外部输入参数为部门:
import reports.ex2.entity.LiteratureType def result = [] def ltList = dataManager.load(LiteratureType).all().list(); ltList.each(lt->{ def count = dataManager.loadValue("select sum(bi.bookCount) from jmxrpr_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 jmxrpr_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 类型,但可以直接将其与实体标识符字段进行比较,类型转换会自动完成。
-
-
报表 参数。
Parameters and Formats(参数和格式) 标签页包含一个声明的报表外部参数 -
Department
:Figure 10. 报表参数运行报表时,用户必须输入此参数。部门是通过应用程序中的
jmxrpr_LibraryDepartment.browse
界面选择的。 -
报表 模板。
新建 JRXML 文件或者下载 BookAvailability.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 可视化设计器中打开模板文件来查看报表布局。将新模板上传到应用程序,选择任何一种输出类型,并将其设置为默认值:
Figure 11. 报表模板
可以在通用报表浏览界面 Reports(报表)→ *Run Reports(运行报表) 运行。
HTML/PDF 报表(分页/页眉页脚)
本示例基于 Library(图书馆) 应用程序,请按照 说明 设置应用程序并创建实体和界面。
在本示例中,我们希望创建一个关于书籍简介的报表:使用横向展示,每页带有页码、页眉和页脚,并使用特殊的 CSS 规则和属性进行配置。输出格式是 HTML 导出为 PDF:
-
报表数据 结构
创建一个没有参数的简易报表。使用 JPQL 查询所有书籍实体的本地属性:
name
和summary
。Figure 13. 报表数据结构 -
报表 模板。
现在创建报表模板文件。在这里定义页眉和页脚块,页眉和页脚会在每页 PDF 都打印。此外,需要使用特殊的
page-break-before:always
CSS 属性,在每个书籍信息块之前生成分页符。如下所示,使用 FreeMarker 语法将数据插入到模板中。完整的 FreeMarker 请参阅: 文档。
<body> <h1>Books report</h1> <!-- Custom HTML header --> <div class="header"> Library book summaries </div> <!-- Custom HTML footer --> <div class="footer"> Address: William Road </div> <#assign books=Root.bands.Books /> <#list books as book> <div class="custom-page-start" style="page-break-before: always;"> <h2>Book</h2> <p>Name: ${book.fields.title}</p> <p>Summary: ${book.fields.summary}</p> </div> </#list> </body>
-
CSS 规则
将使用以下 CSS 代码来设置页眉页脚位置:
div.header { display: block; text-align: center; position: running(header); width: 100%; } div.footer { display: block; text-align: center; position: running(footer); width: 100%; }
下列 CSS 代码调整 PDF 页面展示,以及主要内容的边距以防止内容和页眉/页脚重叠:
body { font: 12pt Georgia, "Times New Roman", Times, serif; line-height: 1.3; padding-top: 50px; } @page { /* switch to landscape */ size: landscape; /* set page margins */ margin: 0.5cm; @top-center { content: element(header); } @bottom-center { content: element(footer); } @bottom-right { content: counter(page) " of "counter(pages); } } .custom-page-start { margin-top: 50px; }
最终,完整的 BookSummary.html 文件如下:
<!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"> <head> <title>Invoice</title> <style type="text/css"> body { font: 12pt Georgia, "Times New Roman", Times, serif; line-height: 1.3; padding-top: 50px; } div.header { display: block; text-align: center; position: running(header); width: 100%; } div.footer { display: block; text-align: center; position: running(footer); width: 100%; } @page { /* switch to landscape */ size: landscape; /* set page margins */ margin: 0.5cm; @top-center { content: element(header); } @bottom-center { content: element(footer); } @bottom-right { content: counter(page) " of "counter(pages); } } .custom-page-start { margin-top: 50px; } </style> </head> <body> <h1>Books report</h1> <!-- Custom HTML header --> <div class="header"> Library book summaries </div> <!-- Custom HTML footer --> <div class="footer"> Address: William Road </div> <#assign books=Root.bands.Books /> <#list books as book> <div class="custom-page-start" style="page-break-before: always;"> <h2>Book</h2> <p>Name: ${book.fields.title}</p> <p>Summary: ${book.fields.summary}</p> </div> </#list> </body> </html>
-
创建报表模板,这里我们选择 Freemarker 模板类型:
Figure 14. 模板编辑器可以在通用报表浏览界面 Reports(报表)→ *Run Reports(运行报表) 运行。
HTML 报表(Groovy 模板引擎)
本示例基于 Library(图书馆) 应用程序,请按照 说明 设置应用程序并创建实体和界面。
本示例创建一个展示某个城镇中图书出版物列表的报表。输出格式为 HTML:
-
使用 JPQL 数据集创建报表:
Figure 16. 报表数据结构BookPublications
区域用来输出图书出版物列表,使用如下 JPQL 查询语句:BookPublications 数据集select b.name as "book", p.name as "publisher" from jmxrpr_BookPublication bp left join bp.book b left join bp.publisher p where bp.town.id = ${town}
这个查询使用了外部的报表参数 -
town
。该参数是 Entity 类型;但是,在 JPQL 查询语句中可以直接用来跟实体标识符进行比较;后台会自动做转换。 -
报表 参数:
在 Parameters and Formats(参数和格式) 标签页声明了一个报表外部参数 -
Town
:Figure 17. 报表参数当运行报表时,用户必须输入该参数。城镇的选择会通过
jmxrpr_Town.browse
界面进行。 -
报表 模板
新建一个 HTML 文件包含下列内容,或者下载 PublicationByTown.html 模板:
PublicationsTemplate<?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 town </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.town.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.town.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 并设置为默认:
Figure 18. Report 模板编辑器
可以在通用报表浏览界面 Reports(报表)→ *Run Reports(运行报表) 运行。