Pentaho Report Designer

Pentaho Report Designer

 

https://blog.csdn.net/qq_41944754/article/details/81222180

Pentaho 报表使用指南
FOROSS
wushexu@163.com
2013/10
目录
1  概述 ............................................................................................................................... 5
1.1  Pentaho .............................................................................................................................. 5
1.2  Pentaho Reporting ............................................................................................................. 5
1.3  示例数据库 ....................................................................................................................... 5
1.4  一些资源 ........................................................................................................................... 6
2  设计报表 ........................................................................................................................ 7
2.1  简单例子 ........................................................................................................................... 7
2.1.1  设置数据源 ................................................................................................................ 7
2.1.2  设置报表内容 ............................................................................................................ 8
2.2  报表结构 ........................................................................................................................... 9
2.3  文件格式 ......................................................................................................................... 10
2.3.1  文件格式 .................................................................................................................. 10
2.3.2  Schema ..................................................................................................................... 11
2.4  数据源 ............................................................................................................................. 12
2.4.1  JDBC .......................................................................................................................... 12
2.4.2  Metadata .................................................................................................................. 13
2.4.3  Pentaho Data Integration ......................................................................................... 14
2.4.4  OLAP ......................................................................................................................... 15
2.4.5  OLAP(Advanced) ....................................................................................................... 17
2.4.6  XML ........................................................................................................................... 18
2.4.7  Table ......................................................................................................................... 19
2.4.8  Advanced .................................................................................................................. 19
2.4.9  Community Data Access ........................................................................................... 21
2.5  表达式、函数 ................................................................................................................. 21
2.6  参数化报表 ..................................................................................................................... 23
2.7  子报表 ............................................................................................................................. 24
2.8  分组报表 ......................................................................................................................... 26
2.9  图表 ................................................................................................................................. 28
2.10  国际化( i18n ) ........................................................................................................... 30
2.10.1  报表设置 .................................................................................................................. 30
2.10.2  资源加载 .................................................................................................................. 31
2.11  交叉报表 ...................................................................................................................... 31
2.11.1  Sql 查询 .................................................................................................................... 32
2.11.2  报表设置 .................................................................................................................. 32
2.11.3  MDX 数据源 ............................................................................................................. 34
3  报表引擎 ...................................................................................................................... 36
3.1  libraries ............................................................................................................................ 36
3.2  报表模型 ......................................................................................................................... 36
3.2.1  接口 .......................................................................................................................... 36
3.2.2  类层次 ...................................................................................................................... 37
3.3  数据层 ............................................................................................................................. 39
3.3.1  TableModel .............................................................................................................. 39
3.3.2  DataFactory .............................................................................................................. 39
3.3.3  核心的 DataFactory 实现 ........................................................................................ 40
3.3.4  数据源扩展 .............................................................................................................. 41
3.3.5  DataRow 接口 .......................................................................................................... 42
4  嵌入应用 ...................................................................................................................... 43
4.1  引擎初始化 ..................................................................................................................... 43
4.2  加载报表 ......................................................................................................................... 43
4.3  读取参数定义 ................................................................................................................. 43
4.4  注入参数 ......................................................................................................................... 44
4.5  报表输出 ......................................................................................................................... 44
4.5.1  html .......................................................................................................................... 45
4.5.2  PDF ........................................................................................................................... 45
4.5.3  excel ......................................................................................................................... 46
4.6  编程方式创建报表 ......................................................................................................... 46
4.6.1  创建元素 .................................................................................................................. 46
4.6.2  预处理器 .................................................................................................................. 48
5  扩展报表 ...................................................................................................................... 49
5.1  表达式和函数 ................................................................................................................. 49
5.1.1  LibFormula ................................................................................................................ 49
5.1.2  报表表达式 .............................................................................................................. 49
5.1.3  报表函数 .................................................................................................................. 50
5.1.4  报表监听器 .............................................................................................................. 50
5.2  实现表达式 ..................................................................................................................... 50
5.2.1  定义表达式类 .......................................................................................................... 50
5.2.2  定义元数据 .............................................................................................................. 51
5.2.3  使用及效果 .............................................................................................................. 53
5.3  实现函数 ......................................................................................................................... 55
5.3.1  定义函数类 .............................................................................................................. 55
5.3.2  定义函数描述类 ...................................................................................................... 56
5.3.3  资源文件 .................................................................................................................. 57
5.3.4  注册函数 .................................................................................................................. 57
5.3.5  使用及效果 .............................................................................................................. 57
5.4  使用脚本语言 ................................................................................................................. 59
5.4.1  BSH ........................................................................................................................... 60
5.4.2  JavaScript .................................................................................................................. 60
5.5  实现报表元素 ................................................................................................................. 61
5.5.1  定义元素类型类 ...................................................................................................... 61
5.5.2  定义元素元数据 ...................................................................................................... 63
5.5.3  定义模块类 .............................................................................................................. 64
5.5.4  定义读写处理器 ...................................................................................................... 64
5.5.5  使用及效果 .............................................................................................................. 65
1  概述
1.1  P ENTAHO
Pentaho 是 Java 平台上著名的商业智能(BI)项目。它包含多个产品以及产品插件、辅助工
具,包括 BI 平台(BI Platform)、ETL、报表、联机分析、数据挖掘等。
Pentaho 有的产品分企业版(EE)和社区版(CE),主要的产品都有社区版,社区版的代码和企业
版是一样的。社区版已能提供完整的 BI 解决方案。
Pentaho 的 BI 平台,是一个 Java Web 应用(BI Server),通过插件方式扩展功能。它以流程
为中心,面向解决方案,增加一个需求就是增加一批(xml)配置文件,不需要写代码。
Pentaho 社区版官网:http://community.pentaho.com
1.2  P ENTAHO  R EPORTING
Pentaho Reporting 是 Pentaho 的报表解决方案。它原先是开源项目 JFreeReport,后来容纳
进 Pentaho。Pentaho Reporting 采用的开源协议是 LGPL。
Pentaho 报表有两种使用方式,一种是基于 BI Server(不需要写代码),一种是嵌入应用方
式(传统 JFreeReport 的方式)。
报表主要通过报表设计器(Pentaho Report Designer, PRD)来定义。定义好的报表保存为后
缀为 prpt 的文件。
本文档讲述报表的结构、定义方式,报表引擎的报表模型、数据层,嵌入式报表引擎的使用
方式等。
Pentaho 报表可以使用多维分析(MDX 查询)作为数据源,关于 MDX 查询、多维分析方面
的内容,请参考文档《Pentaho 多维分析使用指南》。
1.3  示例数据库
PRD 本身带了一个示例数据库,在 resources/sampledata 目录下,是一个 HSQL 数据库(内
存数据库)。这个数据库可作为 Pentaho 报表的示例数据库,也可作为 Pentaho Analysis(多
维分析)的示例数据库。
这个数据库或叫 SteelWheels,是一个销售汽车模型的公司的销售数据,包括雇员表、客户
表、客户地区表、产品表、销售表等等。产品有产品线和供应商属性。订单有日期以及年份、
季度属性。本文档演示的例子只使用产品表(PRODUCTS)、销售表(ORDERFACT)。
1.4  一些资源
官网  http://reporting.pentaho.com
文档  http://wiki.pentaho.com/display/Reporting
代码  https://github.com/pentaho/pentaho-reporting
API  http://javadoc.pentaho.com/reporting/
JIRA  http://jira.pentaho.com/browse/PRD
图书  Pentaho Solutions: Business Intelligence and Data Warehousing with Pentaho and MySQL
图书  Pentaho Reporting 3.5 for Java Developers
2  设计 报表
报 表 设 计 器 ( Pentaho Report Designer, PRD ) 是 一 个 Java 桌 面 程 序 。 从
http://reporting.pentaho.com/下载(在Report Creation Tools标题下)。Pentaho Report Designer
下载包已包含所有报表相关的库。下载后解压即可使用(假设预先设置了 JAVA_HOME 环境
变量)。
从 report-designer.bat(或 report-designer.sh)启动 PRD。第一次启动会显示欢迎页,右边有
若干样例,可供参考。欢迎页也可从 Help 菜单打开(Welcome)。也可从欢迎页进入新报
表向导(Report Wizard)开始体验(或从 File 菜单进入)。
新建一个报表后,可看到如下界面:
最左边是一列报表元素(可拖入报表),主区域是报表设计区域,右边是 Structure(显示报
表结构)、Data 信息,右下是 Style(元素样式)、Attributes 设置区域。
2.1  简单例子
这个例子使用示例数据库 SampleData,查询各产品线各年的销售额。
2.1.1 设置数据源
打开右边 Data 标签页,右键点击 Data Sets 可看到可选择的各种数据源类型。
这里选 JDBC,就可打开数据源、查询设置界面。
左边列出已定义的数据源,选择第一个 SampleData 即可。PRD 会预先加载 SampleData 数据
库,可通过 JNDI、 JDBC 或内存数据库方式使用。
右边是查询设置区域。查询关联到某个数据源。
这里创建一个查询 total_by_line_year:
SELECT
SUM("ORDERFACT"."QUANTITYORDERED") AS QUANTITYORDERED,
SUM("ORDERFACT"."TOTALPRICE") AS TOTALPRICE,
"PRODUCTS"."PRODUCTLINE",
"ORDERFACT"."YEAR_ID"
FROM
"ORDERFACT"  INNER  JOIN  "PRODUCTS"  ON  "ORDERFACT"."PRODUCTCODE"  =
"PRODUCTS"."PRODUCTCODE"
GROUP BY "PRODUCTS"."PRODUCTLINE","ORDERFACT"."YEAR_ID"
ORDER BY "PRODUCTS"."PRODUCTLINE","ORDERFACT"."YEAR_ID"
定义完后,在 Data Sets 下即可看到数据源和数据源下面的查询。查询可展开列出所有字段。
2.1.2 设置报表内容
先设置报表标题。从左边的报表元素栏把 Label 拖到 Report Header,双击 Label 输入标题。
再设置列表表头。同样是使用 Label 元素。
设置报表数据元素。可把从右边查询下的字段直接拖到 Details 中来,调整位置,和表头对
齐。
设置后如下图:
点击左上角的预览图标(眼睛状),可看到如下效果:
2.2  报表结构
从设计区以及 Structure 树状图中可看出报表的结构,一般可分为这些部分:Page Header、
Report Header、Group Header、Detail Header、Detail/No Data、Detail Footer、Group Footer、
Report Footer、Page Footer、Watermark。
以下是一个典型的报表的结构图:
Group 用来设置分组报表(在内存中对数据分组),每个报表都有一个 Group,即使没有定
义。Detail 是根据数据行重复的部分,如果没有数据,会显示 No Data。Watermark 可用来
定义背景。
如果某个组件需要设置却没有在左边显示,可以设置它的属性 hide-on-canvas 为 false,就可
以显示出来。
2.3  文件格式
报表文件.prpt是一个.zip压缩文件,内部使用 xml 文件,基本遵循 ODF规范(Open Document
Format)。
2.3.1 文件格式
.prpt 文件解压缩后结构如下:
 layout.xml
描述整个报表的布局,以及所有的报表元素。
 styles.xml
样式定义文件。
 settings.xml
配置、运行时参数文件,可从 PRD 的 File 菜单 Configuration.. 配置。
 datadefinition.xml
数据定义文件,包括参数、数据源、函数。数据源会引用 da tasources 下的文件。
 datasources/
此目录存放数据源及查询设置文件。
2.3.2 S CHEMA
所有的 xml 文件都有相应的 schema(xsd)文件,可从 http://jfreereport.sourceforge.net/ 下
载。
目前核心模式文件有:
config-description.xsd  content.xsd  core-types.xsd datadefinition.xsd
dataschema.xsd  layout.xsd  settings.xsd  styles.xsd
模式中数据源部分是一个复杂类型
compounddatafactory.xsd
kettle-datasource.xsd
pmd-datasource.xsd
此外,为保持后向兼容,还支持遗留的模式
2.4  数据源
这里介绍在 PRD 中可定义的数据源类型
报表引擎一章),很容易增加新的实现
表示报表引擎不支持。
这次数据源的实现一般位于报表引擎的扩展包中
界面位于 PRD 的扩展包中(
关于报表引擎的数据源接口和实现
在 PRD 中可选择的数据源类型如下
2.4.1 JDBC
Jdbc 是最常用的数据源类型
的数据源,可以修改,也可以新增数据源
模式中数据源部分是一个复杂类型,可以扩展。以下是预定义的数据源模式
compounddatafactory.xsd  hibernate-datasource.xsd  inlinedatasource.xsd
mondrian-datasource.xsd  olap4j-datasource.xsd
sqldatasource.xsd  staticdatasource.xsd
还支持遗留的模式(在遵循 ODF 规范之前的)。
中可定义的数据源类型。由于 Pentaho Reporting 的数据层接口很
很容易增加新的实现,或扩展已有的实现,因此在 PRD
这次数据源的实现一般位于报表引擎的扩展包中(engine/extensions-*),在
(designer/ datasource-editor-*)。
关于报表引擎的数据源接口和实现,见“报表引擎”一章“数据层”一节。
中可选择的数据源类型如下(点 Data 菜单或在 Data Sets 上点右键):
是最常用的数据源类型。数据源设置界面(见“简单例子”一节)的左边列出了已定义
也可以新增数据源。新建/修改数据源的界面如下:
模式:
inlinedatasource.xsd
datasource.xsd
staticdatasource.xsd
的数据层接口很简单(见
PRD 中不能定义并不
在 PRD 中的定义

):
的左边列出了已定义
这里的 Jdbc 设置包含三种方式获得数据源
接设置 Jdbc 驱动类、主机、数据库名等的方式创建
驱动来连接已有的 ODBC 数据源
2.4.2 M ETADATA
Pentaho Metadata 允许数据库管理员为终端用户定义一个基于
户要面对数据库模式的复杂性
(Common Warehouse Metamodel
Language(MQL) 是一个基于
设置界面如下:
设置包含三种方式获得数据源,JDBC(Native)、ODBC 和 JNDI。JDBC(Native)
数据库名等的方式创建 Jdbc 数据源,ODBC 通过 JDBC
数据源,JNDI 通过名字查找已有的 JDBC 数据源。
允许数据库管理员为终端用户定义一个基于关系数据的业务层
户要面对数据库模式的复杂性。Pentaho Metadata 使用的基于 XML 的文件来描述
Common Warehouse Metamodel)标准,后缀为.XMI。 Pentaho 的
是一个基于 XML 的查询模型,简化了查询数据库的工作。
JDBC(Native)是直
JDBC-ODBC Bridge

关系数据的业务层,避免了用
的文件来描述,遵循 CWM
的 Metadata Query
Metadata (Custom)只是定义一个 Metadata 数据源,没有定义查询。
2.4.3 P ENTAHO  D ATA  I NTEGRATION
Pentaho Data Integration 即 Kettle,是 Pentaho 的 ETL 解决方案。此数据源类型允许从 ETL
过程读取数据。设置界面如下:
需要选择一个 Kettle 文件(
运行期时依赖于 Kettle,需要把
2.4.4 OLAP
OLAP 数据源允许从一个多维分析引擎后端查询数据
2.4.4.1 OLAP4J 、P ENTAHO  A
olap4j 是连接多维分析引擎、
驱动。olap4j 也包含一个 XMLA
Pentaho Analysis,即 Mondrian
而不是使用 olap4j 的 API。
OLAP4J、Pentaho Analysis 类型
的 MDX 查询结果。它会把 columns
最后得到的 TableModel,根据数据内容
直接用于展示。这跟 Denormalized
例如定义以下 MDX 查询:
.ktr),选择一个转换步骤。
需要把 Kettle 的相关库加入到运行期的类路径中。
数据源允许从一个多维分析引擎后端查询数据,使用 MDX 语句来查询
A NALYSIS
、执行多维分析查询的一套 Java 标准 API。Mondrian
XMLA 的客户端实现,因此也可以连接任何 XMLA
Mondrian,是 Pentaho 的多维分析引擎。这里表示直接连接
类型(包括 Denormalized 类型)的数据源,可以处理任意轴数量
columns 轴映射到 TableModel 的列上,其他轴映射到行上
根据数据内容,会增加相应的列,因此可以跟 SQL
Denormalized 类型的不一样。

来查询。
Mondrian 实现了 olap4j
XMLA 服务器。
这里表示直接连接 Mondrian,
可以处理任意轴数量
其他轴映射到行上。
SQL 查询结果一样,
SELECT
[Product].[Line].Members on rows,
{[Year].Members} on columns
FROM [orders]
WHERE [Measures].[Sales]
预览查询,结果如下:
可以看到,2003、2004、2005 出现在了列上。列数多少跟有多少个年份有关。
查询得到的字段如下:
如果已知年份是这些,可以这样定义数据源,在表头增加这些年份的列即可。否则,要使用
Denormalized 的 OLAP 数据源,并定义交叉报表。
2.4.4.2 (D ENORMALIZED )
OLAP4J(Denormalized)、 Pentaho Analysis (Denormalized)两种类型和 OLAP4J、Pentaho Analysis
不太一样。Denormalized 是“反规格化”的意思,它并不把数据转换成列头,列头跟维度对
应。实际上比起非 Denormalized 的版本,它需要做更少的处理。
例如,前面的查询会得到结果:
可以看到,没有把 2003、2004、2005 转换成列头,只有 year 列。
得到字段如下:
分组报表或交叉报表可以按 year 字段来分组。
2.4.4.3 (L EGACY )
OLAP4J(Legacy)、Pentaho Analysis(Legacy)两种类型是遗留实现,它只能适用于不超过两个轴
的 MDX 查询结果。TableModel 实现内部,只是简单地将 MDX 结果集的 columns 轴和 rows
轴映射为 TableModel 的列和行,获取某行某列的数据时,直接从结果集读取。
2.4.5 OLAP(A DVANCED )
OLAP(Advanced)跟 OLAP 的数据源实现是一样的
源下并不定义查询,查询语句直接定义在元素的
询。Custom 是指查询是可以定制的
2.4.6 XML
XML 数据源允许从一个 XML
以下是设置界面:
需要指定一个 xml 文件,然后定义查询
这里 result_set.xml 文件的内容如下
<?xml version="1.0" encoding="
<ResultSet>
<Row>
的数据源实现是一样的,只是用 OLAP(Advanced)的方式定义
查询语句直接定义在元素的 query 属性上,或者通过编程的方式设置查
是指查询是可以定制的。
XML 文件中查询数据,使用 XPath。
然后定义查询,查询内容是 XPath 表达式。
文件的内容如下:
encoding="UTF-8"?>
的方式定义,数据
或者通过编程的方式设置查
<NAME>LibBase</NAME>
<DESCRIPTION>Base library containing common functions</DESCRIPTION>
<SIZE>113210</SIZE>
</Row>
<Row>
<NAME>LibLoader</NAME>
<DESCRIPTION>Loading and caching library</DESCRIPTION>
<SIZE>53552</SIZE>
</Row>
</ResultSet>
/*/Row 表示查询第二级的 Row 元素,作为数据行,Row 的子元素名就是列名,子元素的文
本值就是列的值。
2.4.7 T ABLE
Table 类型数据源用来定义一个静态的二维表,表的数据都是预定义的。一个查询是一个二
维表,列可以根据需要增、删、改名,如下图:
2.4.8 A DVANCED
Advanced 包含其他一些数据源。
其中 JDBC (Custom)跟前面类似
的 query 属性上,或通过编程方式设置
2.4.8.1 S CRIPTABLE
Scriptable 数据源允许从一段脚本代码返回数据
javax.swing.TableModel 类型
以下是设置界面,以及 groovy
2.4.8.2 J AVA  M ETHOD  I NVOCATION
Java Method Invocation 数据源类型允许通过反射的方式
数据。可以指定类的构造函数和方法的参数
设置界面如下:
跟前面类似,它同样是使用 JDBC 数据源,只是查询是定制的
或通过编程方式设置。
数据源允许从一段脚本代码返回数据。脚本语言有多个选择,脚本代码要返回
类型。
groovy 脚本例子:
NVOCATION
数据源类型允许通过反射的方式,从一个 Java 类调用一个方法得到
可以指定类的构造函数和方法的参数。
只是查询是定制的,写在元素
脚本代码要返回
类调用一个方法得到
2.4.9 C OMMUNITY  D ATA  A CCESS
Community Data Access 数据源类型允许从 Pentaho BI Server 获取查询定义。需要设置 BI
Server 的服务器 URL,登录的用户名、密码,Solution 名,路径,查询名等。
2.5  表达式、函数
元素的数据可以设置为一个字段(Field 属性),或一个表达式(Value 属性)。
例如要把金额转换为万元,则可以把 Value 属性设置为”=[TOTALPRICE]/10000.0”。在表达式
里用方括号引用变量、参数或函数。
要使用预定义函数,需要先加入到报表中。在Data页里functions上右键点击Add function…,
加入需要的函数。
下面是选择函数的窗口,可以看到有这些分类:
有的函数需要参数,需在函数属性里设置参数。所有函数都有两个属性:名字和依赖级别。
名字(Name),用于在表达式、公式或其他函数中引用它。依赖级别(Dependency Level),
用于确定执行的顺序。
要在报表的页脚显示页码就需要使用函数,选择 Common 下的 Page of Pages 函数,再把它
到 Page Footer,即可显示页码、总页数。
以下示例在 Report Footer 加入了总数、总金额、平均金额。用了 Count、Sum 两个聚集函数。
平均金额则是设置表达式”=[TotalGroupSumFunction0] / [TotalItemCountFunction1]”
结果如下:
关于表达式、函数更多的内容,请参考“扩展报表一章”。
2.6  参数化报表
通常报表都需要参数化,比如需要传入日期参数。
可从 Data 页里 Parameters 增加报表参数。比如这里要给报表增加一个年份参数 year,按如
下设置:
years 是一个预先定义的查询,用来列出可选的年份:
select distinct YEAR_ID from ORDERFACT
Display Type 指定候选列表的展现方式,创建参数录入界面时可依照此。
定义好参数以后,可在查询中引用参数,使用${year}的形式:
SELECT
SUM("ORDERFACT"."QUANTITYORDERED") AS QUANTITYORDERED,
SUM("ORDERFACT"."TOTALPRICE") AS TOTALPRICE,
"PRODUCTS"."PRODUCTLINE"
FROM
"ORDERFACT"  INNER  JOIN  "PRODUCTS"  ON  "ORDERFACT"."PRODUCTCODE"  =
"PRODUCTS"."PRODUCTCODE"
WHERE "ORDERFACT"."YEAR_ID" = ${year}
GROUP BY "PRODUCTS"."PRODUCTLINE"
预览报表,效果如下:
2.7  子报表
Pentaho 报表支持子报表,子报表几乎包含所有主报表的属性和子元素。子报表也可以带参
数,也有查询属性,用来设置数据。主报表定义的查询子报表都可以看到。
增加一个子报表通过拖入一个子报表元素。子报表在主报表中的放置有两种方式,Inline 和
banded,inline 会在行内显示,banded 会占据一整栏(类似 css 里 display: block)。
以下是一个子报表的示例,主报表查出产品线,子报表查询产品线下的产品。定义界面见下
图:
子报表需要定义报表参数,并映射到主报表参数或运行时变量。
在 Parameters 上右键 Edit sub-report parameters...增加子报表参数参数,定义后如下图所示:
结果如下:
2.8  分组报表
当需要对数据进行分组显示时,就需要分组报表。数据是一次查询的,但是在内存内分组。
这里演示按产品线分组的销售报表。先创建查询 total_by_prod:
SELECT
SUM("ORDERFACT"."QUANTITYORDERED") AS QUANTITYORDERED,
SUM("ORDERFACT"."TOTALPRICE") AS TOTALPRICE,
"ORDERFACT"."PRODUCTCODE",
"PRODUCTS"."PRODUCTNAME",
"PRODUCTS"."PRODUCTLINE"
FROM
"ORDERFACT"  INNER  JOIN  "PRODUCTS"  ON  "ORDERFACT"."PRODUCTCODE"  =
"PRODUCTS"."PRODUCTCODE"
WHERE "ORDERFACT"."YEAR_ID" = ${year}
GROUP  BY  "PRODUCTS"."PRODUCTLINE","ORDERFACT"."PRODUCTCODE",
"PRODUCTS"."PRODUCTNAME"
ORDER  BY  "PRODUCTS"."PRODUCTLINE","ORDERFACT"."PRODUCTCODE",
"PRODUCTS"."PRODUCTNAME"
注意排序是必须的,报表引擎会假设数据是排好序的。
然后创建分组,在报表结构的根节点 Master Report 右键 add group。需要指定分组的字段(一
个或多个),这是分组的最重要属性。其他的设置一样。效果如下:
下面试两级分组的例子,先按产品线分组再按供应商分组。查询如下:
SELECT
SUM("ORDERFACT"."QUANTITYORDERED") AS QUANTITYORDERED,
SUM("ORDERFACT"."TOTALPRICE") AS TOTALPRICE,
"ORDERFACT"."PRODUCTCODE",
"PRODUCTS"."PRODUCTNAME",
"PRODUCTS"."PRODUCTLINE",
"PRODUCTS"."PRODUCTVENDOR"
FROM
"ORDERFACT"  INNER  JOIN  "PRODUCTS"  ON  "ORDERFACT"."PRODUCTCODE"  =
"PRODUCTS"."PRODUCTCODE"
WHERE "ORDERFACT"."YEAR_ID" = ${year}
GROUP  BY  "PRODUCTS"."PRODUCTLINE","PRODUCTS"."PRODUCTVENDOR",
"ORDERFACT"."PRODUCTCODE", "PRODUCTS"."PRODUCTNAME"
ORDER  BY  "PRODUCTS"."PRODUCTLINE","PRODUCTS"."PRODUCTVENDOR",
"ORDERFACT"."PRODUCTCODE", "PRODUCTS"."PRODUCTNAME"
效果如下:
2.9  图表
Pentaho Reporting 采用了开源图表工具 JfreeChart 来实现图表功能。
拖入一个 chart 元素即可增加一个图表,双击图表元素即弹出设置界面,支持多种图标类型。
 折线图
以下是一个折线图的示例。设置界面如下:
左边是与展示相关的属性,右边是数据源设置。数据源设置的属性含义如下:
category-column:用于确定分类(X 轴)的数据源列名
value-column:用于确定数值(Y 轴)的数据源列名
series-by-value:如果设置,值会作为序列(即折线)名称 If set, values entered act as the series name for the value columns provided.
series-by-field:如果设置,数据源列会作为序列名称,设置此属性会把数值列切分为序列组
If set, fields entered act as the series name for the value column provided. Setting this property will slice the value column into series groups.
运行效果:
 饼图
以下是一个饼图的示例。
效果如下:
2.10 国际化( I 18 N )
多语言支持采用的是 Java 标准的做法:bundle 和 properties 文件。
2.10.1 报表设置
properties 文件可以存放于.prpt 内部,也可以存放于外部(Classpath 中)。可以从 File 菜单
的 Resources .. 创建、编辑 properties,这样 properties 会存放于.prpt 内部。
编辑非 ascii 字符的 properties 文件,需要自己处理 native2ascii。
显示多语言的文本,使用 resource-label 元素。
属性 value 设置为 properties 文件的 key。
属性resource-indentifier指示properties文件。如果properties文件为translations.properties,
resource-indentifier 属性可不用设置,否则要设置成 properties 文件名。属性 name 指示 Locale
名称。如下图:
2.10.2 资源加载
Pentaho Reporting 定 义 了 ResourceBundleFactory 接 口 来 加 载 语 言 资 源 文 件 。
ResourceBundleFactory 定义了以下两个方法:
public ResourceBundle getResourceBundle(String key);
public Locale getLocale();
一个报表默认配置为使用 ResourceBundleFactory 的实现类 DefaultResourceBundleFactory,它
使用了 Java 的 ResourceBundle 实现。DefaultResourceBundleFactory 包含了 setLocale 方法。
ResourceBundleFactory 的另一个实现类 LibLoaderResourceBundleFactory(位于 util 包),它
使 用 了 LibLoader 的 方 式 来 加 载 。 LibLoader 是 一 个 可 扩 展 的 资 源 加 载 框 架 。
LibLoaderResourceBundleFactory 也包含了 setLocale 方法。
DefaultResourceBundleFactory 和 LibLoaderResourceBundleFactory 都包含了 setLocale 方法。
如果要设置 Locale,通过 ReportEnvironment 接口的实现类 DefaultReportEnvironment 是不错
的选择,DefaultReportEnvironment 包含定义了 setLocale 方法。
2.11 交叉报表
交叉报表,或叫多维报表,是很重要的报表类型。见下图:
年份放在了列表头上,但 2003、2004 并不是数据库表的一个字段名,而是数据。这样的报
表有多少列预先是不知道的,须查出数据后才能知道。这样的报表需要报表引擎、报表设计
器的支持。
交叉报表实际也是分组报表,同样是把数据在内存中分组。
2.11.1 S QL 查询
交叉报表可以使用任何数据源。上面的图是个产品线在各年的销售额,sql 查询如下:
SELECT
PRODUCTCODE, YEAR_ID, SUM(TOTALPRICE) AS TOTALPRICE
FROM ORDERFACT
GROUP BY PRODUCTCODE,YEAR_ID
ORDER BY PRODUCTCODE,YEAR_ID
和分组报表一样,排序同样是必须的。
下面的例子增加一个“季度”的维度,sql 查询如下:
SELECT
PRODUCTCODE, YEAR_ID, QTR_ID, SUM(TOTALPRICE) AS TOTALPRICE
FROM ORDERFACT
WHERE YEAR_ID < 2005
GROUP BY PRODUCTCODE,YEAR_ID,QTR_ID
ORDER BY PRODUCTCODE,YEAR_ID,QTR_ID
效果如下:
2.11.2 报表设置
交叉报表在 PRD 中是一项体验功能,需要自己启用。打开 Edit 菜单的 Preferences...,把 Other
settings 下的 Enable (unsupported) experimental features 勾选即可。
这时在报表元素树的根节点 Master Report 上打开右键,可看到 Add Crosstab Group(非禁用
的)。
Crosstab Group 分为 Crosstab Row Group 和 Crosstab Column Group,Row Group 表示行头,
Column Group 表示列头,Column Group 嵌套在最内层(总是会有)。
Row Group 和 Column Group 都有一个最重要的属性,group,指示按哪个字段分组。
创建 Crosstab Group 后,左边报表结构会出现 crosstab 这一栏。在 crosstab 里是不能够拖拽
元素的,可以在树状图的相应容器下点右键 Add Element 来加入元素, 元素属性在下边属
性页编辑。如下图:
正如前面“数据源”一节所述,如果数据源采用的非 Denormalized 的 MDX 数据源,并且已
知道要分组的数据维度有多少列(即所有的取值),则不需要定义成交叉报表,甚至不需要
定义成分组报表。不过这样报表定义里列头就写死了。
2.11.3 MDX 数据源
MDX 是多维查询分析语言,比较适合作为交叉报表的数据源。使用 MDX 查询,需要使用
OLAP 引擎 Pentaho Analysis(Mondrian),不过 PRD 的 lib 目录已经包含相关库了。
使用 mdx 查询,需要一个 Schema 文件,这是一个 xml 文件,定义了数据立方体、维度、度
量等信息(提供给 Mondrian)。简单的 Schema 示例如下:
<Schema name="of">
<Cube name="orders">
<Table name="ORDERFACT"/>
<Dimension name="Product">
<Hierarchy hasAll="true">
<Level name="product" column="PRODUCTCODE"/>
</Hierarchy>
</Dimension>
<Dimension name="Time">
<Hierarchy hasAll="true">
<Level name="year" column="YEAR_ID"/>
</Hierarchy>
</Dimension>
<Measure name="Sales" column="TOTALPRICE" aggregator="sum"/>
</Cube>
</Schema>
Mondrian 数据源有非 Denormalized(Banded)、Denormalized(以及 Legacy)类型,前面数
据源部分已介绍。这里数据源类型选择 Pentaho Analysis(Denormalized),设置界面如下:
与 JDBC 数据源相比多了 Schema File 文件的设置,写 sql 的地方变成了写 mdx。
报表展现和 sql 数据源的差不多。
以下查询增加了“季度”的维度,mdx 如下:
SELECT
[Product].Members on pages,
{[Year].[2003],[Year].[2004]} on rows,
[Quarter].Members on columns
FROM [orders]
WHERE [Measures].[Sales]
结果跟前面“Sql 查询”的结果一样。
3  报表 引擎
Pentaho Reporting 包含几大部分:
  基础库(libraries)
  报表引擎核心(engine core)
其依赖于基础库。代码是 org.pentaho.reporting.engine.classic.core.**
  报表扩展(extentions),包括各种数据源适配器,脚本支持等
  报表设计器(designer)
3.1  LIBRARIES
基础库有十几个,基本都是名为 lib*,看名字就可知道用途。主要的库如下:
libbase 
libcss 
libdocbundle  zip 包
libfonts 
libformat  文本格式化
libformula-ui  公式可视化编辑
libformula  公式库,实现了 OpenFormula
libloader  资源加载与缓存
librepository  层次化存储
libserializer 
libswing  设计器支持
libxml 
3.2  报表模型
.prpt 文件只是一个报表的定义,要展现此报表,需要把它解析成报表对象。一个报表用一
个 MasterReport 对象表示,解析.prpt 的过程就是构造 MasterReport 对象的过程。
MasterReport 对象包含很多属性,包括子元素对象,数据源,参数定义等等。
这 里 介 绍 与 报 表 元 素 相 关 的 类 , 涉 及 的 类 和 接 口 都 位 于
org.pentaho.reporting.engine.classic.core 包。
3.2.1 接口
相关的接口就下面三个:
  ReportElement (extends Cloneable, Serializable)
  ReportDefinition
  RootLevelBand
3.2.1.1 R EPORT E LEMENT
用来布局的构件。持有样式和属性,并允许建立对克隆对象的引用,如果通过 ID 对象来克
隆的话。
3.2.1.2 R EPORT D EFINITION
表示一个报表(包括子报表)。定义了获取报表 ReportHeader 、ReportFooter、PageHeader、
PageFooter、DetailsHeader、DetailsFooter、ItemBand、NoDataBand、PageDefinition、Watermark、
组(按序号)、顶级组、查询名等方法(get*方法)。
3.2.1.3 R OOT L EVEL B AND 
RootLevelBand 是直接连接到一个报表定义或一个组的元素。用于内容创建时的入口点。
3.2.2 类层次
类数量不是很多,都是容器元素,因为很多元素(内容元素)都没有对应的类,如 text-field、
number-field、label、message 等,它们由 ElementFactory(的子类)创建 Element 类的实例。
3.2.2.1  层次图
  Element (implements filter.DataTarget, ReportElement)
  Section
  Band
  AbstractRootLevelBand (implements RootLevelBand)
  GroupFooter
  GroupHeader
  ItemBand
  NoDataBand
  ReportFooter
  ReportHeader
  CrosstabSummaryFooter (implements RootLevelBand)
  CrosstabSummaryHeader (implements RootLevelBand)
  CrosstabTitleFooter (implements RootLevelBand)
  CrosstabTitleHeader (implements RootLevelBand)
  DetailsFooter (implements RootLevelBand)
  DetailsHeader (implements RootLevelBand)
  PageFooter (implements RootLevelBand)
  PageHeader (implements RootLevelBand)
  Watermark (implements RootLevelBand)
  Group
  CrosstabColumnGroup
  CrosstabGroup
  CrosstabOtherGroup
  CrosstabRowGroup
  RelationalGroup
  GroupBody
  CrosstabColumnGroupBody
  CrosstabOtherGroupBody
  CrosstabRowGroupBody
  GroupDataBody
  SubGroupBody
  AbstractReportDefinition (implements ReportDefinition)
  MasterReport
  SubReport
有相当一部分是*Header、*Footer 类。下面介绍最重要的几个。
3.2.2.2 E LEMENT 
Element 所有报表元素的基类。
如果是内容元素,当调用方法 getValue(function.ExpressionRuntime)时产生可打印的值。
所有元素都有一个非空的名称,并有一个私有样式表。
元素可以从它的父元素继承所有的样式。每当元素的样式表没有定义相应键的自己的值时样
式值就会继承。有些样式键是不能被继承的,这是会使用缺省样式表。
全局样式表总是会在父样式表之前被查询。增加样式表的顺序是重要的,后增加的样式表会
比先增加的优先。
报表元素不能在不用报表实例间共享,加入元素到一个 band 会从另一个原来所属的 band
删除。
3.2.2.3 S ECTION
一个 section 允许访问子元素,没有定义怎样增加或组织子元素。定义合理的顺序留给子类实现。
3.2.2.4 B AND
一个 band 是其他元素或 band 的集合,类似一个 AWT 容器。
3.2.2.5 I TEM B AND
用于显示一行数据。
3.2.2.6 W ATERMARK
用于在报表每一页的背景打印信息。有禁止在第一页和最后一页打印的选项。
3.2.2.7 G ROUP
组可以包含任意数量的(嵌套的)组。分组字段的顺序是不重要的。如果组没包含任何分组
字段,则会展开报表的所有行(这样的组叫缺省组)。
组包含 GroupHeader、GroupFooter、GroupBody(某个子类)子元素。GroupHeader 和
GroupFooter 都是一个 Band。
3.2.2.8 M ASTER R EPORT
MasterReport 表示一个主报表。
主 报 表 包 含 setBundle 、 setResourceBundleFactory 、 setParameterDefinition 、
setResourceManager、setDataFactory 等 setter 方法。
AbstractReportDefinition 是 MasterReport 和 SubReport 的基类,提供了公共实现。
3.2.2.9 S UB R EPORT
SubReport 表示一个子报表。
子报表可以绑定到顶级 band 并将会打印。子报表有它自己的 tablemodel,也可以有它自己
的 dataFactory。
子报表可以导入导出参数。参数映射可以自由定义,并不要求和父报表列名相同。
如果定义了全局导入或导出(通过增加参数映射"*" => "*"),其他定义的参数会被忽略。
3.3  数据层
Pentaho Reporting 有一个很简单的数据层,引擎核心通过这一数据层来访问数据,从而屏蔽
不同数据源的差异并保持数据源类型的多样化。只要实现数据层的相关接口,就可以增加任
意类型的数据源。
数据层只有两个关键接口 TableModel 和 DataFactory。
3.3.1 T ABLE M ODEL
这个 TableModel 就是 javax.swing.table.TableModel,Pentaho Reporting 没有定义一个新的接
口。
TableModel 表示一个二维数据集,根据行号和列号可以取到数据。主要有以下方法:
int getRowCount()
int getColumnCount()
Object getValueAt(int rowIndex, int columnIndex)
String getColumnName(int columnIndex)
其他如修改数据和增加 swing 事件监听器的方法没有被使用。
core 包的 MetaTableModel 接口继承了 TableModel,增加了获取表格、列、单元格属性的能
力。
3.3.2 D ATA F ACTORY
DataFactory 表示一个数据工厂,根据请求创建返回一个 TableModel 对象。主要方法有:
String[] getQueryNames()
boolean isQueryExecutable(String query, DataRow parameters)
TableModel queryData(String query, DataRow parameters)
MasterReport 和 SubReport 都有 setDataFactory 方法。
3.3.2.1 C OMPOUND D ATA F ACTORY S UPPORT
同样在 core 包,DataFactory 有一个子接口,CompoundDataFactorySupport。它可以组合多
个 DataFactory,根据情况用其中一个 DataFactory 来执行查询。
3.3.3 核心的 D ATA F ACTORY 实现
引擎核心包含了一些 DataFactory 的实现类,类层次如下:
  DataFactory
  TableDataFactory
  ExternalDataFactory
  CachingDataFactory(cache)
  StaticDataFactory(modules.misc.datafactory)
  NamedStaticDataFactory(modules.misc.datafactory)
  SimpleSQLReportDataFactory(modules.misc.datafactory.sql)
  SQLReportDataFactory(modules.misc.datafactory.sql)
  CompoundDataFactorySupport
  CompoundDataFactory
3.3.3.1 T ABLE D ATA F ACTORY
TableDataFactory 提供了按键来访问预定义的二维表,它不接收参数,因此不能用于参数化
查询。
3.3.3.2 E XTERNAL D ATA F ACTORY
允许使用作为参数传入的 tablemodel 作为数据源。
3.3.3.3 C ACHING D ATA F ACTORY
类 CachingDataFactory 实现了 DataFactory 的子接口 CompoundDataFactorySupport,增加了对
查询结果缓存的能力。
3.3.3.4 S TATIC D ATA F ACTORY
使用 Java 反射机制来搜索报表数据源。查询可以是以下格式:
<full-qualified-classname>#methodName(Parameters)
<full-qualified-classname>(constructorparams)#methodName(Parameters)
<full-qualified-classname>(constructorparams)
3.3.3.4.1  N AMED S TATIC D ATA F ACTORY
子类 NamedStaticDataFactory 提供了查询别名机制来解耦报表定义和底层的数据源实现。报
表不再需要指定原始查询,取而代之的是在报表定义中使用一个符号名称。
3.3.3.5 S IMPLE SQLR EPORT D ATA F ACTORY
SimpleSQLReportDataFactory 使用 JDBC 执行 SQL 查询的数据工厂。它需要提供一个
ConnectionProvider 以便从中获得 JDBC 连接。
ConnectionProvider 是一个接口,有 DriverConnectionProvider、JndiConnectionProvider、
StaticConnectionProvider 这几个实现类。
3.3.3.5.1  SQLR EPORT D ATA F ACTORY
子类 SQLReportDataFactory 增加了用脚本语言定义 SQL 的能力。
3.3.3.6 C OMPOUND D ATA F ACTORY
CompoundDataFactory是 CompoundDataFactorySupport的实现类。可以组合多个DataFactory,
返回第一个能执行特定查询的 DataFactory 的查询结果。
CompoundDataFactory 的子类 CascadingDataFactory 是一个内部实现类,不应该使用它。
3.3.4 数据源扩展
针对不同的数据源类型,报表引擎提供了若干个数据源实现的扩展包。这些扩展包不属于引
擎核心,它们位于 engine/extensions-*包。
每个数据源实现包含:DataFactory 和相应的 TableModel 实现,数据源 xml 定义文件的解析,
把数据源定义串行化到 xml 文件等几部分。
3.3.4.1 M ONDRIAN
Mondrian 数 据 源 提 供 了 BandedMDXDataFactory 、 DenormalizedMDXDataFactory 、
LegacyBandedMDXDataFactory 这 几 个 DataFactory 。 相 应 的 , 它 们 分 别 返 回
BandedMDXTableModel、DenormalizedMDXTableModel、LegacyBandedMDXTableModel 这几
个 TableModel。
Banded 即 对 应 PRD 界 面 中 OLAP4J 、 Pentaho Analysis 类 型 , Denormalized 对 应
OLAP4J(Denormalized)、Pentaho Analysis(Denormalized)类型,Legacy 对应 OLAP4J(Legacy)、
Pentaho Analysis(Legacy)类型。
关于 Banded、Denormalized、Legacy 的区别,在前面(设计报表/数据源/OLAP)已介绍。
3.3.4.2 OLAP4J
与 Mondrian 数 据 源 类 似 , olap4j 数 据 源 也 有 对 应 的 BandedMDXDataFactory 、
DenormalizedMDXDataFactory、LegacyBandedMDXDataFactory 这几个 DataFactory,以及
BandedMDXTableModel、DenormalizedMDXTableModel、LegacyBandedMDXTableModel 这几
个 TableModel。
Banded、Denormalized、Legacy 的含义跟 Mondrian 一样。
3.3.4.3 M ETADATA
Pentaho Metadata 已在前面(设计报表/数据源/Metadata)介绍,该数据源提供了使用 MQL
来查询数据的能力。
Pentaho Metadata 数 据 源 提 供 数 据 工 厂 SimplePmdDataFactory 。 它 需 要 提 供 一 个
IPmdConnectionProvider 以 获 得 JDBC 连 接 。 IPmdConnectionProvider 有 一 个 实 现 类
PmdConnectionProvider , 根 据 元 数 据 定 义 从 DriverConnectionProvider/
JndiConnectionProvider/ StaticConnectionProvider 获取连接。
SimplePmdDataFactory的子类PmdDataFactory提供了脚本支持,跟前面SQLReportDataFactory
类似。
Pentaho Metadata 数据源依赖于 pentaho-metadata 项目。
3.3.4.4 K ETTLE
Kettle 数据源支持通过 ETL 过程来加载数据,它定义了数据源工厂 KettleDataFactory。它定
义的查询是 KettleTransformationProducer 类型。
3.3.4.5 S CRIPTING
Scripting 数据源支持从一段脚本程序中获取数据,它定义了数据源工厂 ScriptableDataFactory。
它使用了 apache 的 BSF 项目来管理多脚本语言。
3.3.4.6 XP ATH
XPath 数据源支持用 XPath 的方式读取 xml 文件,定义了数据源工厂 XPathDataFactory。
3.3.5 D ATA R OW 接口
DataRow 的目的是使用一个统一接口来访问 TableModel、报表参数、表达式和函数的(一行,
对 TableModel 而言)数据。DataRow 由引擎核心使用,跟数据源实现无关。它只有以下三
个方法:
Object get(String col)
String[] getColumnNames()
boolean isChanged(String name)
4  嵌入应用
实际使用 Pentaho 报表都是嵌入到应用中,这也是传统 JfreeReport 的用法。这就需要写代
码来加载、操作报表。
4.1  引擎初始化
使用报表引擎,首先要初始化,只要做一次即可:
ClassicEngineBoot.getInstance().start();
ClassicEngineBoot位于引擎核心org.pentaho.reporting.engine.classic.core包,它继承了LibBase
库的 AbstractBoot 类,而后者又实现了 SubSystem 接口。
这个过程会加载报表引擎核心模块,同时也加载一批报表扩展模块,根据配置,也会加载额
外的模块。
4.2  加载报表
从报表文件加载报表,需要使用ResourceManager类。ResourceManager类位于Libloader库,
全限定名是:org.pentaho.reporting.libraries.resourceloader.ResourceManager。
ClassLoader classloader = this.getClass().getClassLoader();
URL reportDefinitionURL = classloader.getResource("reporting/Sample1.prpt");
ResourceManager resourceManager = new ResourceManager();
resourceManager.registerDefaults();
Resource directly = resourceManager.createDirectly(reportDefinitionURL, MasterReport.class);
MasterReport report = (MasterReport)directly.getResource();
这样就得到了 MasterReport 对象,加载包含了报表定义解析、构造报表对象的过程。
可是这里只用了 libraries . resourceloader 包下的类,作为基础库是不了解 MasterReport 的结
构的,怎么就能够构造出 MasterReport 对象呢?
实际上构造报表是 engine.classic.core 里面做的,MasterReport 是个 final 类,它有一个
ResourceManagerBackend属性(可以从构造函数传入),它通过调用ResourceManagerBackend
的方法来注册资源工厂(org.pentaho.reporting.libraries.resourceloader.ResourceFactory 接口
的实现),而资源工厂是通过配置文件得到的。
4.3  读取参数定义
很多报表都会需要参数,参数一般需要由用户输入。为了构建参数输入界面,需要读取报表
的参数定义。
表示报表参数定义的对象是 ReportParameterDefinition,MasterReport 类有
getParameterDefinition()方法,返回 ReportParameterDefinition 对象。参数相关的类一般位于
parameters 包。
ReportParameterDefinition 有以下方法:
int getParameterCount()
ParameterDefinitionEntry getParameterDefinition(int parameter)
ParameterDefinitionEntry[] getParameterDefinitions()
ReportParameterValidator getValidator()
ParameterDefinitionEntry 表示一个参数定义,从中可获得参数的名称、类型、缺省值、是否
必须等信息,用于生成报表参数的表单。
如果是一个列表参数,需要构建表单中该参数的候选值列表(下拉列表),可以这样:
ParameterDefinitionEntry pde=//...
ParameterContext context = new DefaultParameterContext(report)
ListParameter lp=( ParameterDefinitionEntry)pde;
ParameterValues values = lp.getValues(context);
从 ParameterValues 可以读取行数、每一行的 keyValue 和 textValue,从而可以构造列表参数
的候选列表。
4.4  注入参数
先从获得报表的 ReportParameterValues 对象,在调用 put 方法传入参数:
Map<String, Object> reportParameters = // ...获得报表参数
if (null != reportParameters) {
ReportParameterValues rpv= report.getParameterValues();
for (String key : reportParameters.keySet()) {
rpv.put(key, reportParameters.get(key));
}
}
注入参数时要保证参数类型正确,如果需要一个 Integer 而传入了 String,就会报错。
4.5  报表输出
pentaho 报表有多种输出格式支持,它使用 itext、POI 等开源工具支持输出。写代码时要用
到 org.pentaho.reporting.engine.classic.core.modules.output 包及子包的相关类。
输出报表首先要得到一个输出流( java.io.OutputStream ),可以来自文件或
HttpServletResponse。
报表输出的过程就是报表处理的过程,ReportProcessor 是报表处理器,调用 processReport()
开始处理报表。
下面试多种输出格式的示例。注意代码要放在 try 里,最后保证关闭 reportProcessor:
OutputStream outputStream = //...
MasterReport report = //...
AbstractReportProcessor reportProcessor = null;
try {
//...
// reportProcessor = ...
// reportProcessor.processReport();
} finally {
if (reportProcessor != null) {
reportProcessor.close();
}
}
4.5.1  HTML
这里 StreamRepository 为 org.pentaho.reporting.libraries.repository.stream.StreamRepository,
位于 librepository 库。
StreamRepository targetRepository = new StreamRepository(outputStream);
ContentLocation targetRoot = targetRepository.getRoot();
HtmlOutputProcessor outputProcessor = new
StreamHtmlOutputProcessor(report.getConfiguration());
HtmlPrinter printer = new AllItemsHtmlPrinter(report.getResourceManager());
printer.setContentWriter(targetRoot, new DefaultNameGenerator(targetRoot, "index", "html"));
printer.setDataWriter(null, null);
printer.setUrlRewriter(new FileSystemURLRewriter());
outputProcessor.setPrinter(printer);
reportProcessor = new StreamReportProcessor(report, outputProcessor);
reportProcessor.processReport();
4.5.2 PDF
final PdfOutputProcessor outputProcessor = new PdfOutputProcessor(
report.getConfiguration(), outputStream, report.getResourceManager());
reportProcessor = new PageableReportProcessor(report, outputProcessor);
reportProcessor.processReport();
4.5.3  EXCEL
final FlowExcelOutputProcess or target = new FlowExcelOutputProcessor(
report.getConfiguration(), outputStream, report.getResourceManager());
reportProcessor = new FlowReportProcessor(report, target);
reportProcessor.processReport();
4.6  编程方式创建报表
MasterReport 对象一般从.prpt 文件加载得到,但也可以通过代码构造。如果加载得到的
MasterReport 对象需要调整,也可以通过代码方式修改报表定义。
4.6.1 创建元素
下面的代码不需要加载.prpt 文件,通过代码构造报表和报表元素。
MasterReport report = new MasterReport();
//设置数据源,为演示,使用一个静态数据源
DefaultTableModel tableModel = new DefaultTableModel(new Object[][] {
{ "libloader", 13405 }, { "libformula", 456938 } },new String[] { "名称", "大小" });
final TableDataFactory dataFactory = new TableDataFactory();
dataFactory.addTable("default", tableModel);
report.setDataFactory(dataFactory);
// 增加公式和表达式
FormulaExpression formula = new FormulaExpression();
formula.setName("SizeKilobytes");
formula.setFormula("=[Size] / 1024");
report.addExpression(formula);
// 增加 header、footer
ReportHeader reportHeader = new ReportHeader();
ReportFooter reportFooter = new ReportFooter();
report.setReportHeader(reportHeader);
report.setReportFooter(reportFooter);
// 增加 item band
ItemBand itemBand = new ItemBand();
report.setItemBand(itemBand);
// 增加一个标签到报表头(作为标题)
//注意使用 LabelElementFactory 创建 Label
LabelElementFactory labelFactory = new LabelElementFactory();
labelFactory.setText("库信息");
labelFactory.setX(1f);
labelFactory.setY(1f);
labelFactory.setMinimumWidth(100f);
labelFactory.setMinimumHeight(20f);
labelFactory.setBold(true);
Element label = labelFactory.createElement();
reportHeader.addElement(label);
// 增加列表表头:库名
TextFieldElementFactory textFactory = new TextFieldElementFactory();
textFactory.setFieldname("Name");
textFactory.setX(1f);
textFactory.setY(1f);
textFactory.setMinimumWidth(100f);
textFactory.setMinimumHeight(20f);
Element nameField = textFactory.createElement();
itemBand.addElement(nameField);
// 增加列表表头:大小
NumberFieldElementFactory numberFactory = new NumberFieldElementFactory();
numberFactory.setFieldname("SizeKilobytes");
numberFactory.setX(101f);
numberFactory.setY(1f);
numberFactory.setMinimumWidth(100f);
numberFactory.setMinimumHeight(20f);
Element sizeField = numberFactory.createElement();
itemBand.addElement(sizeField);
这样一个报表已构造完毕,按前面的方法处理报表、输出即可。
效果如下:
4.6.2 预处理器
报表预处理器允许在生成报表前对报表进行操作,通过实现 ReportPreProcessor 接口并加入
到报表预处理器列表中。AbstractReportDefinition 类有 addPreProcessor(ReportPreProcessor
preProcessor)方法,作为 AbstractReportDefinition 的子类,MasterReport 和 SubReport 自然
都可以增加报表预处理器。
下面是一个例子,使用关系数据库数据源,查询客户信息。不手工创建 item band 的元素,
根 据 数 据 源 的 元 数 据 自 动 增 加 元 素 。 关 键 在 于 使 用 了 报 表 预 处 理 器
RelationalAutoGeneratorPreProcessor,它是接口 ReportPreProcessor 的实现类。
final String QUERY_NAME = "ReportQuery";
final String QUERY_SQL = "select CUSTOMERNAME, CITY, STATE, POSTALCODE, COUNTRY
from CUSTOMERS";
final MasterReport report = new MasterReport();
report.setQuery(QUERY_NAME);
final DriverConnectionProvider dcp = new DriverConnectionProvider();
dcp.setDriver("org.hsqldb.jdbcDriver");
dcp.setUrl("jdbc:hsqldb:./sql/sampledata");
dcp.setProperty("user", "sa");
dcp.setProperty("password", "");
final SQLReportDataFactory dataFactory = new SQLReportDataFactory(dcp);
dataFactory.setQuery(QUERY_NAME, QUERY_SQL, null, null);
report.setDataFactory(dataFactory);
report.addPreProcessor(new RelationalAutoGeneratorPreProcessor());
5  扩展报表
Pentaho Reporting 有一套扩展系统的方式,能够无侵入性地增加功能。这主要是通过定义模
块、加载模块的方式来实现的。本章主要讲述创建自定义表达式、函数、报表元素的方法和
步骤。示例参考了《 Pentaho Reporting 3.5 for Java Developers》一书 。
5.1  表达式和函数
5.1.1 L IB F ORMULA
LibFormula 是一个提供公式支持的基础库,包括:公式解析、公式运算以及一批预定义的表
达式和函数。公式的语法基于 OpenFormula 标准。
5.1.1.1 F UNCTION 接口
接口 Function 是 LibFormula 中所有预定义的函数实现的接口。一个函数是一个任意的运算,
返回的值类型只有在函数运算完成后才可用。函数必须是无状态的,这意味着,使用完全相
同的参数调用相同的函数必须总是返回相同的计算结果。
当需要自定义函数时,如果函数跟报表状态无关,并且内部不需要访问报表的当前数据行,
那么可以选择实现 LibFormula 的 Function 接口。
Function 接口只有两个方法:
TypeValuePair evaluate(FormulaContext context, ParameterCallback parameters)
String getCanonicalName()
5.1.2 报表表达式
在报表引擎核心模块的 function 包有一个 Expression 接口,表示一个表达式。表达式不维护
状态,因此是轻量级的函数。表达式用于在报表的一行内计算值,可以用一个 dataRow 变
量来访问这个报表内当前行的其他字段、表达式或函数。
Expression 接口主要的方法有:
int getDependencyLevel()
String getName()
Object getValue()
DataRow getDataRow()
ExpressionRuntime getRuntime()
ResourceBundleFactory getResourceBundleFactory()
Configuration getReportConfiguration()
getValue 是表达式运算的方法,实现自定义表达式/函数时要实现的关键方法。
getDependencyLevel、getName 也有相应的 set 方法,一般在 PRD 界面会有这两个属性。
getDataRow 可以访问当前数据行。DataRow 包含的方法前面(报表引擎/数据层/DataRow 接
口)已经提过。
AbstractReportDefinition 有 addExpression、removeExpression、getExpressions 和 setExpressions
方法可以维护报表的表达式。
5.1.3 报表函数
同样在报表引擎核心模块的 function 包,也有一个 Function 接口,表示一个报表函数。它跟
LibFormula 库的 Function 接口没有关系。它继承了 Expression 接口,因此也可以访问报表的
当前行数据。
除此之外,Function 也继承了 ReportListener 接口(位于 event 包,它继承了标记接口
java.util.EventListener)。当报表在生成时,函数能接收到事件通知,允许函数检测报表生成
的过程,并维护内部状态。
函数是有状态的表达式。每当报表在生成过程改变它的状态时,报表函数就会被调用。为了
支持报表引擎的 ReportState 实现,在某些检查点,函数的工作模型基于函数状态的克隆。
Function 有以下直接子接口:AggregationFunction、 LayoutProcessorFunction、 OutputFunction、
StructureFunction。
5.1.4 报表监听器
Function的父接口ReportListener的方法如下:
void groupFinished(ReportEvent event)
void groupStarted(ReportEvent event)
void itemsAdvanced(ReportEvent event)
void itemsFinished(ReportEvent event)
void itemsStarted(ReportEvent event)
void reportDone(ReportEvent event)
void reportFinished(ReportEvent event)
void reportInitialized(ReportEvent event)
void reportStarted(ReportEvent event)
5.2  实现表达式
这里以一个例子来说明自定义表达式的步骤。这个自定义表达式用正则表达式来提取想要的
内容。需要传入两个参数,一个是原始字符串,一个是包含一个分组的正则表达式,表达式
运算结果是正则表达式匹配的第一个分组。
5.2.1 定义表达式类
所有的表达式都要实现 Expression 接口,这里先实现一个正则表达式类。可以继承
AbstractExpression 类,它包含了 Expression 接口所有方法的空实现。
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import org.pentaho.reporting.engine.classic.core.function.AbstractExpression;
public class RegexExpression extends AbstractExpression {
private String regex;
private String field;
//getter、setter...
public Object getValue() {
try {
final Pattern p = Pattern.compile(regex);
final Object o = getDataRow().get(getField());
if (o == null) {
return null;
}
final Matcher m = p.matcher(o.toString());
m.find();
return m.group(1);
} catch (Exception e) {
return e.getMessage();
}
}
}
5.2.2 定义元数据
5.2.2.1  资源 文件
这是一个标准的 Java 资源文件包,包含表达式显示名称和分组(在选择表达式/函数对话框
中的分组),每个属性以及 dependencyLevel 的显示名和分组(在属性编辑界面的分组)。
dependencyLevel 指示公式的运算优先级。
这个文件应该位于表达式实现类的相同目录,并命名为<类名>Bundle.properties,这个例子
就是 RegexExpressionBundle.properties。
display-name=Regex Expression
grouping=Other
property.field.display-name=Field Name
property.field.grouping=Other
property.regex.display-name=Regex
property.regex.grouping=Other
property.name.display-name=Name
property.name.grouping=Common
property.dependencyLevel.display-name=Dependency Level
property.dependencyLevel.grouping=Common
5.2.2.2  元数据 XML
还需要提供一个表达式元数据 XML 文件。文件名是没关系的,后面由自己的 Module 类来加
载。这里把它叫 meta-expressions.xml。
一个表达式定义是一个 expression 节点,下面元素是表达式的属性。expression 和 property
的 hidden 属性指示是否在 PRD 中可见。
property 的 value-role 属性指示属性值所用于的角色,这有助于 PRD 确定要显示的编辑器类
型。这些是合法的选项:Value、Resource、ElementType、Query、Field 和 Group。
<meta-data xmlns="http://reporting.pentaho.org/namespaces/engine/classic/metadata/1.0">
<expression class="RegexExpression" bundle-name="RegexExpressionBundle"
result="java.lang.String" hidden="false">
<property name="dependencyLevel" mandatory="false"
value-role="Value" hidden="false"/>
<property name="field" mandatory="true" value-role="Field" hidden="false"/>
<property name="regex" mandatory="true" value-role="Value" hidden="false"/>
<property name="name" mandatory="true" value-role="Name" hidden="false"/>
</expression>
</meta-data>
5.2.2.3  定义模块类
为了在报表引擎注册这个 XML 文件,还需要定义一个 Module 类。Module 是一个接口,位
于 LibBase 库中。继承 AbstractModule 类简化了定义 Module 类的工作。
一个 Module 类应该有一个缺省函数,并调用 AbstractModule 的 loadModuleInfo 方法。这样
可以加载必要的模块配置文件。
initialize 方法内引用了刚才定义的 XML 文件 meta-expressions.xml。
import org.pentaho.reporting.engine.classic.core.metadata.ElementMetaDataParser;
import org.pentaho.reporting.libraries.base.boot.AbstractModule;
import org.pentaho.reporting.libraries.base.boot.ModuleInitializeException;
import org.pentaho.reporting.libraries.base.boot.SubSystem;
public class ExModule extends AbstractModule {
public ExModule() throws ModuleInitializeException {
loadModuleInfo();
}
public void initialize(final SubSystem subSystem) throws ModuleInitializeException {
ElementMetaDataParser.
initializeOptionalExpressionsMetaData("meta-expressions.xml");
}
}
5.2.2.4  模块属性文件
除了模块类,还必须定义一个描述这个模块的属性文件,名为 module.properties。
module.name: exmodule
module.producer: foross
module.description: ..
module.version.major: 1
module.version.minor: 0
module.version.patchlevel: 0
dependency.core.module: org.pentaho.reporting.engine.classic.core.ClassicEngineCoreModule
dependency.core.dependency-type: required
dependency.core.version.major: 3
dependency.core.version.minor: 9
dependency.core.version.patchlevel: 1
5.2.2.5  注册模块
定义了模块实现之后,还需要在报表报表引擎中注册这个模块。做法是,在包含这个模块的
JAR 根 目 录 , 增 加 一 个 属 性 文 件 叫 classic-engine.properties , 里 面 包 含 一 个 属 性
org.pentaho.reporting.engine.classic.extensions.modules.<Module Name>.Module,属性的值是
这个模块实现类的包含包名的完整类名:
org.pentaho.reporting.engine.classic.extensions.modules.exmodule.Module=ExModule
5.2.3 使用及效果
前面的文件都准备好之后,就可以把它们编译成一个 JAR 包,放到 PRD 的类路径(lib 目录)
中,启动 PRD,就可以检查结果。
打开一个报表,点出增加函数对话框,可以看到函数分组中多了一个 Other,下面有一个
Regex Expression 函数,这就是前面自定义的函数:
把这个函数加入报表,选择函数,可以看到下面的属性编辑界面:
属性显示名称和分组是在文件 RegexExpressionBundle.properties 设置的。
这里使用前面出现过的产品销售报表来演示。给报表增加一列,取值是从产品编码中提取的
前面部分数字。
按上图设置这两个函数属性的值。把函数拖入报表中,加入表头,调整位置、样式。最后可
得到下面的效果:
5.3  实现函数
现在自定义一个跟前面功能一样的函数。因为不需要访问报表状态和数据行,所以可以通过
实现 LibFormula 库 Function 接口的方式来自定义函数。
5.3.1 定义函数类
首先要实现一个函数类,这里是 RegexFunction。重点是实现 evaluate 方法。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.pentaho.reporting.libraries.formula.EvaluationException;
import org.pentaho.reporting.libraries.formula.FormulaContext;
import org.pentaho.reporting.libraries.formula.LibFormulaErrorValue;
import org.pentaho.reporting.libraries.formula.function.Function;
import org.pentaho.reporting.libraries.formula.function.ParameterCallback;
import org.pentaho.reporting.libraries.formula.lvalues.TypeValuePair;
import org.pentaho.reporting.libraries.formula.typing.TypeRegistry;
import org.pentaho.reporting.libraries.formula.typing.coretypes.TextType;
public class RegexFunction implements Function {
public TypeValuePair evaluate(FormulaContext context,
ParameterCallback parameters) throws EvaluationException {
if (parameters.getParameterCount() != 2) {
throw new EvaluationException (LibFormulaErrorValue.
ERROR_ARGUMENTS_VALUE);
}
final TypeRegistry typeRegistry = context.getTypeRegistry();
final String param1 = typeRegistry.convertToText(parameters.getType(0),
parameters.getValue(0));
final String param2 = typeRegistry.convertToText(parameters.getType(1),
parameters.getValue(1));
try {
final Pattern p = Pattern.compile(param1);
final Matcher m = p.matcher(param2);
m.find();
return new TypeValuePair(TextType.TYPE, m.group(1));
} catch (Exception e) {
return new TypeValuePair(TextType.TYPE, e.getMessage());
}
}
public String getCanonicalName() {
return "REGEX";
}
}
5.3.2 定义函数描述类
需要为函数定义一个函数描述类。需要调用父构造函数的方法,以加载资源。
import org.pentaho.reporting.libraries.formula.function.AbstractFunctionDescription;
import org.pentaho.reporting.libraries.formula.function.FunctionCategory;
import
org.pentaho.reporting.libraries.formula.function.userdefined.UserDefinedFunctionCategory;
import org.pentaho.reporting.libraries.formula.typing.Type;
import org.pentaho.reporting.libraries.formula.typing.coretypes.TextType;
public class RegexFunctionDescription extends AbstractFunctionDescription {
public RegexFunctionDescription() {
// 确保调用父构造函数,带上函数名和函数资源包名
super("REGEX", "Regex-Function");
}
// 把函数放到用户自定义函数分类
public FunctionCategory getCategory() {
return UserDefinedFunctionCategory.CATEGORY;
}
public int getParameterCount() {
return 2;
}
public Type getParameterType(int position) {
return TextType.TYPE;
}
public Type getValueType() {
return TextType.TYPE;
}
public boolean isParameterMandatory(int position) {
return true;
}
}
5.3.3 资源文件
需要定义一个资源文件用于界面显示。这里叫 Regex-Function.properties。
display-name=REGEX
description=Executes a regular expression on a string, returning the first found group
parameter.0.display-name=Regular Expression
parameter.0.description=A Java Regular Expression string, with a grouping defined within the
string.
parameter.1.display-name=String Input
parameter.1.description=A string to parse.
5.3.4 注册函数
为了把函数注册到 LibFormula 模块,需要增加一个名为 libformula.properties 的属性文件,
内容如下:
org.pentaho.reporting.libraries.formula.functions.information.Regex.class=RegexFunction
org.pentaho.reporting.libraries.formula.functions.information.Regex.description=RegexFunction
Description
5.3.5 使用及效果
编译并把目标文件加入 PRD 类路径后,重启 PRD。下面在前面的报表再加一列,取产品编
码的后面部分数字。
增加 Minor 一列(原来加的一列改为了 Major),在 Detail 里加以 text-field。如下图:
编辑这个 text-field 的 value 属性,点后面 Expr 一列(如果改过,会变为笔状):
弹出表达式编辑框:
可以在这里直接编辑,也可以点后面的按钮弹出公式编辑器:
按上面输入表达式,运行报表,可看到结果:
5.4  使用脚本语言
另一种实现自己的报表表达式的办法是使用脚本语言。不过这样的话表达式仅限于当前报表
使用。
下面的的例子仍然实现前面一样的功能。
5.4.1 BSH
这里用 Bean-Scripting-Host(BSH)来实现一个表达式。打开函数对话框,展开 Script 分组,选
择 Bean-Scripting-Host。
按下面设置 Expression 属性:
import java.util.regex.*;
Object getValue() {
final Pattern p = Pattern.compile("S(\\d+)_.*");
final Matcher m = p.matcher(dataRow.get("PRODUCTCODE"));
m.find();
return m.group(1);
}
即设置完毕(未处理异常)。把函数拖入报表即可。
5.4.2 J AVA S CRIPT
用 Javascript 来实现。选择 Script下面的 JavaScript 函数,或者选择 Bean-Scripting
Framework(BSF)并把表达式编程语言属性设置为 javascript。
Expression 属性按如下设置:
dataRow.get("PRODUCTCODE").match(/S(\d+)_.*/)[1]
即可完成。
5.5  实现报表元素
Pentaho Reporting 同样允许自定义报表元素。这个例子自定义一个多角星的元素,仅仅渲染
一个多角星。有几个角、起始角度、内圆比例可以作为参数传入。
5.5.1 定义元素类型类
首先定义一个 ElementType 实现类,在 getValue 方法内绘制一个星形。注意使用了名空间
http://reporting.pentaho.org/namespaces/pr4jd。
import java.awt.Polygon;
import java.util.Locale;
import org.pentaho.reporting.engine.classic.core.Element;
import org.pentaho.reporting.engine.classic.core.function.ExpressionRuntime;
import org.pentaho.reporting.engine.classic.core.metadata.ElementMetaData;
import org.pentaho.reporting.engine.classic.core.metadata.ElementType;
import org.pentaho.reporting.engine.classic.core.metadata.ElementTypeRegistry;
import org.pentaho.reporting.engine.classic.core.style.ElementStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.ElementStyleSheet;
import org.pentaho.reporting.engine.classic.core.util.StringUtil;
public class StarType implements ElementType {
private static String NAMESPACE = "http://reporting.pentaho.org/namespaces/pr4jd";
private transient ElementMetaData elementType;
public StarType() {
}
public ElementMetaData getMetaData() {
if (elementType == null) {
elementType = ElementTypeRegistry.getInstance().getElementType("star");
}
return elementType;
}
public Object getValue(final ExpressionRuntime runtime, final Element element) {
if (element == null) {
throw new NullPointerException("Element must never be null.");
}
final float innerPercent = parseParam(element, "inner-percent", 0.5f);
final float startAngle = parseParam(element, "start-angle", 0f);
final int points = (int) parseParam(element, "points", 5);
int outerRadius = 100;
int innerRadius = (int) (outerRadius * innerPercent);
double startingRotation = (startAngle - 90) * Math.PI / 180;
double angleIncrement = 2.0 * Math.PI / points;
double currRadians = startingRotation;
int minX = Integer.MAX_VALUE;
int minY = Integer.MAX_VALUE;
final Polygon p = new Polygon();
for (int i = 0; i < points; i++) {
double outerX = outerRadius + outerRadius * Math.cos(currRadians);
double outerY = outerRadius + outerRadius * Math.sin(currRadians);
double innerX = outerRadius + innerRadius
* Math.cos(currRadians + angleIncrement / 2);
double innerY = outerRadius + innerRadius
* Math.sin(currRadians + angleIncrement / 2);
p.addPoint((int) outerX, (int) outerY);
p.addPoint((int) innerX, (int) innerY);
currRadians += angleIncrement;
minX = Math.min((int)outerX, minX);
minY = Math.min((int)outerY, minY);
}
if (minX > 0 || minY > 0) {
final Polygon p2 = new Polygon();
for (int i = 0; i < p.npoints; i++) {
p2.addPoint(p.xpoints[i] - minX, p.ypoints[i] - minY);
}
return p2;
} else {
return p;
}
}
public Object getDesignValue(final ExpressionRuntime runtime, final Element element) {
return getValue(runtime, element);
}
public void configureDesignTimeDefaults(final Element element, final Locale locale) {
ElementStyleSheet style= element.getStyle();
style.setStyleProperty(ElementStyleKeys.SCALE, Boolean.TRUE);
style.setStyleProperty(ElementStyleKeys.DRAW_SHAPE, Boolean.TRUE);
style.setStyleProperty(ElementStyleKeys.MIN_WIDTH, new Float(100));
style.setStyleProperty(ElementStyleKeys.MIN_HEIGHT, new Float(100));
element.setAttribute(NAMESPACE, "inner-percent", 0.5f);
element.setAttribute(NAMESPACE, "start-angle", 0f);
element.setAttribute(NAMESPACE, "points", 5);
}
private float parseParam(final Element element, final String attrName, float defaultValue) {
final float val;
final Object attrib = element.getAttribute(NAMESPACE, attrName);
if (attrib != null) {
if (attrib instanceof Number) {
final Number n = (Number) attrib;
val = n.floatValue();
} else {
val = StringUtil.parseFloat(String.valueOf(attrib), defaultValue);
}
} else {
val = defaultValue;
}
return val;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
5.5.2 定义元素元数据
像自定义表达式一样也需要元数据 XML。这里用文件名 meta-elements.xml。
<meta-data xmlns="http://reporting.pentaho.org/namespaces/engine/classic/metadata/1.0">
<include-globals
src="res://org/pentaho/reporting/engine/classic/core/metadata/global-meta-elements.xml"/>
<element name="star" hidden="false" bundle-name="metadata" implementation="StarType">
<attribute-group-ref ref="common-attributes"/>
<attribute-group-ref ref="interactivity"/>
<attribute namespace="http://reporting.pentaho.org/namespaces/pr4jd"
name="inner-percent" mandatory="true" hidden="false"
value-type="java.lang.Number" value-role="Value"/>
<attribute namespace="http://reporting.pentaho.org/namespaces/pr4jd"
name="start-angle" mandatory="true" hidden="false"
value-type="java.lang.Number" value-role="Value"/>
<attribute namespace="http://reporting.pentaho.org/namespaces/pr4jd" name="points"
mandatory="true" hidden="false"
value-type="java.lang.Number" value-role="Value"/>
<style-group-ref ref="borders"/>
<style-group-ref ref="common"/>
<style-group-ref ref="layout"/>
<style-group-ref ref="replaced-content"/>
</element>
</meta-data>
5.5.3 定义模块类
和自定义表达式一样,需要定义一个模块类。如果跟别的自定义表达式同一个模块,就用同
一个模块类(ExModule),在 initialize 方法加上一行,meta-elements.xml 引用了刚才的文
件:
ElementMetaDataParser.initializeOptionalElementMetaData("meta-elements.xml");
5.5.4 定义读写处理器
读写处理器用于解析元素定义的 XML 和把元素定义串行化到 XML。
5.5.4.1  读处理器
用类名 StarReadHandler:
import org.pentaho.reporting.engine.classic.core.modules.parser.bundle.layout.elements.
AbstractElementReadHandler;
import org.pentaho.reporting.libraries.xmlns.parser.ParseException;
public class StarReadHandler extends AbstractElementReadHandler {
public StarReadHandler() throws ParseException {
super("star");
}
}
5.5.4.2  写处理器
用类名 StarWriteHandler:
import java.io.IOException;
import org.pentaho.reporting.engine.classic.core.Element;
import
org.pentaho.reporting.engine.classic.core.modules.parser.bundle.writer.BundleWriterException;
import org.pentaho.reporting.engine.classic.core.modules.parser.bundle.writer.BundleWriterState;
import org.pentaho.reporting.engine.classic.core.modules.parser.bundle.writer.
elements.AbstractElementWriteHandler;
import org.pentaho.reporting.libraries.docbundle.WriteableDocumentBundle;
import org.pentaho.reporting.libraries.xmlns.common.AttributeList;
import org.pentaho.reporting.libraries.xmlns.writer.XmlWriter;
import org.pentaho.reporting.libraries.xmlns.writer.XmlWriterSupport;
public class StarWriteHandler extends AbstractElementWriteHandler {
private static final String NAMESPACE = "http://reporting.pentaho.org/namespaces/pr4jd";
public StarWriteHandler() {
}
public void writeElement(final WriteableDocumentBundle bundle,
final BundleWriterState state, final XmlWriter xmlWriter,
final Element element) throws IOException, BundleWriterException {
if (bundle == null) {
throw new NullPointerException();
}
if (state == null) {
throw new NullPointerException();
}
if (xmlWriter == null) {
throw new NullPointerException();
}
if (element == null) {
throw new NullPointerException();
}
final AttributeList attList = createMainAttributes(element, xmlWriter);
if (xmlWriter.isNamespaceDefined(NAMESPACE) == false) {
attList.addNamespaceDeclaration("pr4jd", NAMESPACE);
}
xmlWriter.writeTag(NAMESPACE, "star", attList,
XmlWriterSupport.OPEN);
writeElementBody(bundle, state, element, xmlWriter);
xmlWriter.writeCloseTag();
}
}
5.5.5 使用及效果
加载目标文件,启动 PRD 后,可看到元素选择栏多了个星形图标,这就是刚才自定义的元
素:
把它拖进报表,设置属性。元素定义了三个自己的属性:
设置好属性,再在样式里设上填充色,可看到以下效果(设计和预览都是一样的):

posted @ 2018-09-30 14:28  r|sh  阅读(2688)  评论(0编辑  收藏  举报