ireport中文手册3.7版(无图)

来源:互联网 发布:神雕侠侣湖南卫视源码 编辑:程序博客网 时间:2024/06/06 20:40


目录

                                             

 

Giulio Toffoli 1

1 序言... 6

什么是iReport?. 6

功能特点:... 7

iReport 社区:... 7

鸣谢:... 8

2 入门... 8

必要条件:... 8

下载:... 9

编译iReport:... 9

基本的配置:... 9

创建JDBC连接:... 12

第一个报表:... 13

命令行选项:... 17

3 JasperReports基础概念... 17

JasperReports 17

报表生命周期:... 18

Jrxml源代码和jasper文件:... 18

数据源和打印格式:... 22

版本兼容性:... 23

表达式:... 24

一个简单的程序:... 25

4 报表结构... 26

Bands 26

Title. 27

Page header 27

Column header 27

Group header 28

Detail 28

Group footer 28

Column footer 28

Page footer 28

Last Page footer 28

Summary. 29

Background. 29

报表属性:... 29

列... 30

高级选项:... 32

脚本:... 32

更多…... 33

Title on a new page选项:... 33

Summary on a new page选项:... 35

Floating column footer选项:... 35

打印顺序:... 35

无数据打印(如果没有数据时):... 36

i18n:... 36

Resource BundleBase name. 36

XML源文件的编码设置:... 37

5 报表元素... 37

选择并插入元素到报表中:... 37

布置和元素顺序... 40

使用元素树管理元素:... 43

基本属性:... 43

线... 46

矩形... 46

椭圆... 47

图象... 47

文本元素... 50

静态文本... 51

文本域... 51

子报表... 55

专用元素... 56

图表... 56

条形码... 56

超连接... 58

Reference. 59

LocalAnchor 59

LocalPage. 59

RemoteAnchor 59

RemotePage. 59

6 字体... 59

字体... 59

扩展字体... 60

编码... 61

使用Unicode字符... 61

报表字体... 61

7 字段,参数和变量... 62

字段... 62

SQL查询的字段注册... 63

JavaBean的字段注册... 64

JRExtendedBeanDataSource的字段注册... 65

字段和文本域... 65

参数... 66

在查询中使用参数... 67

使用程序传递参数... 67

内置参数... 69

变量... 69

内置变量... 71

8 Bands and groups 71

Bands 71

Groups 72

9 Subreport 77

创建子报表... 78

连接子报表到父报表... 78

参数的通道... 78

指定数据源... 79

指定子报表... 80

一步一步举例... 80

返回参数... 86

10 数据源... 87

iReport中的数据源... 88

JDBC连接... 89

ClassNotFoundException. 91

URL不正确... 91

连接参数不正确... 91

使用JDBC连接... 91

字段注册... 92

JRDataSource接口... 93

JavaBean作为数据源... 93

JavaBean的一个字段作为数据源... 95

XML数据源... 96

字段的注册... 98

XML和子报表... 100

CSV数据源... 104

字段的注册... 105

JREmptyDataSource. 105

实现一个新的JRDataSource. 106

用iReport实现个性化的JRDataSource. 108

JavaBean Extended数据源... 110

11 国际化... 111

Resource Bundle BaseName. 111

恢复本地化字符串... 113

格式化消息... 114

配置本地化报表... 114

12 脚本... 115

JRAbstractScriptlet类... 115

iReport处理脚本... 117

用脚本部署报表... 118

13 模板... 119

模版结构:... 119

使用通用模板... 121

14 图表... 123

创建一个简单的图表... 123

级Series 128

自动级... 129

手动级... 130

图表类型和属性... 132

饼图... 133

3D饼图... 133

柱状图... 134

3D柱状图... 136

线图... 136

区域图... 137

15 插件和附加工具... 137

插件结构XML文件... 138

it.businesslogic.ireport.plugin.IReportPlugin类... 139

大型编译器插件... 142

文本向导插件... 144

16 常规问题解决方案... 145

打印百分比... 145

计算组的发生数... 146

分离detail 148

插入一个页... 149

交叉报表... 152

使用多重连接找回数据... 152

如何使用存储过程... 153

 

1 序言

什么是iReport?

iReport是一个能够创建复杂报表的开源项目,并且它能调用JasperReports库应用于任何一种java应用程序。本身是分布式的且由符合GNU通用公共许可的百分之百纯java编写。

由于它丰富的图形界面,你能够很快的创建出任何一种你想要的报表。iReport能够让我们提高技术方面的信心,比如它能降低学习JasperReports的XML语法的难度,而且能够为熟练的技术人员节省大量的时间并能开发出非常精细的报表。

这里将带给大家的虽然是0.4.1版本的,但是大部分的资源都是来自于0.2.0版本发布之后的。因为早先的0.2.0版本不是用java编写的,而是用Visual J++;因此这些版本都只能在微软的Windows 系统运行,自从0.2.0版本发布以后便停止了用Visual J++的开发。

我的任务就将最新的版本的iReport介绍给大家,因此,我不可能应用老的版本讲解。

功能特点:

以下将列出iRreport的一些比较突出的功能:

• 百分之九十九支持JasperReports XML标签

• 所见即所得的报表编辑器,也就是说它具有创建矩形,线,椭圆,正文区域,标签,图表,子报表,条码等完善的工具图标供使用。

• 嵌入式编辑器带有灯泡提示代码规则

• 支持Unicode和非拉丁语言(俄文,中文,日文,韩文…)

• 文档结构浏览器

• 完善的报表编译器和输出器

• 支持所有可以通过JDBC连接的数据库

• 支持所有有效的数据源

• 自动报表创建向导

• 支持子报表

• 源文件的备份

• 支持文档模版

• 支持TrueType字型

• 支持本地化

• 可添加插件扩展功能

• 完全支持脚本

• 支持图表

• 标准对象库管理(页码…)

• 支持拖拽

• 无限制的取消/重做

iReport开发团队是那些来自世界各地的工程师,他们默默无闻的用他们熟练的技术和丰富的经验日负一日的为iReport添加功能排除bugs。

iReport 社区:

iReport网址是http://ireport.sourceforge.net; 企业的网址是http://www.sourceforge.net/projects/ireport.设立了两个英语社区为大家讨论交流:

Help:在这里你不但可以提出要求,也可以提出技术上的问题

http://sourceforge.net/forum/forum.php?forum_id=217623

Open Discussion: 这个社区是用来发布注释,判定讨论结果和提出新的功能建议的。http://sourceforge.net/forum/forum.php?forum_id=217622

如果你还是无法解决你的问题,不要着急,我们还有一个特殊的跟踪系统来帮助你:http://sourceforge.net/tracker/?group_id=64348&atid=507164

不保证你的提问能很快得到答复,但是你一定能在几天内收到一个另你非常满意的答复。这些都是免费的,如果你享有这些,我们还是希望你能够给我们的项目一些资助。如果你需要一些关于商业方面的支持,你可以写email到: gt@businesslogic.it.

请将你发现的bug的记录发送到:

http://sourceforge.net/tracker/?group_id=64348&atid=507163

在企业网站上, 也可以进一步的提出要求(RFE). 有能力的也可以提出不足并发表完整的代码。为了能始终了解关于最新的项目的开发情况你可以将你的邮件地址加到我们的邮件列表中:http://lists.sourceforge.net/lists/listinfo/ireport-questions

所有的iReport团队成员会以往直前地,严肃地,认真地考虑所有来自于用户们的建议,批评和忠告。

 

鸣谢:

 

iReport 的结晶来自于许多人。但是一些人正在被我们遗忘,我很荣幸的感谢以下为我们工程作出贡献的一些人:Teodor Danciu, Alexander, Andre Legendre, Craig BSpengler, DavidWalters, Egon R Pereira, ErtanO, G Raghavan, Heiko Wenzel,Kees Kuip, OctavioLuna, Peter Henderson, Vinod Kumar Singh, Wade Chandler,Erica Pastorello以及所有的评论家。

 

2 入门

在这章我们将看到使用iReport之前的必要步奏,如何获得二进制的分发和源程序和如何编译和安装它。

 

必要条件:

iReport需要Sun Java 2 SDK 1.4以上版本; 为了能编译jasper文件就必须安装完整的java2(JDK),不光是(JRE)这个运行环境。如果你还想编译iReport源代码,你还要安装Jakarta Ant version 1.6以上版本。

硬件方面,类似于java的环境,iReport也占很多的RAM,所以它也需要只少256Mb 的内存和至少20Mb的磁盘空间。

 

下载:

你可以到SourceForge网站上的企业主页上下载最新发布的iReport

(http://sourceforge.net/projects/ireport). 可能有几种不同的分类:

iReport-x.x.x.zip 这是官方的zip格式的二进制文件。

iReport-x.x.x.tgz 这是官方的tar gz格式的二进制文件。

iReport-x-x-x-src.zip 这是官方的包含源代码的zip格式的二进制文件。

x.x.x表明了iReport的版本号。每一种都包含必须使用的第三方的库和程序及附加文件,例如模板和一些html格式的基础教程。

如果你想要更多最新版本的源程序,你可以直接地连接CVS库。但必须要有一个CVS客户端(像CVS,JCVS或者WinCVS)。

如果你有CVS那就执行如下的命令行:

cvs-d:pserver:anonymous@cvs.ireport.sourceforge.net:/cvsroot/ireport login  (目前好象无法连接)

andthen all on the same line…

cvs -z3-d:pserver:anonymous@cvs.ireport.sourceforge.net:/cvsroot/ireport

coiReport2

这样CVS客户端就可以将iReport的所有文件下载到本地,包括所有的文档,库和所有有用的编译iReport的文件。

就使用其他CVS的用户来说,SourceForge网站也自制了详细的解释用来检出工程。

 

编译iReport:

这些源中包含一个build.xml文件,它是被JakartaAnt 用来编译和启动iReport 和或用来创建不同类型的工程。

下载 iReport-x.x.x-src.zip,解压缩到你指定的目录,例如:c:\devel(or/usr/devel on unix system)。打开命令提示符或shell,进入你解压的目录和iReport目录:C:\devel\iReport-0.3.2>ant iReport

 

如果这个源完整的存在与目录中,它将被编译进类中iReport就能直接启动。

 

基本的配置:

如果选择下载了iReport二进制版本的,那就直接将该压缩文件解压缩到指定目录,例如:c:\devel (or/usr/devel on a unix system). 打开命令提示符或shell,进入被解压缩的目录,输入iReport目录:

C:\devel\iReport-0.3.2>iReport.bat

oron unix:

$ ./iReport.sh

(inthis case, it should be preceded by a “chmod +x” if the file is not executable.)

第一步执行完毕时iReport将创建一个名叫”.ireport”的文件在用户的主目录。这里的主目录指由自己设置和配置的目录。如果文件夹不能被创建,这就有可能是解压缩造成的影响而不能够配置成功,这时,你就要自己手动的创建一个目录。

进行下一步之前你需要将tools.jar 文件拷贝到JDK的lib目录下以及iReport的lib目录下。如果没有这个文件的话在编译report时将会产生一些异常(carried out by using classes contained in this java library).在MacOS X系统中tools.jar文件就不需要拉,因为具有编译ireport所必须的类的classes.jar文件代替它。

iReport的初始化配置包括:设置所要查看运行后的文档的格式;选择语言;设置编译后的文件目录。其他的配置说明将在以下进行。为了继续的进行配置必须打开ireport,然后选择菜单选项中工具选项(menuOptions → Tools.)。此时将出现2.1选项窗口。

2.1图

选择你最熟悉的语言接下来点“Compiler”选项卡。

2.2图

这个选项卡是用来设置编译后的文件存储目录,默认的目录会在iReport的根目录。一般情况下是要指定一个有效的目录来保存编译文件。这个目录也可以是加载报表源时的目录,既然这样就选择“Use the reports directory for compiles”复选框。

2.3图

完成以上列出的配置后,接下来我们还要设置报表输出格式和查看XML源所用编辑器。重启iReport继续设置上图的选项。

创建一个空白报表测试一下我们的设置 (menu File New Document), 领悟一下iReport所提供的功能。之后点工具条上的运行按扭。如果你操作的正确,将会有一个保存jrxml文件的提示,相应的一个jrxml文件将被创建,之后会发布出一个预先设置的空白页。这就意味着你刚才的配置ok拉。

创建JDBC连接:

一个有代表性的关系数据库可以提供最普通的数据源给一个报表。首先,我们来看看如何设置一个JDBC连接,点菜单Datasource Connections/Datasources 并点窗口的连接列表的new按扭。此时打开一个新建连接(图2.4)窗口。在这个面板上填写连接名:(i.e. “My new connection”)并选择正确的JDBC驱动。iReport支持大部分的JDBC驱动URL格式。因此你能够自动创建一个URL通过在相应的输入框中填写服务器地址和数据库名。若要完成连接你就必须输入数据库名和密码用来连接数据库。如果你想保存密码,那就将 “Save password” 打对勾。

注意:iReport将密码保存在一个txt文件中,如果你不想保存密码就不要选择“Save password”复选框…

点test按扭测试一下连接,不过最好是再保存之前测试。

 

2.4图

iReport被装入的JDBC驱动只有MYSQL和HSQLDB。如果在测试期间发现有ClassNotFound异常,很有可能是能被选择的驱动的classpath中不包含JAR或

(ZIP)文件。不用关闭iReport,拷贝这个JDBC驱动到lib目录下,重试一下;这个JAR将被重新被iReport加载。在第十章,我们将深入广泛的解释所有的数据源的配置形式。测试通过后按保存按钮保存连接。

通过这种方式我创建了一个新的数据源,这样iReport就可以将它作为预置的数据源来使用。选择菜单中“build Set active connection”项目。

2.5图

从列表中选择我们的连接按OK 按钮(图2.5). 那么iReport就会在需要使用数据库时用这个连接 (我们想要字段就可以通过SQL查询和打印来创建)。

第一个报表:

现在我们已经安装配置了iReport,并创建了一个JDBC连接数据库,接下来我们将创建一个简单的报表用这个向导。

这个例子以及以后的所有例子我们都用HSQL 数据库引擎(HSQLDB),它是一个小型的用java编写的关系型数据库,而且提供了JDBC驱动。如果用它的话,我们就必须拷贝hsqldb.jar文件到libs目录(这个文件已经在0.3.2版本之后都包含在发布文件中了)。为了能了解到更多的关于这个小家伙的信息,就登陆HSQLDB的官方网站http://hsqldb.sourceforge.net.

为了能设置一个有效的数据库连接我们给出以下例子(来源与本手册);使用以下参数:

Proprieties

Value

Name

Northwind

JDBC Driver

org.hsqldb.jdbcDriver

JDBC Url

jdbc:hsqldb:c:/devel/northwind/northwind

Username

sa

Password

 

表格2.1

配置的最后请设置Northwind作为一个有效的连接(Build →Set active connection)。选择菜单 “File → Report Wizard”.这是一个用来一步步创建报表的工具。

图2.6

在文本区域输入SQL查询用来充当报表中的数据,例如:

select * from customersorder by country

…点 Next. 这里的分组选项是非常重要的一条。接下来我们将详细讨论。iReport 将读取customers表的这些字段 (图 2.7).

图2.7

选择你需要的字段然后点 Next. 你会得到一个提示:你希望从这些被选择到报表中的那个字段用来分组 (即便要) (图 2.8)…

图2.8

根据这个向导,你最多可以创建四个组。其他的可以随后来定义(事实上它是可以设置很多组的)。

我们将定义一个简单的组用COUNTRY字段 (图. 2.8).

下一步向导会让你选择一个能被用来创建一个基本报表的模板。iReport提供了一些非常简单摸板供选择,接下来我将试着创建一个新模板。目前我们知道的有两种类型的模板: thetabular templates, 所有的记录都在同一条表格线内,一个字段后面跟的一个数据。the columnar templates, 这里是将字段按列排列,每列一个字段,下面将是所有数据。

图2.9

第一个报表选择tabular模板,它是著名的T样式(T的意思就是tabular)。一但你选择这个模板,那就点next。之后向导将展示我们操作的结果。点Finish来创建这个报表,它将展现在iReport的中央区域,等待被执行。执行之前你得先保存报表源,这样它才能被用来编译创建报表。该如何编译创建呢?你可以点工具条上按钮(使用连接的运行报表)。

图2.10

接下来你就点这个带连接的运行报表按钮,此时将会提示你输入你个文件名来保存这个文件。可以以report1.jrxml的文件名来保存。在控制面板上的下面的窗口将会有一些提示信息。这些信息就是告诉你发生了什么事:一个报表被编译,并完成创建,输出“exported”

图2.11

操作完成后,如果不出以外,这个报表将以缺省的PDF格式展示在你面前,原因是你最初设置输出格式为PDF。

命令行选项:

可能有一些特殊的参数出现在命令行上。所有的参数不区分大小写的。特们能被缩写知道最短(例如:这个命令:–ireport-homec就可以被指定为–i;并不是它因为以“i”开头;命令解释器将认为-i是一个不明确是否是–ireport-home选项).

根据需要Boolean型选项可能被指定用缩写型–opzione和扩展型–opzione=true–opzione=false

以下命令可以得到命令选项的列表:

iReport.bat -?

./iReport.sh -?

以下的表格能解释不同的有效选项,它引用0.4.1版本,可能不能完成所有连续的版本。

Option

Description

-config-file < filename>

指定一个配置文件的文件名。 这个文件不会修改ireport,他将保存一个最终修改后的配置到规范性的目录,用户主目录/.ireport

-ireport-home <dir>

指定程序目录。

-temp-dir <dir>

指定一个存储临时性文件的目录。

-user-home <dir>

指定用户目录。默认的是系统的根目录。

-version

用这项可以立即打印出iReport的版本信息。

表格2.2

如果Ant被使用,它就不可能指定这些选项立即执行从命令行,但是它却是必须的,可以修改build.xml文件来达到,可添加<arg>标签有利于java任务在iReport运行时。

 

3 JasperReports基础概念

JasperReports

iReport的核心就是一个开源的JasperReports库,它是由一个罗马的叫TeodorDanciu的开发者开发。是目前最有利于创建分布式和强有力的报表的免费软件库。这章我们就来阐述一下JasperReports的基础概念来加深我们对iReport工作流程的理解。

JasperReports API, 为报表定义的XML结构语法,以及在我们程序中需要用的库的详细资料都归档在这本名叫“The JasperReports Ultimate Guide.”的手册中。这本书非常的超值。(目前标价35$).其他可以直接利用的信息和例子可以到官方网站:  http://jasperreports.sourceforge.net.

两者不相同的是,iReport的分布式依照GPL规范,而JasperReports依照LGPL规范,因此它的局限性很小。这就意味着JasperReports能够被随意应用于商业,不用购买昂贵的软件许可或呆在家里从网上搜索复杂的开源的许可。这是用iReport创建一个被用做商品报表的基本原则,事实上,程序仅仅需要用JasperReports库来打印出报表来,仅仅在程序运行时用到它。由于没有完整的商业许可(指需求以外的许可),iReport只能作为一种开发工具,也不可能成为一个不符合GPL分布式标准的程序的一部分。

报表生命周期:

报表的生命周期和java类的生命周期非常的相似。Java被一些源文件来组成,也就是它可以依照它的语言规则进行自身的扩展,编写。这些源代码被编译器编译成扩展名为class的文件。可以通过接口来实例化或直接加载到内存中调用;执行期间这些属性将被加强。

同样的,一个报表也是由一个源代码的文件来描述,这个源文件就是由DTD(jasperreport.dtd, version 0.6.3is listed in Appendix B)来定义的XML标记。在0.5.3版本中它的源文件扩展名变成了.jrxml(例如:JasperReportsXML); 取代了一般的.xml扩展名。报表的源代码被编译成jasper文件(扩展名是.jasper)。jasper文件是一种预报表,严密的说就像是java的类被封状成的对象。Jasper文件通过你的应用程序来加载。它被添加一个数据源的标记从而创建报表,接着它就能以你想要的格式输出(例如:pdf或xls)。

因此它可以被定义成两种截然不同的动作:一个是用于执行在开发期间(设计和编写一个报表,编辑一个jasper源文件),另一个是用于执行在运行期间、

(加载开发期间的jasper文件生成报表)。

Jrxml源代码和jasper文件:

已经解释过,一个报表就由一个被创建的DTD文件定义的XML文件 (jasperreport.dtd)。这个源文件是由一系列的片段定义,这些片段就是一些关于报表的物理特性,像这个页面的尺寸,版面的布置,以及版块的高度等等;还有一些逻辑上的特性,像参数,变量,一个为得到被选择的数据的查询的定义等等

简单的说,这个jrxml源代码包含的片段就是下面这些:

Report main characteristics

Property (0,+)

Import (0,+)

Global font (0,+)

Parameters (0,+)

SQL query (0,1)

Fields (0,+)

Variables (0,+)

Groups (0,+)

Group header

Group header elements (0,+)

Group footer

Group footer elements (0,+)

Predefined bands

Predefined bands elements

jrxml文件例子:

 

<?xml version="1.0"encoding="ISO-8859-1" ?>

<!-- Created with iReport - A designerfor JasperReports -->

<!DOCTYPE jasperReport PUBLIC"//JasperReports//DTD Report Design//EN"

"http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">

<jasperReport

name="untitled_report_1"

columnCount="2"

printOrder="Vertical"

orientation="Portrait"

pageWidth="595"

pageHeight="842"

columnWidth="266"

columnSpacing="0"

leftMargin="30"

rightMargin="30"

topMargin="20"

bottomMargin="20"

whenNoDataType="NoPages"

isTitleNewPage="false"

isSummaryNewPage="false">

<property name="ireport.scriptlethandling"value="2" />

<queryString><![CDATA[select *from customers]]></queryString>

<field name="CUSTOMERID"class="java.lang.String"/>

<field name="COMPANYNAME"class="java.lang.String"/>

<background>

<band height="0"isSplitAllowed="true" >

</band>

</background>

<title>

<band height="46"isSplitAllowed="true" >

<staticText>

<reportElement

mode="Opaque"

x="145"

y="6"

width="245"

height="34"

forecolor="#000000"

backcolor="#FFFFFF"

key="element-1"

stretchType="NoStretch"

positionType="FixRelativeToTop"

isPrintRepeatedValues="true"

isRemoveLineWhenBlank="false"

isPrintInFirstWholeBand="false"

isPrintWhenDetailOverflows="false"/>

<textElementtextAlignment="Center"

verticalAlignment="Top"rotation="None" lineSpacing="Single">

<font fontName="Arial"

pdfFontName="Helvetica"size="24" isBold="false" isItalic="false"

isUnderline="false" isPdfEmbedded="false" pdfEncoding ="Cp1252"

isStrikeThrough="false" />

</textElement>

<text><![CDATA[This is thetitle]]></text>

</staticText>

</band>

</title>

<pageHeader>

<band height="0"isSplitAllowed="true" >

</band>

</pageHeader>

<columnHeader>

<band height="0"isSplitAllowed="true" >

</band>

</columnHeader>

<detail>

<band height="19"isSplitAllowed="true" >

<textFieldisStretchWithOverflow="false"

pattern="" isBlankWhenNull="false"evaluationTime="Now" hyperlinkType="None" >

<reportElement

mode="Opaque"

x="1"

y="1"

width="264"

height="18"

forecolor="#000000"

backcolor="#FFFFFF"

key="element-2"

stretchType="NoStretch"

positionType="FixRelativeToTop"

isPrintRepeatedValues="true"

isRemoveLineWhenBlank="false"

isPrintInFirstWholeBand="false"

isPrintWhenDetailOverflows="false"/>

<textElementtextAlignment="Left"

verticalAlignment="Top"rotation="None" lineSpacing="Single">

<font fontName="Arial"

pdfFontName="Helvetica"size="10" isBold="false" isItalic="false"

isUnderline="false" isPdfEmbedded="false" pdfEncoding ="Cp1252"

isStrikeThrough="false" />

</textElement>

<textFieldExpression

class="java.lang.String"><![CDATA[$F{COMPANYNAME}]]></textFieldExpression>

</textField>

</band>

</detail>

<columnFooter>

<band height="0"isSplitAllowed="true" >

</band>

</columnFooter>

<pageFooter>

<band height="0"isSplitAllowed="true" >

</band>

</pageFooter>

<summary>

<band height="0"isSplitAllowed="true" >

</band>

</summary>

</jasperReport>

清单3.1

图3.1展示了清单3.1打印出来的结果。其实清单3.1是iReport的加长型,它比我们需要的太长拉。这是因为iReport不能生成精短的代码(例:不能一些具有缺省值的属性)。

图3.1

不管如何减少XML代码,也无法改变报表的最终结果和生成速度。

在编辑(通过一些JasperReport类来实现)jrxml文件期间,这个xml文件被分解加载为JRBaseReport对象。JRBaseReport一个丰富的数据结构,可以将xml的内容精确的放到内存中。所有的解析表达式被加载,生成它相应java类文件。这些类继承JRCalculator,依靠普通java编译器编译成的这些类被加载为缓冲字节。开始初始化JRBaseReport,一个JasperReport类(继承JRBaseReport类)被实例化,先前的JRCalculator类缓冲字节被存储在新类的compileData区域。从而获得的JasperReport类连续的写进jasper文件,并随时准备被加载。

JasperReports的速度取决于实际情况,所有的报表规则被编辑到java的本地字节码中。报表的结构在编辑时被检验,而不是在运行时。

数据源和打印格式:

 通过其他方式提供数据来完成打印是不可能的,这些最经久耐用,吸引人的报表是没有意义的。Without thepossibility of filling a print through some dynamically supplied data,the most sophisticated and appealing report would beuseless.

JasperReports 允许通过两种不同的方法来提供指定的数据来打印:通过参数和数据源,这主要依赖一个普通的接口JRDataSource.

图3.2

一整章的内容都是关于datasources,哪儿将解释它如何应用在iReport中和如何能定义一个符合常规的datasources。(为了能提供一个准确的JasperReports)。JRDataSource能读取一组被整理在表格中的记录体(行和列)。

JasperReports可能被报表用任何地方,来代替一个直接的datasources,一个JDBC(已经举过例子)能连接任何一个关系型数据库,对指定的一个报表执行sql查询。 如果数据(通过datasources)不足够,或者它需要指定特定的值完成执行,它将很有可能产生一些名值对传送给打印机。这些对被叫做parameters(参数),他们可以被预先性的传给报表。通过fillManager能够加入一个jasper文件和datasource在一个 JasperPrint 对象。 通过实现JRExporter接口的类这个对象能够创建一个真实的打印以你所期望的格式输出。

JasperReports 可以由你做主来选择不同格式的输出,用来创建pdf,xls,cvs,xml,html,等文件。通过JRViewer类能够直接打印你屏幕上所看到。

 

版本兼容性:

 当一个新的版本的JasperReport被发布,通常一些类会有所改变。这些改进的类特意地定义报表的结构。所以为了避免在编译报表时因用了不同的库而产生的冲突,JasperReport使每个编译过的jasper文件具有联系性,可以精确的判别库版本并使用老版本进行编辑。如果你执行一个打印加载一个jasper文件,它不同于老版本支持的文件,就会产生一个错误。可能是这种情况:

java.io.InvalidClassException:

net.sf.jasperreports.engine.base.JRBaseReport;local class

incompatible: stream classdescserialVersionUID = 406, local class

serialVersionUID = 600

net.sf.jasperreports.engine.JRException:Error loading object from

InputStream

Caused by: java.io.InvalidClassException:

net.sf.jasperreports.engine.base.JRBaseReport;local class

incompatible: stream classdescserialVersionUID = 406, local class

serialVersionUID = 600

然而,老的报表源可能被编译用新版本的库,这个源代码被第一次编译:这是因为锌版本的通常仅仅传入新的标签但又不是必须的,并没有修改XML通常的结构。

移植一个JasperReports到下一个版本下完全可以的。它能够很快的被执行由于一个叫massive compiler 的iReport插件,它能够编辑所有在同一目录结构下的报表,能安全的拷贝已经现有的jasper文件。

我们将讨论massive compiler 在插件章节。

表达式:

所有的JasperReports的规则被定义通过表达式。一个表达式符合java语法,即有一个对象和结果。

表达式的例子:

• “This is anexpression”

• new Boolean(true)

• new Integer(3)

• (($P{MyParam}.equals(“S”))? “Yes” : “No”)

无效的表达式例子:

• 3 + 2 * 5

• true

• (($P{MyParam} == 1)? “Yes” : “No”)

详细的查看第一个和第二个例子都是无效的,因为他们都是简单类型(int 在第一个事例,boolean在第二个事例)。第三个表达式也无效的,因为采取MyParam参数(之后我们将定义为$P{...}格式) 是一个简单类型,它能被比较通过==和一个int型,但结果不是true。

表达式返回的类型是由上下文决定的。举个例子如果一个表达式恰好终止当一个元素被打印之后,这个返回类型将是boolean型。同样地,如果我写一个加了下划线的number型字段,返回类型就是Integer或Double。

在表达式中我提到了参数,变量和字段,报表定义的语法概要:

Syntax

Description

$F{name_field}

指定字段名 (F means Field)

$V{name_variable}

指定变量名

$P{name_parameter}

指定参数名

$P!{name_parameter}

这是一种特殊的格式,是报表查询的一部分,这个参数肯定不会负一个值传递给预编译语句,但它是这个查询的一部分。

表3.2

字段,变量,参数永远作为一个对象(他们可以负null值),他们的类型在被声明时被指定。JasperReports0.6.2版本以后,出现了一个新类型$R{name_resource}结构。它被用做字符串的本地化。(我们将在国际化那章来讨论)

通常定义一个返回对象用一个表达式是不够的。例如:如果你想打印一个罗马字体的数字,或者用一个特别的数据代替周日,就可能要将详细的细节传给一个外部类方法,这个方法应该声明为staitic,例如:

MyFormatter.toRomanNumber( $F{MyInteger}.intValue() )

toRomanNumber 是 MyFormatter 类的静态方法,带有唯一的int型参数并传回这个罗马版的数字in a lace。

很多地方都用到这个技巧,比如推断出一个CLOB区域的文本内容,或者添加一个值到HashMap参数中。这种操作就不能依靠简单的表达式。

一个简单的程序:

我们用一个简单的程序(清单3.2)来完成这章关于JasperReports提出的介绍。这段代码将展示如何由一个jasper文件生成一个pdf文件,这里用一个特殊的datasourcesJREmptyDataSource. JREmptyDataSource 是一种空的datasources。我们引用test.jasper文件(清单3.1)来进行编译。

import net.sf.jasperreports.engine.*;

importnet.sf.jasperreports.engine.export.*;

import java.util.*;

public class JasperTest

{

public static void main(String[] args)

{

String fileName ="/devel/examples/test.jasper";

String outFileName ="/devel/examples/test.pdf";

HashMap hm = new HashMap();

try

{

JasperPrintprint = JasperFillManager.fillReport(

fileName,

hm,

new JREmptyDataSource());

JRExporter exporter = new

net.sf.jasperreports.engine.export.JRPdfExporter();

exporter.setParameter(

JRExporterParameter.OUTPUT_FILE_NAME,

outFileName);

exporter.setParameter(

JRExporterParameter.JASPER_PRINT,print);

exporter.exportReport();

System.out.println("Created file:" + outFileName);

}

catch (JRException e)

{

e.printStackTrace();

System.exit(1);

}

catch (Exception e)

{

e.printStackTrace();

System.exit(1);

}

清单3.2

 

4 报表结构

这章我们将分析报表的构成,来观察一下它由那几部分构成,当用数据打印时这几部分是如何运转的。

Bands

一个报表依靠“type”页来定义说明。它被分成不同水平的一份被叫做bands。当报表加入数据去打印时,这些部分被印刷很多次依照他们自身的属性(依照报表创建者设计的规则)。举个例子,page header 被重复的打印在每页的开始部分,这样的话,每个band都会重复的打印每一单一的记录。

这个 “type” 页被分成9个预先确定的bands作为新组被加进去。事实上,iReport控制每一个头条(Group header)和一个摘要条(Group footer)为每一个组。

图4.1

一个带总是和页的宽度一样(左右的空白除外)然而它的高度,即使已经被设计好,但可能还会依据被包含在内的元素的实际来打印;它能够自由的延长靠近页底。这种特色的出现在bands包含一个subreports或者text field时纵向的内容。通常情况下,bands的高度被用户指定一个“minimal height”。不是所有的bands能依照内容被这个外力改变,特别是:Column Footer,Page Footer 和 Last Page Footer.所有的band高度的总和(除了background)总是小于或等于页的top和bottome之间的最小高度。

Title

这是首先看到的band。它被创建仅仅一次,可能被打印在每一分开的页。耍点小聪明,你能利用这个模拟一个无效的subreports(随后我将看看如何做)。关于尺度的确认,它是不可能躲过去的,在报表页的高度设计期间。As regards the admitted dimensions, it is not possible toexceed,

during design time, thereport page height (包含top和bottome标记之间)。如果title被打印在几张单独的页面上,这个band的高度不用被包括在整个band的高度之内的,一般低与page的高度。

Page header

这个band允许你设计一个page的header。它的高度在设计阶段被定义,通常不会改变在创建报表的过程中(除非有垂直插入相当大的成分,例如这个textfields包含很长的文本和subreports)。页面的header出现在整个打印页的相同位置在设计阶段期间。Title和Summarybands不包括pageheader 在打印一个单独的页时。

Column header

这个band在每一个详细的列开始时被打印。这column的概念一会儿再结实。通常的,包含标签的tabular报表的列的名字被插入在这里。

Group header

一个报表能容纳零个到多个group bands,它允许收藏详细的记录在不动groups。有groupheader ,自然要有group footer(他们能能独立的展现和取消)。不同的属性被联合在一个group。他们确定他们的行为功过查看graphic point。它是可能的影响一个新的页的group header或者一个newcolumn,打印这个band在整个页的下面,如果这个bands超出了一个单独的页(以一个组的级别作为一个pageheader)。它 是可能的去修改被请求的高度并打印它:如果它是超过其他的高度,这个group将被打印在一个新的page(特别要注意它的值由于太长,在打印时会无限的循环),等等。接下来我们将详细讨论groups。

Detail

Detail band 将每个通过datasources读到记录响应的传给打印机。很可能,大多数的元素都被放在这里。

Group footer

这个band表示一个group的结束。通常它包含的区域显示小计或者分开图解元素,作为一条线,等等。

Column footer

这个band的出现表示每一个column的结束。它的尺寸是不能被调整的(即使它包含一个相当大的元素,像subreports或者文本域)。

Page footer

这是页脚。它和page header同时出现在每页。同column footer一样,他是不足够大的。

Last Page footer

如果你想使最后一页的footer与其他的页的footers不一样,这时可能就要用到这个band。如果这个band的高度是0,他将被完全的忽视,其他确定结构的普通页也能适用在最后一页。它首次出现在JasperReports的0.6.2版本。

Summary

在其他的地方这个组名被叫做report footer。它允许你在report的最后插入你想要的任何内容关于总结等。

Background

Band第一次出现在JasperReport0.4.6版本时。它由于许多用户的坚持不懈的要求能够创建水印和similar effects而引入 (整个页面的结构). 它可以具有最大的高度以至于和页面高度一样。

报表属性:

现在我们已经看过报表的单个部分,我们将继续创建一个新的报表。按菜单上的这个按钮选择New Document:打开一个窗口。在这里填写报表的属性(图4.2)。这个窗口可以随时打开通过view菜单的Reportproperties。

图4.2

报表的名字是第一个属性。这个名字是本地命名,它和源文件的名字是相互独立的,它仅仅被JasperReports library 调用(例如:命名一个报表编译后的java文件)。

页面的尺寸大概是报表最重要的属性。一系列报表的尺寸标准被提议。iReport 和 JasperReports使用的最小量度单位是像素。(像素大小是75点每英寸,每英寸的点数)。

然而,我们经常使用的报表的量度单位更为平常,像厘米,英寸或毫米。

表4.1列出了量度标准和像素大小。由于尺寸管理基于像素,所以当我们用不同的量度看同一数据会发生很大改动。

Page type

Dimensions in pixel(像素)

LETTER

612 x 792

NOTE

540 x 720

LEGAL

612 x 1008

A0

2380 x 3368

A1

1684 x 2380

A2

1190 x 1684

A3

842 x 1190

A4

595 x 842

A5

421 x 595

A6

297 x 421

A7

210 x 297

A8

148 x 210

A9

105 x 148

A10

74 x 105

B0

2836 x 4008

B1

2004 x 2836

B2

1418 x 2004

B3

1002 x 1418

B4

709 x 1002

B5

501 x 709

ARCH_E

2592 x 3456

ARCH_D

1728 x 2592

ARCH_C

1296 x 1728

ARCH_B

864 x 1296

ARCH_A

648 x 864

FLSA

612 x 936

FLSE

612 x 936

HALFLETTER

396 x 612

_11X17

792 x 1224

LEDGER

1224 x 792

表4.1

通过修改高度和宽度,你就可以创建任意大小的报表。报表页的定位有landscape和portrait选项,事实上这并没有太大的意义,因为报表页是由宽和高来刻画它的尺度的,并且每个单页都是相互独立。然而这个属性可以别用来确定报表的输出。

页面的空白尺寸依赖于Margin选项卡的四个输入值来确定。

像你看到的那样,一个报表页被几条平行线分开为几部分:bands。这个选项页是用来排版报表的,现在的这部分具有独立的数据(像title片段,或者page footers),和其他的片段一样被打印根据数据记录的不同从零开始(像groupheaders和detail)。这个选项页的最后一个属性值能分开垂直的列为了利用报表页中可利用的空间。

上下文中的column的概念很容易被”field”搞混。事实上,column和记录集是没有关系的,只和detail band有关系。意思就是说一条记录用十个fields和一个表的话,不需要十列。然而,这些元素可以用table实现恰当的放置。十列将导致一个很长的记录列(非常狭窄的横条)被打印。下面的例子将告诉你怎样设置值为一个简单的列报表在A4纸上。

图4.3

Columns的值是1,它的宽度和整个页面一样,除了空白。列之间的空间没有意义,所以它的值是0。

 

图4.4                                                             图4.5

看4.5图,这个页的大部分没有被使用,如果使用大量的列,这个报表看起来会好看一些。图4.6展示了两列报表的尺寸大小。

图4.6

既然这样,在这个“columns“,我们输入2。iReport将自动的计算列的宽度依照页的空白和宽度。如果你想在两列之间插入空白,那就为”spacing”填写一个值。

像4.8图中看到的,这个页面的空白有被更好的利用。

滥用列的话可能将打印一个非常长列(像一个电话本一样)。总之,当detail band和连续的bands出现超过一列的宽度空白时你要记住使用列来减少宽度。所有的空白,列的宽度和每列之间的空白,加起来要小于页的宽度。如果不检验这种情形的话可能导致错误产生。

图4.7                                                             图4.8

在图4.5和4.7中页面上有用区域设置报表的元素(像fields,images等等)。这部分是不可利用的,像空白和第一列余下的空白。The parts whichare not utilizable, such as margins and columns following the first one (whichhave to be considered like the continuation of this one) are highlighted ingrey.

高级选项:

以上我们看到的仅仅是基础关于设计的基础设置。现在我们将看一些高级选项。其中一些将被彻底的检查和粉肠详细的解释在以下章节,如果要想完全的理解和应用,那就要在努力学习JasperReports的用法一直到精通。

脚本:

脚本是一个java类,它的方法执行在报表生成期间,通过触发一个特殊的事件,像一个新页的开始,一个group的结束等。我们常常可以看到那些生动的工具图片,像MS Access 或 MS Excel,脚本就相当于一个module,是一些程序和特殊的事件的关联或可返回的功能,在报表的上下文被插入。(例如text field的表达式)

将有一个章节全部用来讲解脚本。在scriptlet选项卡(图4.9),可以指定一个外部的脚本(java类)或激活iReport的内部脚本支持。

图4.9

如果你不想使用脚本,那就设置下拉菜单的值为:Don’t use scriptlet class…或者在输入区域填写你所要使用的类的名字。

更多…

在”more..”选项卡(图4.10)可以对打印进行设置。

图4.10

Titleon a new page选项:

Title指定为一个新页的选项,打印在每页的开始,在title之后页面将发生大的变化。图4.12和4.13展示报表的结果,图4.11显示报表。

图4.11

Title被打印总是一样的,而且在每页的顶部。

图4.12显示使用缺省设置打印的结果:

图4.12

图4.13显示打印的结果如果“title on a newpage “选项设置为true。Figure 4.13 shows the print result withthe “Title on a new page” option set totrue.

像你看到那样,没有一行其他的band被打印在title页,甚至没有page header或page footer。然而这页仍然计算这页的总数。

图4.13

Summaryon a new page选项:

这个选项完全和先前的选项一样,只是summary band被打印在最后一页。现在,如果你选择了这项,那新页将包含summaryband。

Floating columnfooter 选项:

这个选项允许你加强column footer band的打印,直接在最后detail band(或groupfooter)后显示而不不在column后显示。当你想用报表元素创建表格时使用这个选项。 (详细请看JasperReports tables.jrxml)

打印顺序:

Print order用来决定如何组织打印多列数据。缺省的printorder一是vertical,它是垂直的打印记录直到页末开始打印新的一列。 (就像报纸或电话本一样) 。Horizontal print orderprints 以横向打印记录当一行占据页宽后开始打印另一行。图4.14和4.15:

图4.14                                                           图4.15

这两个图清晰的显示这个两个选项的概念。如你看到的,每个名字按字母的顺序打印。图4.14显示了纵向的打印(第一列打印完接着打印第二列),图4.15显示了横向的打印(打印完所有的行显示出整个列)

无数据打印(如果没有数据时):

当提供一个空的数据打印时(或者sql查询没有返回记录) 一个空文件被创建(或返回是一个零字节长度的流)。这个缺省的行为能被修改通过指定其他的,在没有数据时。(指when no data)。表4.2概述了可能的值和意义。

Option

Description

NoPages

缺省值,最后的结果为空。

BlankPage

返回一个空白页。

AllSectionsNoDetails

返回整个页的组成,出了detail band

表4.2

i18n:

il8n选项卡用来设置片段的参数。

Resource Bundle Basename

Resource Bundle base name 是一个参数名,当你想使报表国际化时。ResourceBundle 包含用在报表中的标签,句子,表达式翻译文本以指定的语言。这个语言符合一个特殊的文件。base name

表示文件名,能帮助你找到这个文件用正确翻译。为了用精确的语言来重建文件名,一些language/country首位字母大写(e.g._it_IT,forItalian-Italy)和.properties扩展名作为前缀。我们将解释国际化在11章。

XML源文件的编码设置:

保存源文件的缺省编码格式是UTF-8. 然而,如果你想用一些你需要的XML编码格式,你就需要指定正确的charset(UTF-8)。

The UTF-8 manages allaccented letters and the euro. 其他常用的可以选择编码格式列表(“ISO-8859-1” 广泛应用于欧洲).

5 报表元素

这章我们将解释报表的主要对象和他们的特性。

这里的”element”就是一些图形对象,像一些文本或长方形。不同于字处理机那样,在iReport那段的概念中,表和分页符将不存在;任何东西被创建借助于elements,包括文字,当他们排成一行时就创建了表格,等等。这些相近的被大多数报表工具所采用。

“basic”元素中有7个由JasperReports提供:

- Line

- Rectangle(长方形)

- Ellipse

- Static text

- Text field (or simplyField)

- Image

- Subreport

通过这些元素的结合,能够创建任何一种报表。

除了这些之外,iReport还提供了两种特殊的基于象元的元素:chart(图表)和barcode(条形码)。

每种元素都有一些普通的属性,像高,宽,位置,band应该被放的位置和其他特殊的属性(例如:字体,在长方形的情况时,border的厚度)。它可能分为两个大的类别的组:图形元素(像:line,rectangle,ellipse,image)和文本区域(labels和textfield)。

子报表代表一种独立的元素,因为他使用起来很复杂,我也将接触他们在一个单独的章节。

这些元素被插入bands。特别是每一元素都不能合放在一个band中。如果这些元素不能被完整包含在band中,报表编译器将返回一个错误信息,关于元素的错误的姿态;不管怎么样,报表都将被编译,甚至是更糟糕的情况,但”out of band”将不能被打印出来。

选择并插入元素到报表中:

为了添加元素到报表中,选择(图5.1)工具条上目前显示的工具

表格5.1

取向工具被用来对这些元素做更重要操作和一些常用的工具。当你想插入一个元素时,点鼠标左键在你想插入元素的地方向下拖拽鼠标来画一个合适的长方形。当松开鼠标时,一个新的元素将被自动的选择和创建。这个新的元素也将在iReport面板的右边的元素浏览(elementsbrowser)中出现。

图5.1

双击鼠标右键或者选择菜单ViewElement Properties, it 能够打开元素的属性窗口(图5.2)。

图5.2

这个窗口是有组织的几个选项卡。This window is organized in severl tabs. The “Common” tab 选项卡包含了每一种元素的通用的属性,其他的选项卡是每一种元素单个的属性。

能够选种多个元素在同一时间功过取选工具和画一个长方形将你要选择的元素包含在内。被选择的区域会显示一个粉红色的长方形框。

或者,选中一个或多个元素在同一时间,通过按“Shift”键用鼠标点中你已经插入的元素。

选种一个元素时将在该元素长方形的每个角显示兰色的小方框(图5.4),当选择多个元素时该元素长方形的每个角显示灰色的小方框。(图5.5)

                        

图5.3                     图5.4                         图5.5

多重选择中的第一个元素作为主要的选择。.

为了能够调整元素的大小,可以移动鼠标的光标到长方形的边上或拐角处:点并拖拽来安排你想要的尺寸。为了更小心的调整,可以在元素的属性框的特别选项卡中填写合适的尺寸。如果同时选择了多个元素,一个元素的调整会调整所有的元素。

此外,你也可以用放大报表,通过使用工具条上的zoom工具(图5.6):

图5.6

你可以在选择框中选择百分比(图5.6)或者直接写一个你想要的值(明确一下,字符后使用’%’号)。

警告:在调整元素期间,必须注意使用整数(像1x,2x,3x,等)来避免近似值的错误!

布置和元素顺序

一个元素可以通过鼠标来移动:通过点这个元素,选中后可以进行拖拽到任意你想要的位置。为了能够最大化的提高移动的准确度,你可以用方向键进行移动,一次移动一个像素。同样的操作,你可以完成通过按shift键,将引起这个元素十个像素的移动。

.即使移动时有一点阻碍,也可以破坏掉这个元素的阻碍,可以选择菜单EditDisable elements mouse move.

菜单可以ViewShow grid查看不同元素的位置,通过格栅作为参考。也可以插入一个动作,通过菜单EditSnap去对起格线。

图5.7

随着越多元素组织进报表,可能就要用到几个工具,这些工具可以从这两个菜单format和contextual中找到,可以按右键查看选择插入元素。更多的官能性需要选择更多的元素。在这种情况下,基本元素被作为做作的参考。表5.2是对官能性的总结。

Operation

Description

Sel.

mult.

Align left(左对齐)

校正基本元素的左边

Align right(右对齐)

校正基本元素的右边

Align top

校正基本元素的上边(或者上部分)

Align bottom

校正基本元素的底边

Align vertical axis

校正被选中元素的水平中心

Align horizontal axis

校正被选中元素的垂直中心

Align to band top

设置最高值为0

 

Align to band bottom

尽可能的放置元素在属于他的底边的band.

 

Same width

设置被选择元素的宽度为一样

Same width (max)

设置被选择元素的宽度都为最大宽度

Same width (min)

设置被选择元素的宽度的最窄值

Same height

设置被选择的元素的高度等于基本元素的高度

Same height (max)

设置被选元素的高度等于最高元素的高度

Same height (min)

设置被选元素的高度等于最矮元素的高度

Same size

设置被选元素规格为基本元素

Center horizontally(水平居中)

(band based)

设置被选元素水平居中

 

Center vertically(垂直居中)

(band based)

设置被选元素垂直置中

 

Center in band

字段中间

 

Center in background

整体置中

 

Join sides left

被选元素以靠最左边元素为基准,所有元素的左边相连

Join sides right

被选元素的以靠右边元素为基准,所有元素的右边相连

HS →Make equal

使被选元素之间保持一样的距离

HS →Increase(增加)

在所有元素中见插入5个像素的空白(向右移动)

HS →Decrease(减少)

在所有元素中间插入5个像素的空白(向左移动)

HS →Remove

删除水平方向的空白并向左移动元素

表格5.2

元素能够被互搭;也就是通过使用格式功能Bring to front and Send to back使元素置前或置后。zorder被给通过整齐的元素插入到报表。这个排列能被看到在元素树,这些元素被查看在每一个band从最矮到最高的。

我们说过,一个元素已经被连接到所属的band。如果这个元素的一部分或全部超出band,它将会出现一个红色的高亮框架显示(仅仅为text元素),这个位置可能就是无效的。其他元素,这个错误位置被高亮显示在元素树或者被选择的元素上用一个红色的拐角。

图5.8

 如果一个元素的部分遮掩了其他元素,这个拐角用绿色高亮显示;但如果一个元素的全部遮掩了其他元素,这个拐角用粉红色高亮显示。

图5.9

移动一个元素从一个band到另一个band,iReport可以自动改变所属的band。去指定不同的band,需要用属性窗口的第一个复选框(图5.9)。

如果两个或更多个元素被选择,那么属性窗口将只显示公共属性,如果这些属性值是不同的,将显示空值(使用的字段被显示空白)。具体的值为特殊属性,将适用于所有被选择的元素。

使用元素树管理元素:

元素树能够容易和精确地局部地选中报表元素。

图5.10

这里报表的外型是一个属性结构:主节是bands(使用一个文件夹表示),进到band里面是元素符号,名字和坐标能被看到,他们也被置于band中。

双击一个你选择的元素,将打开该对象的属性窗口。也可以通过鼠标右键属性菜单打开。再往后常用的功能就复制和粘贴,这儿有两个特殊的功能,move up and move down, 意思就是说可以修改一个元素在具体band中的z-border.

图5.11

如果选择了band的名字,可以右键属性进行对band 属性的操作。(图 5.11).

所有的band的特征将在第8章被解释。

基本属性:

所有的元素都有公共的属性在属性窗口“common”的选项卡 (图 5.2).主要关系到元素在页面上的位置:以下对不同属性的描写。

并列和同等规格的总是被确定为72个像素大小。

Band  指元素所属的band。所有的元素只属于一个band,一个band总联系着这个元素。元素的安放总是在band中。

Top   所属band的元素的上边到band顶部的距离

Left   从band左边到元素右上角的距离

Width  指元素的宽度s the element width;

Height 指元素的高;它实际上的值是根据打印时真实值的高度来确定

表格5.3

Foreground   指文本被打印的颜色和元素的线和拐角被画的颜色。

Background   指元素背景填充色

Transparent   这个选项表示元素为透明的,透明的元素的部分应该被背景色填充。

警告:不是所有的输出格式都支持透明的。

 

Remove LineWhen Blank  This 这个选项允许拿走垂直空间占有的对象,如果不太明显,这个元素option allowsto take away the vertical space

occupied by an object, if this is notvisible; the element visibility is

determined by the value of theexpression contained in the Print

WhenExpression attribute; thinking about the page as agrid where

the elements are put, the line whichthe element occupies, is that

where it is put;

表格5.4

表格5.3加亮元素的一条线;为了真正的删除这条线,所有的元素占有仅仅一部分线,有null值的地方 (没有被打印出来);

Print in first whole band   这个选项保证当元素值溢出时被打印在下一页或下一列;这个保证被使用当Print repeated values是不活跃时

Print when detail overflows   这个选项允许打印元素以页或列,如果band不能被打印当前的列或页

Print repeated values this  这个选项决定时候打印元素,当该元素的值与前一条记录值一样时

Positiontype   在band被改变的情况下确定顶部的坐标。三个可能的值是:

- FixRelativeToTop   预先定义位置类型;这个坐标从来不改变的。

- Float   元素进一步的向底边增加他们的高度,依据前一个元素的高度

- FixRelativeToBottom  元素维持其到底边的距离的常量值;被用做单独记录的分割线。

Print when group changes   所有的报表的组被显示在这个下拉框中;如果他们中的一个被选择,仅当表达式改变组的时候被选择的一个将被打印,此时一个新的坏的组被选择。

Key   它是元素的名字,只有一个意义(iReport自动提出),被程序用来在运行时修改需要修改的文件的属性;

Stretchtype  这个属性用来定义详细打印期间元素的高度;可能值有以下几种::

- No stretch              预先改变类型利用元素的高度保持一直。

-RelativeToBandHeight    元素成比例的增加使band增加,用来模仿表格的垂线。

- RelativeToTallestObject  这个选项修改一个元素的高度从而改变离它最近的元素:它也被用做element group,这是一个元素组机制,但不能被iReport管理。

Print when expression it is 它是一个java表达式像那些描述在第三章,返回一个boolean对象;除了这些元素之外,这些表达式也被连接到band中。如果表达式返回true,这个元素是隐藏的。一个null值和一个新boolean(true)关联,将被无条件打印出来。

图形元素:

图形元素的画一个对象像一条线或一个长方形;他们通常不显示数据,但是他们却更多的被打印出来,从美学上看他们更有趣,通俗易懂。所有种的元素分享这个“Graphics element”选项卡在这个属性窗口:

图5.11

Pen  指你画线和框架的厚度;它可能的值是:

- None  厚度为null,表示禁止画线或边框

- Thin  线和边框的厚度最薄,但可以看的到。

- 1Point 线和边框被设置为一个像素;

- 2Point 线和边框被设置为两个像素;

- 4Point 线和边框被设置为四个像素;

- Dotted 线和边框被画用虚线;

Fill 用来修改填充背景;仅仅被允许使用fill值,完全的填充

线

在JasperReports中线被定义为长方形,有对角线的长方形。

     

图5.12               图5.13

这个线被画用Foreground色和Pen 厚度.

Linedirection it 被表示成两条对角线,可能的值是: TopDown (看图 5.13) 和BottomUp.

矩形

长方形常用在一个元素周围的边框。这个边界用一个较粗的前景色线来画的。背景被背景色填充,如果这个元素没有被定义为透明的话。

长方形的特殊性在JasperReports中会有一个rounded comers。被定义的意思的是radius属性,描绘弯曲度在你画一个拐角时,使用像素。

        

图5.14                           图5.15

椭圆

椭圆是唯一一个没有自己的属性的元素。至于长方形,它的边框也是用一个粗的颜色是前景色的线画的。背景被背景色填充如果这个元素没有被定义为transparent。椭圆被画在长方形内切边与长方形的四条边相切。

图5.16

图象

图象是最复杂的图形对象。可以使用raster images

(像GIF,PNG, JPEG, etc...) 插入到报表中,但它也能被使用作为一个 canvas

对象,, 你可以画一种箱子:这个图象元素被使用,例如,画一个图表或一个条形码。

 

图5.17                                图5.18

可以使用自己写的类使用net.sf.jasperreports.engine.JRRenderable 接口。一个文本连接(“Hyper Link” tab)能够关联到一个图形元素。我们将分析文本连接在这章。

图象特征可以在“Image”选项卡设置.

ImageExpression 它是一个java表达式。它的结果是一个被Image

Expression Class属性定义的对象;

Expression Classattribute; 以返回类型为理由,图象被装载改变的方式;

ImageExpression Class 表达式的返回类型。

表格5.4概述了Image Expression Class可能采用和描述Image Expression结果的解释。

Type

Interpretation

java.lang.String

一个被认为是一个文件名的字符串;JasperReports将设法解释这个字符串想一个绝对的路径;如果没发现文件,它将设法加载指定名字的源从classpath

正确的表达式是:

“c:\\devel\\ireport\\myImage.jpg”

“it/businesslogic/ireport/icons/logo.gif”

java.io.File

指定一个文件对象作为图象去加载。

正确的表达式可能是:

new java.io.File(“c:\\myImage.jpg”)

java.net.URL

指定It specifies the java.net.URL 对象。当你以html格式输出报表时使用它。

正确的表达式可能是:

New java.net.URL(“http://127.0.0.1/test.jpg”)

java.io.InputStream

指定一个准备读取的java.io.InputStream对象;既然这样我们就不能考虑图象存在或它在一个文件中:大多数我们读取一图象从数据库,返回一个inputStream。

正确的表达式可能是:

MyUtil.getInputStream(${MyField})

java.awt.Image

指定一个java.awt.Image对象;当一个图象对象被创建时大概返回一个简单的对象;

正确的表达式可能是:

MyUtil.createChart()

JRRenderable

指定一个使用

net.sf.jasperreports.engine.JRRenderable 接口的对象。

表格5.5

在这个例子中我们有解释, MyUtil 代表一个创造类。如果你想使用一个创造类通过调用一个static 方法去运行特殊的细节,就需要使用一个属于它的包(例如

it.businesslogic.ireport.util.MyUtil)或者用import(菜单Show→Import directives in the report)引用这个包。我们解释这个方法在这个例子中是static的,但当我们讨论变量时,我们将看到如何实例化一个类在打印开始时和如何使用它在表达式中。

Image Expression 中使用字段,变量和参数,它将加载或生成图象以变化的方式(像已经发生的,例如,在detail中生成一个有图象的目录,每个目录关联一个图象)

Scale Image   定义图象怎样适应元素的尺度;可能的值有三个:

- Clip 图象的尺寸不改变;

- FillFrame 图象适合元素的尺寸(变的不成型)

- RetainShape 图象适合元素的尺寸,但保持图象原来的比例

  

图5.19                      图5.20                      图5.21

Using cache this如果这个元素最近将被再打印,可以使用这个选项使图象保存在内存中以便下次使用;图象只有被Image Expression Class 设置java.lang.String 才能使用cache;

Verticalalignment  这个属性用来定义图象为垂直队列依照元素区域; 可能的值是:

- Top    图象排列在顶部;

- Middle 图象被放在垂直队列的中间在元素区域中。

- Bottom 图象被排列在底部;

Horizontalalignment 依照元素区域,图象被定义到水平队列;可能的值是:

- Left 图象排列在左边;

- Center 依照元素区域,图象排列在水平中间

- Right 图象排列在右边;

Evaluationtime  定义Image Expression被处理时的状态;事实上表达式的赋值能被做当报表引擎在创建报表时遭遇这个元素或或者也能延缓在一些特殊的案例中:例如,你想去计算一个子报表。

赋值时间是一个非常有用的功能,它将被解释在JasperReport手册中。可能的值:

- Now立即求表达式的值;

- Report 报表产生之后求表达式的值;

- Page页未求表达式的值 ;

- Column列末求表达式的值;

- Group求每组的值;

Evaluationgroup Evaluation time.

图形元素(和text元素)可以被想象成一个框架,或者可以定义它的四个边的值。

它是元素元素和内容之间的空间。边框和内容被定义在border选项卡。他们的属性被介绍在JasperReports0.6.3版本。

图5.22

可以选择元素的类型和画每条边的颜色。边框类型是:

- None,厚度为null,允许不打印出边框线;

- Thin最小厚度;

- 1Point 一个像素的厚度;

- 2Point 2个像素的厚度;

- 4Point 4个像素的厚度;

- Dotted最小厚度的虚线;

一个简单查看图形效果的方式就选择border选项卡中间的显现边框。

文本元素

和图形元素一样,文本元素也有一个允许查看的公共属性:它是font选项卡(图5.24)

图5.23

 “font” 选项卡是用来设置元素中文本的属性,所以不仅仅是字体(字符的类型和尺寸),还有文本的队列,可能的rotation和线空间。

Report font  是一个边框形式字体的名字。从这里可以设置所有字符的属性;边框形式字体可以定义报表的标准和管理他们通过选择菜单:ViewReport fonts;

Linespacing 行间距,可能的值是:

- Single 单行写如;(预先确定值predefinedvalue);

- 1_1_2 间隔一行半写入;

- Double 双倍写入;

Horizontalalign 依照元素使文本水平排列;

Verticalalign 依照元素使文本垂直排列;

Rotation 允许指定文本如何去打印,可能的值是:

- None 文本将正常的打印从左到右,从上到下;

- Left the 文本逆时针旋转90度,它被打印从底到顶,水平和垂直队列依照文本;始针4

ionports0.6.3banbe     the    旋转(例如,文本开始打印将沿这底边垂直队列画顶的界限开始);

- Right the 文本顺时针旋转90度从顶到底,垂直和水平队列依照文本旋转;

图5.24

其他的字符的字体设置将在第六章详细解释。

文本元素的属性可以用文本工具(图5.25)条来进行修改。

图5.25

静态文本

static text被用来展示非动态文本的报表。 仅仅一个参数用来区别这个元素从一个普通文本元素在static text选项卡中,指定你要看到的文本:它是一个标准的字符串,不是表达式,也不需要依照java语言的规范。

       

图5.26                         图5.27

文本域

文本区域可以打印一个java表达式的值。简单例子就是打印一个字符串(java.lang.String)来自于一个表达式想这个:“HelloWorld!”

既然这样,静态文本创建就需要很小的工作量,因为这个例子中字符串是一个不变的值;其实用java表达式去定义文本区域允许包含非常高的控制超长文本。不直接的联系文本元素(像发生在不同报表工具文本元素隐含的数据库字段的值):不同字段的记录值,是可利用的通过datasource,存储在一个名字叫fields的对象中,他们被访问依靠表达式的语法在第三章。

和图象一样,一个超文本连接可以关联textfields,可以在HyperLink中定义

        

图5.28                         图5.29

TextfieldExpression Class it指定域表达式的返回类型;可能的值有许多,包括所有的由sql类型组成和一些管理数据的类的java对象,以下表格列出了所有可选的类型的。

Type

java.lang.Object

java.lang.Boolean

java.lang.Byte

java.util.Date

java.sql.Timestamp

java.sql.Time

java.lang.Double

java.lang.Float

java.lang.Integer

java.io.InputStream

java.lang.Long

java.lang.Short

java.math.BigDecimal

java.lang.String

表格5.6

列表中包含的 java.lang.Object 类型能够在没有其他类型可以联合数据使用。

Evaluationtime 指定报表创建Textfield在那个阶段赋值;

Evluationgroup 是否赋值在一个组后

Stretchwith overflow 当它被选择时,这个选项可以垂直的改变内容,如果元素不能充分的包含在文本线内的话;

Blank when null 当域表达式返回一个null值时允许打印空白;

Pattern  指定字符串可以使用Format类,指定用Textfield Expression Class是正确的。

JasperReports能格式化日期和数字;下面的表格概述中的一些例子包括字母和他们的意义可以快速的创建日期和数字。

Letter

Date components

Examples

G

Era designator

AD

y

Year

1996; 96

M

Month in year

July; Jul; 07

w

Week in year

27

W

Week in month

2

D

Day in year

189

d

Day in month

10

F

Day of week in month

2

E

Day in week

Tuesday; Tue

a

Am/pm marker

PM

H

Hour in day (0-23)

0

k

Hour in day (1-24)

24

K

Hour in am/pm (0-11)

0

h

Hour in am/pm (1-12)

12

m

Minute in hour

30

s

Second in minute

55

S

Millisecond

978

z

Time zone

Pacific Standard Time; PST; GMT-08:00

Z

Time zone

-0800

表格5.7

这儿是一些dates和timestamp的格式例子:

Dates and Time Pattern

Result

"yyyy.MM.dd G 'at' HH:mm:ss z"

2001.07.04 AD at 12:08:56 PDT

"EEE, MMM d, ''yy"

Wed, Jul 4, '01

"h:mm a"

12:08 PM

"hh 'o''clock' a, zzzz"

12 o'clock PM, Pacific Daylight Time

"K:mm a, z"

0:08 PM, PDT

"yyyyy.MMMMM.dd GGG hh:mm aaa"

02001.July.04 AD 12:08 PM

"EEE, d MMM yyyy HH:mm:ss Z"

Wed, 4 Jul 2001 12:08:56 -0700

"yyMMddHHmmssZ"

010704120856-0700

表格:5.8

Symbol

Location

Localized?

Meaning

0

Number

Yes

阿拉伯数字

#

Number

Yes

阿拉伯数字, 0作为缺省的

.

Number

Yes

十进制或货币分割付

-

Number

Yes

负号

,

Number

Yes

分组号

E

Number

Yes

科学符号中为单独是尾数和说明Separates mantissa and exponent in scientific notation. 不需要引用像素或后缀Need not be quoted in prefix or suffix.

;

Subpattern boundary

Yes

分割正负样式Separates positive and negative subpatterns

%

Prefix or suffix

Yes

乘以100使用百分号

\u2030

Prefix or suffix

Yes

乘以1000使用每一千

¤ (\u00A4)

Prefix or suffix

No

Currency sign, replaced by currency symbol. If doubled, replaced by international currency

symbol. If present in a pattern, the monetary decimal separator is used instead of the decimal separator.

 

'

Prefix or suffix

No

引用特殊字符Used to quote special characters in a prefix or suffix, for example, "'#'#" formats 123 to "#123". To create a single quote itself, use two in a row: "#

o''clock".

表格5.9

这是一些数字格式的例子:

Dates and Time Pattern

Result

"#,##0.00"

1.234,56

"#,##0.00;(#,##0.00)"

1.234,56 (-1.234.56)

表格5.8

图5.30

通过“create”按钮可以打开样式编辑,意思就是数字,日期,流通等的简单格式

TextfieldExpression  是一个打印表达式,返回在TextfieldExpression Class;中设置的类型

 可以转变StaticTextTextfield通过选择和按F3键。

为了能快速的改变一个或更多个普通文本元素的表达式可以选择他们和按F2键。

子报表

子报表是包含在其他报表中的一个元素,由一个jasper文件和在子报表的属性中被指定的datasource提供数据开始创建。

以下是关于子报表特征的一些简要插图。由于这个子栏目的复杂性,我们将在另一章详细解释。

图5.31

 

图5.32                                    图5.33

Parameters Map Expression 定义一个运行时赋值的表达式;这个表达式必须返回java.util.Map;这个map中包含一些名值对,这些名值对将被传递给子报表作为参数值;

Connection/Datasource expression 定义一个返回JDBC连接或JRDataSource用来填充子报表;

Using cache保存或不保存数据到内存,以便能快速的加载数据再下一次;

Subreport expression  定义一个在运行时返回Subreport expression class对象的表达式。依照返回类型,表达式被赋值为了恢复用来生成子报表的jasper对象;

Subreport parameters this 这个表可以定义一些使用适当的表达式动态提供的名值对给子报表;

专用元素

除了JasperReports提供的原始的元素外, iReport提供两个”合成”元素为他们的普通属性和补偿使用图形元素。

图表

所有关于图表的信息查看14章。

条形码

这个元素可以创建一个动态的条形码形式的值。

 

图5.34                 图5.35

指定打印条形码的类型。

可能的值列表在表格5.9

Barcode types

2of7

3of9

Bookland

Codabar

Code128

Code128A

Code128B

Code128C

Code39

EAN128

EAN13

GlobalTradeItemNumber

Int2of5

Int2of5

Monarch

NW7

PDF417

SCC14ShippingCode

ShipmentIdentificationNumber

SSCC18

Std2of5

Std2of5

UCC128

UPCA

USD3

USD4

USPS

表格5.9

Checksum it specifies the code 控制条形码是否被打印指定的代码;这个特征仅仅被条形码的一些类型提供;

Show text指定是否打印文本 ;

BarcodeExpression 指定以来于条形码的表达式的值;总是返回string类型的值;

Evaluationtime e Evaluation group 和图形元素的意思一样;

超连接

图形和文本域元素都能被用做一个anchor(锚)在文档中,作为超连接指向源或其他本地的anchor(锚)。锚是一种特殊的“标签”用来识别文档中特殊的位置。

超连接和锚可以通过Hyper Link(图5.35)选项卡来定义。这是分开的两部分。上部分是一个文本域,这里可以指定这个锚的名字。这个名字可以被其他的连接引用。

下部分是定义连接的源或文档中的位置。

JasperReports 可以创建五个类型的超连接:Reference,

LocalAnchor, LocalPage,RemoteAnchor and RemotePage. 通过Hyperlink targetit 可以指定打开一个连接在当前的窗口(预先设定,目标是self(本身))或一个新的窗口(Blank target)。

警告:不是所有的输出格式支持超连接。

图5.37

Reference

The Reference 连接指出一个外部的源,一个可以被通过点URL识别的源,例如一个服务器去管理向下的记录功能。这表达式仅仅需要Hypelink Reference Expression.

LocalAnchor

点这个本地锚意思就是创建一个连接在同一文档之间。它可以被使用,例如通过一个标题的连接可以找到相应的章节。

定义一个本地锚去要指定一个能生成有效名字的Hyperlink Anchor Expression

LocalPage

如果指示代替锚,你想点一个详细的当前报表页,就需要创建一个LocalPage连接。既然这样就需要指定这个指示页的号码,意味着使用 HyperLink Page Expression (这个表达式返回一个Integer对象)。

RemoteAnchor

如果你想点一个外部的锚的细节,你就要使用RemoteAnchor 连接。既然这样你就要指定在Hyperlink Reference Expression域和指定Hyperlink Anchor Expression来命名锚

RemotePage

这个连接可以点进一个文档外部的详细页面。既然这样,这个外部文件的URL点就指定Hyperlink Reference Expression域和这页的号码将指定HyperLink Page Expression

6 字体

Fonts是描述文本的特征 (形状和尺寸)。在JasperReports中可能指定每个元素的字体属性。而且它可以定义一个名叫“report font” 的球形字,并联合他们到文本元素。这个球形字体将被包含在元素中使用。

字体

通常一个字体被定义有四个特征:

- 字体名字(字体家族)(fontfamily)

- 字体尺寸

- 属性(黑体,斜体,带下划线,barred)如果以PDF输出报表,JasperReports需要一些附加的信息:

PDF Font Name 这是预先确定的PDF文档字体的名字;

PDF Embedded   这是指定一个字体的标记,像“externalTTF”类型,

应该被包含或不包含在PDF文件。.

PDF Encoding    这是一个字符串,用来指定字符编码的名字。

如果不输出PDF格式的报表,字体使用指定的font name,强化的部分可以指定它的属性。在这种情况下的PDF文档,识别使用的字体和它的属性(黑体,斜体,等)。

其他属性是可以被忽视的,因为他们已经被包含在PDF字体中。

扩展字体

可能要使用扩展的TTF(True Type font)。为了能够使用,就必须将扩展字体(扩展名为.ttf的文件)加到CLASSPATH中:这是需要的在设计(使用iReport时)和生成(通过一个java程序,swing或servlet生成报表时)时。

警告:需要避免添加数以百计TTF到CLASSPATH中,因为可能这可能使iReport启动向下运行变的缓慢。你可以添加一个%WINDIR%\fonts目录在CLASSPATH中。

图6.1

In the 在“Font name”选择框中仅仅是系统字体,通过java虚拟机来管理,通过操作系统来展示他们。意思就是说如果你想使用扩展的TTF字体在非PDF报表中,你就需要去安装它到系统中。

安装后,在PDF Font Name选择框中选择 “External TTF Font...”。

选择框中的“True Type font”将被激活。它将在classpath中查找所有的True Type fonts引用它。

为了能在输出的PDF中正确的显示字体,需要选择“PDF Embedded”。

编码

字符编码是JasperReports中最模糊的问题之一;这个问题可能发生在打印PDF格式的报表时。所以选择一个正确编码格式是非常重要的。

编码如何指定的说明:The encoding specifies how the characters have to be interpreted: 在意大利,例如,如果你想打印合适的重音(像è, ò, a, ù,等),就需要使用CP1252编码(西方,欧洲一个ANSI标准WesternEuropean ANSI aka WinAnsi)。然而一些JVM版本不支持编码(1.4版本以前的),但他们可以使用Cp1252编码(唯一不同的是小写的”p”)。

iReport 富含预先设置的编码类型在选择框去选择。

如果你在一些不标准的PDF格式报表中有一些问题,确认所有的字段的编码类型是否一致,核实从数据库读取的报表的数据的编码设置。

使用Unicode字符

可以使用Unicode写不标准的字符(像希腊,西里尔和亚洲字符);Unicode编码可以被指定在表达式中,用来识别这些文本。例如,如果你想打印 euro符号,可以使用Unicode \u20ac字符来避免乱码。

注意:表达式\u20ac不是简单字符串,它是识别包含€字符的java表达式。如果写一个静态文本到文本元素中,\u20ac就能打印出来,因为它是静态文本,所以不被作为java表达式类解释(仅仅适合在textfield中)。

报表字体

可以选择菜单”View”中”Report fonts” 定义球形字体。会打开一个管理球形字体的窗口。一个新的图解可以查看图6.1。

从”Report font”选择框中选择使用球形字体在文本域中(图5.23)。

iReport不做管理使用最理想方式的“reportfont”。限制自身选择报表字体的属性值到文本元素中和复制所有的球形字体到文本元素中。事实上,球形字体天生就是为节约XML源为目标的,来避免为每一个单独的域指定字体。因为这些工作都可以被iReport自动的完成,最优化的重要性并不大。然而,因为这个企图集中报表字体的管理被迫停滞,因为,如果提出,JasperReports用属性来指定元素的标准,他们总是被指定被。 更简单的,如果一个球形字体报表被使用在文本元素,它的特征被保存在文本元素,本质上还是球形字体报表。

显然一会儿工夫不可能设置超过一个报表的字体。

 

7 字段,参数和变量

报表中有三个组的对象可以存储值:字段,参数和变量。这些对象被使用在表达式中,他们能改变他们的在打印行期间值和他们的类型,所有他们都有一个符合java类的类型,像string或double。字段,参数和变量被提出在报表中。选择主菜单”view”,我们能够发现“Report fields” (这就是字段), “Report variables” and“Report Parameters”这些子菜单.这三个子菜单中的每一个都允许我们管理所有他们的对象(图7.1)

图7.1

通过这个窗口我们可以声明,修改和删除字段,变量和参数。

字段

一个打印一般从数据源开始被创建:数据源在JasperReports 总是被组织成一组记录,这些记录被排列通过一系列正确字段像一个sql查询的结果集。

在图7.1的窗口中,”Fields”选项显示了需要打印的字段。为了能够显示这些字段,可以按”new”按钮,从而打开一个新的窗口(图7.2)

图7.2

字段被定义通过名字,类型和一个特需的描述。你不可能任意选择一个字段的类型。如果这个字段类型不在预选的类型中,就可能断言这个字段作为java.lang.Object和投射他到一个必须的类型在字段被使用的表达式地方。在表达式中你可以查看一个字段通过使用语法:

$F{<field name>}

所以你可以处理MyPerson字段作为it.businesslogic.Person对象:

((it.businesslogic.Person)$F{MyPerson})

这些字段在报表中不可能知道它的高度(也就是延伸到达数百)。为这个原因,iReport可以使用不同的工具通过精确的数据源型声明字段。

 

SQL查询的字段注册

这个最广泛使用工具可以断言或记录一个sql查询的字段。首先需要做的是打开ReportQueryDialog(按按钮).

查询解说的窗口将打开。它将用来填充报表(如果这个报表的创建来自于一个sql查询)

图7.3

之后要使DBMS连接起作用,就要插入一条查询语句(跳到15页查看如何做),例如:

select * from customers

iReport将运行这个sql查询,分析结果以便你去选择想要显示的字段名称。通过选择字段,他们将被注册值(图7.4)。

图7.4

注意:注册字段,就需要选择他们从这个列表中;如果查询包含一些错误,取消“AutomaticallyRetrive Fields”选择框,并按“Readfields”按钮读字段。

 

既然这样所有的字段将被变为String类型:一般的类型设置基于最初的sql类型,能够被String ,Integer等匹配。

JavaBean的字段注册

JasperReports中最高级的特征之一是管理datasources的可能性,不基于简单的sql查询。这是一个javabean收集的事例,记录集的概念被java对象替代。在这个用例中”fields”是对象的属性。通过选择JavaBeanDatasource选项,可以注册被读取的字段,这些字段被java对象指定,这个对象是:

it.businesslogic.ireport.examples.beans.AddressBean

图7.5

按钮之后可以指定这个类的名字,这个属性被萃取和引用作为字段。

 

JRExtendedBeanDataSource的字段注册

从javabean收集中创建一个打印,就需要用一个名叫JRBeanCollectionDataSource的datasources(JasperReports装载的)。

iReport提供一个扩展的datasource版本,可以用这个方法来重新声明断言作为一个字段值:

person.getAddress().getStreet()

我们讨论了JRExtendedBeanDataSource。之后我们将了解一下datasource精确的方法,在“JavaBean ExtDatasource” 选项卡有一个类似的工具查看JavaBean的反省(introspection of a JavaBean)。这个工具不能返回一个清晰的列表来探究javabean,但可以通过一个树型结构可以更深的探究,简单属性(想strings和numbers)可以通过树叶显示,其他更多复杂的类型(其他bean)可以进一步的了解到。

这种方式可以到达bean的细节,在类似的java包中。

图7.6

为了添加一个字段到列表中,就需要选择树的接点和按“Add field(s)”按钮

 

字段和文本域

在文本元素中打印一个字段,需要设置正确表达式和textfield类型,如果需要的话,还可以为字段的格式定义恰当的模式。

可以自动的设置表达式通过从字段列表中拖拽字段到相应的band (drag ‘n’ drop feature).

参数

参数是程序用来传递给报表的一个值,创建打印时,他们能被用指导运行阶段行为和(作为应用程序在sql查询中的条件),提供额外的数据去打印,像一个图形对象包含一个字符或字符串在报表标题中。

和字段一样,参数也有类型,要在设计时提出来。这是参数类型能被选择的。

图7.8

此时这个属性“is for prompting”不被ireport使用,它和打印是无关的:它代表是一种传入机制,jasperReports允许应用程序识别用户立即使用的参数值。

我们在表达式中提及到的参数的语法:

$P{<parameter name>}

如果应用程序不直接传给报表一个参数值的话,它可以设置一个默认的值。想想由于参数是一个java对象,所以它不可能用表达式像这样的

0.123 (Wrongexpression)

一个double类型的参数值,但是可以先声明一个double对象像这样:

new Double(0.123) (Rightexpression)

在查询中使用参数

我们有说过,可以用参数在sql查询中。假如你想打印一些信息,关于通过客户ID(在设计时并不知道)得到详细信息。我们的查询就要变一下:

select * from customers

where CUSTOMERID = $P{MyCustomerId}

哪儿的MyCustomerId是一个Integer类型的参数。JasperReports 将传入这个查询:

select * from customers where CUSTOMERID = ?

它将运行这个sql用一个预编译语句通过传递MyCustomerId的值作为查询参数。如果你想避免这种参数管理,可以用特殊的语法:

$P!{<parameter name>}

that 它允许我们在查询中用它的值取代它的名字。例如我们有一个名叫MyWhere的参数,它的值是“where CUSTOMERID = 5”,一个查询像这样:

select * from customers $P!{CUSTOMERID}

在完成期间被传入:

select * from customers where CUSTOMERID =5

使用程序传递参数

参数被程序指令传递给打印机通过一个类,它继承java.util.Map接口。

考虑到的代码列表在27页,以下是一部分:

...

HashMap hm = new HashMap();

...

JasperPrintprint = JasperFillManager.fillReport(

fileName,

hm,

new JREmptyDataSource());

...

fillReport表示所有JasperReports库中的一个键的方法,它可以创建以一个jasper文件名为参数的打印,一个datasource (一个假的datasource, JREmptyDataSource) 和一个参数map,它在这个例子中是空的,用java.util.HashMap对象表示的参数。

用这个参数包含在报表的标题中 (图 7.10 and 7.11), 我们继续这种方式:

1. 首先声明这个名为NAME _REPORT,类型为java.lang.String的参数;

图7.9

2. 添加一个textfield元素的标题band用这个表达式:$P{NAME_REPORT}

3. 修改程序代码:

HashMap hm = new HashMap();

hm.put(“NAME_REPORT”,”This isthe title of the report”);

...

JasperPrintprint = JasperFillManager.fillReport(

fileName,

hm,

new JREmptyDataSource());

我们放这个参数map中的一个值为NAME_REPORT参数。.

 

图7.10                                          图7.11

不强制通过程序传递一个值为所有的参数在报表中声明。如果程序不明确设置一个参数值,JasperReports将用Default Value Expression考虑预先设置的参数值,empty表达式和null的意思一样。事实上,这个例子并不是很有意思的,因为这些数据类型是一些简单的string,然而可能也会提供给报表通过map,一些更复杂的对象,像图象(java.awt.Image)或者一个可用的datasource提供一个详细子报表的情况。此外,提供一个和声明的参数一样类型的对象也是很重要的,否则将会抛出一个ClassCastException异常

内置参数

JasperReports提供了一些内置的参数(报表引擎内在的),这些参数是易读的,但是不可能被用户修改。这些参数(表7.1)。

Built-in parameters

REPORT_PARAMETERS_MAP

它是java.util.Map传递给fillReport的方法,其中包含了用户定义的参数值。

REPORT_CONNECTION

它是通过sql查询创建报表时传递给报表的JDBC连接。

REPORT_DATASOURCE

它是没有使用JDBC连接时创建报表时用的datasource。

REPORT_SCRIPTLET

It 指创建报表时用到的脚本实例,如果没有指定脚本,参数就聚焦到net.sf.jasperreports.engine.JRDefaultScriptlet实例上。

表格7.1

变量

变量是一个用来存放计算结果的对象,就像小计,总计等。

图7.12

和字段参数一样,变量被打出来,必须声明一个他们要求的java类型(Variable Class Type)。

图7.12显示了如何创建一个新的变量,看一下每个字段的意思。

Variable name他是变量的名字;和字段,参数一样,我们提供下面这个表达式

$V{<variablename>}

Variable Class Type  和参数一样,不用考虑对象的类型;在选择框中包含了大多常用的类型像 java.lang.String and java.lang.Double;

CalculationType 可以预先设置的变量的类型是:

Nothing” 不用执行任何计算JasperReports 执行计算来自于datasource的每条新的记录: 执行计算变量的意思就是求它的表达式(Variable Expression);如果计算类型是noting,JasperReports就将变量的表达式赋给变量值;如果计算类型不是noting,表达式的结果将计算一个新值赋给变量。计算类型有:

Calculation types

Nothing

不是计算类型,它被使用当用户指定内在的表达式时,每条记录将被赋值。

Count

计算所有非null的表达式的次数,不要把它和sum搞混了,sum是计算的是数字的结果

Sum

反复的迭加表达式当前的值

Average

计算所有标准输入的表达式的平均值。

Lowest

返回标准输入中最低的表达式的值

Highest

返回标准输入中最高的表达式的值

StandardDeviation

返回标准输入中规格不同的表达式值standard deviation

Variance

返回标准输入中不一致的表达式值

System

不是一种计算方式,也不求表达式的值;使用这个后,报表引擎仅将最后一个变量值放入内存中;它可以用脚本来存储计算结果。.

表格7.2

Reset Type  当变量值被重设Initial Value为或简单null的时需要指定;变量重设是基本的,当你想求一些组的小计或平均值时;重设类型列表(表7.2):

Reset types

 

None

这个Initial Value Expression总是被忽视

Report

这个变量被初始化一次仅仅在报表创建的开始,用Initial Value Expression。

Page

这个变量被初始化在每个新页

Column

The这个变量被初始化在每个新列(或者在每页,如果这个报表页仅仅只有一列的话)

Group

The 这个变量被初始化在每一个新的组(我们定义这个组用Reset Group)

Reset Group  当组选择Group reset类型时用来指定变量的重置

Custom IncrementerFactory Class 一个叫JRIncrementerFactory接口的java扩展类用来定义像总计一个非数值类型的操作;

Variable Expression  用来识别输入值的java表达式

Initial Value Expression 用来给变量初始化一个值的表达式

内置变量

像参数, JasperReports安置了一些用户处置的内部变量,他们是易读的,但不能被用户修改。这些变量是:(表格7.4)

 

Built-in variables

 

PAGE_NUMBER

包含了当前页码,在整个报表中包含总的页数。

COLUMN_NUMBER

包含当前是第几列

REPORT_COUNT

指示当前正在处理的是第几条记录

PAGE_COUNT

当前页中包含了几条记录

COLUMN_COUNT

当前列中包含了几条记录

<group name>_COUNT

以变量前缀来表示这个组记录数

表格7.4

8 Bands and groups

在这章我们将介绍如何用iReport管理band和group。第四章我们已经介绍了报表的结构,看到了报表是什么样子的。这里我们将用到组,如何创建一个breaks,如何管理子报表等等。

Bands

JasperReports将报表划分成7个主要的band和一个背景(总共就是8个bands)。其他两个(thegroup footer 和the group header)bands被加进去。

按按钮进入bands列表(图8.1)。

图8.1

通过这窗口可以修改band的主要的属性,它的高,用像素表达(band高),可能band就会被打乱,如果超出了这页(Split allowed)和Print WhenExpression,这个表达式将返回一个boolean型的对象,并终止打印。就是这个空的表达式隐含了这个表达式从而使band总是被打印。键入表达式可能是字段,变量和参数,通过指令生成一个boolean对象的结果。

甚至指定一个合法的值,band的高也可能增大,如果一个或多个元素垂直的增加(可能在textfield元素内容或子报表超出了指定的尺寸的情况下发生).的话。 JasperReports可以保证band的高永远不会这样。

In 为了能调整band可能要用到bands窗口(图8.1),立即设置一个值在band的高的地方,或者用鼠标移动指针到次的空白处,拖拽它到页的底或顶。(图8.2)

双击次的空白页可以调整band通过改变内容的高度。

图8.2

如果一个或更多个bands没有高度,可以按shift键将它朝底边的空白移动来增加它的尺寸。

移动一个元素从一个band到另一个,这个元素就会自动被这个band关联起来。

Groups

分组可以将报表的记录分开成组。通过一个表达式可以定义一个组。JasperReports求这个表达式的值:一个新的组开始当这个表达式的值改变时。

我们将解释组的用途,通过一步一步的举例。

假设有一个人员列表:我们想创建一个以人名分组的报表,人名按首写字母分组(就像一个电话簿)。运行iReport打开一个空白报表页。用sql查询从数据库中取数据(一个JDBC连接到Northwind数据库,而且这个数据库已经配置完成并测试通过)。按照你记录做第一件你认为的选择:The first thing you have to think to is the order ofrecord

selection: JasperReports获得没有顺序的记录从datasource;为这个原因你认为如何打印这些内容?你得自己把记录排序以正确的方式。我们用这个sql查询:

select * from customers order byCONTACTNAME

通过这种方式就可以将你选择的客户按他的名字排列。选择CONTACTNAME和COUNTRY字段通过Report Query Dialog (图8.3)。

图8.3

创建组之前,务必正确完成每件事,将CONTACTNAME和COUNTRY字段插入到details:编译和创建报表。结果应该和图8.5类似。

图8.4

加点难度,我们可以将detail分成两列(查看33页)。

图8.5

继续数据分组:通过 “groups”按钮进入报表分组管理窗口。

图8.6

New按钮插入一个名字叫“Initial”的组

图8.7

可以通过以下几个属性定义组:

Group Name  定义组的名字,这个名字将被用来命名和这个组关联的两个band:header和footer;

Start on a new column       如果这选项被选择,它允许强制在组的最后将列分开(意思就是新开一个组);如果这个报表仅有一列,这列就将被分开;

Start on a new page   如果选择这项,它允许强制在组的最后将页分开(意思就是新开一个页);

Reset pagenumber   这个选项可以重设页码在一个新组开始时;

Print header on each page   如果选择这项,就可以在所有的页打印组头的内容(如果一个组的内容比一页内容还多时,在新页上也打印组头);

Min height to start new page  如果不是0的话,JasperReports 将在每页打印组,如果有效的空间被指定为次的空白;通常这是为了避免分割(就像一整段被分开一样);

Group Expression  是JasperReports计算记录的表达式;当表达式换一个值时,一个新的组就创建,如果表达式是空的话,既然这样,这个结果就是单一的组的头和单一组的角分在第一列头之后和最后一列角之前;

GroupHeader Band Height  itis the band height representing the group header:

像band一样,它可以在bands窗口(图8.1)中被修改;

Group Footer Band Height  it is the bandheight representing the group footer:它也可以被修改想bands窗口一样(图8.1);

In在我们的例子中我们命名为“Initial”(名字的首写字母)的组,我们将告诉它开始一个新的列(选择Start on a new pageoption)。 我们的表达式返回这个名字的第一个字母;这个表达式是:

$F{CONTACTNAME}.substring(0,1)

并不能充分的做我们想做的事,因为没人敢保证CONTACTNAME字段是否是空值,事实上在赋值时表达式会首先抛出NullPointerException异常,其次是ArrayOutOfBoundException异常。我们测试这个内容用这两个表达式:

( ($F{CONTACTNAME} != null &&$F{CONTACTNAME}.length() > 0) ?

$F{CONTACTNAME}.substring(0,1) :"")

我们用java约束它:

(condition ) ? value1 : value2

如果条件是true就返回value1,相反就返回value2。

具体的说就是如果字段是null或它的长度为0,返回一个空的字符串,否则就返回名字的第一个字母。

添加一个新组,在下面图上有两个新的bands: InitialHeader

and InitialFooter。 用表达式在textfield插入InitialHeader band 作为组(图8.8)。结果在图8.9。

 

图8.8

图8.9

报表中组的数量可能是任意不确定的,一个组可能被一个父组包含,父组包含其他的子组。结果就是一个组列表。

可以修改一个组与另一个组的关系的优先权,通过点组列表框架上的“Move Up”和“Move Down”按钮(图8.6)。

改变组的优先权的意思就改变这这个组的位置。优先权越高,组bands就越远离detail。

9 Subreport

子报表是JasperReports目前最强大的功能之一,它可以实现非常复杂打印。 它的目的就是将一些形态相似的报表插入到另一个报表中。

创建这样的打印需要三件事做: 一jasper文件,一个参数map(可以是空),一个datasource(或一个JDBC连接)。这章我们将介绍如何利用这三个对象来创建一个动态连接的子报表,在父报表数据的基础上来创建。然后,我们将介绍一个小窍门,如何将父报表中的数据提供给子报表。

创建子报表

我们已经说过了,子报表是一个真正的报表,它有自己的XML源,有单独的jasper文件。创建一个子报表就意味着创建一个单独的报表。你得注意打印空白要设置为0为子报表。水平尺寸应该和报表一样大,不需要使子报表元素和子报表一样大,然而为了避免不可预料的结果,最好是精确点。

可以用子报表按钮将一个子报表插入到父报表中;将创建一个类似长方形的元素。子报表元素的尺寸并不意味着真的就这个尺寸,因为子报表将占用所有的没有开始裁切和裁切不正确的空间。我们可能认为只要将子报表尺寸定义到报表左上角就可以整齐的排列子报表了。

连接子报表到父报表

将一个子报表连接到父报表也需要确定三件事:如何获得jasper对象来执行子报表,如何将数据传递给子报表,如何给子报表参数设置值。所有的这些信息可以通过子报表属性来确定:(图9.1,9.2)

图9.1                                   图9.2

这些属性被定义在这两个选项中:Subreport Subreport (Other).

参数的通道

正像打印需要从程序中调用fillReport,方法,参数map被传递在子报表创建时;事实上这个map被直接的管理通过报表引擎,但是你有可能去插入名值对在这个map运行时。可能是最少被用来设置子报表参数值的方法,但是子报表元素遇到的第一个属性在属性窗口;它允许你定义一个结果java.util.Map为对象的表达式。可以用这个方法,例如,可以传递给报表控制(来自于程序)一个包含map的参数,然后用这个参数名字的表达式(例如:$P{myMap})传递map给子报表。也可能传递一个相同的参数给子报表,如果这个参数是内置参数REPORT_PARAMETERS_MAP:就可以写这样的表达式$P{REPORT_PARAMETERS_MAP}。如果你离开bland区域,一个空的map就会传递给子报表(这是不正确的如果我们定义我们期望看到的参数值)。这种机制的限制就是所传递的参数的不变性。为了能绕过这个局限性, JasperReports允许你定义一些能被对象单独创建的参数的名值对。你可以查看表在图9.2。你也完全可以自己动手:通过Add按钮可以添加一个新的参数用来提供子报表的参数map。

图9.3

这个参数名和当初在子报表中显示的一样。意思就是“事物敏感性”,意思就是说大小字母是不同的。

如果你写了错误类型的名字,或者你插入了一个不是你定义的参数,没有错误抛出(但是可能会问你一些为什么停止工作的事情)。

这个表达式是JasperReports一流的表达式,他可以用在字段,参数和变量。它返回一个符合子报表中设置的类型的参数,除非ClassCastException异常。

一个或多个 “subreport parameters”传递记录值在父报表中打印在父报表中执行子报表的查询用你提取的记录(报表headers 和 lines).

指定数据源

设置字报表的datasource就是为了告诉JasperReports如何获取数据来提供给字报表。这儿提供了两个大的datasource组: JDBC connections和Datasource。

用JDBC来提供报表数据组够了,而且简单。既然这样Connection Expression定义一个已经连接到数据库上的java.sql.Connection对象。它可以传递已经打开连接通过明确的参数但是更简单的方法是用预先确定REPORT_CONNECTION参数包含这个连接传递给应用程序的方法。通过使用Connection Expression,

到这为止就可以用sql查询创建一个包含字报表的报表。

用datasource的话就比较复杂:事实上它没有其他概念可以比的上JDBC连接。既然这样就可以就可以通过传递datasource提供给字报表一个参数,这个内部参数REPORT_DATASOURCE就没用了,因为它不可能去提供给子报表。

然而用自主的一种表达式可以生成datasource。

datasource是一种普通“耗材”对象,只能用来填充一次报表;所以datasource作为参数传递只能满足一个子报表。因此这个参数技巧就不适合了,当报表控制得到detail自己的子报表时 (除非控制器只有一条记录)。在我们介绍Datasource时就能发现用习惯的datasources很容易解决这些问题。

指定子报表

指定“.jasper”文件用来创建子报表,我们必须设置Subreport Expression. 这种类型的对象返回先于从选择框中选择的表达式(看图9.2)。可能类型和他们的语意查看表格9.1的列表。

Possible return types of the Subreport Expression

net.sf.jasperreports.engine.JasperReport

表示一个在JasperReport对象中预加的jasper文件。

java.io.InputStream

Ijasper文件的打开流

java.net.URL

定义jasper文件的URL文件

java.io.File

定义jasper文件的文件对象

java.lang.String

定义jasper文件的名字

表格9.1

如果这个表达式是一个字符串,它被JRLoader类用来从指定的本地加载文件具体说就是这个字符串首先被解释作为URL,万一MalformedURLException这个字符串被解释成一个文件的物理路径:如果这个文件不存在的话,这个字符串就被解释成java源这就意味着如果你提交一个文件,这个字符串就包含了它的绝对路径,或者你放一个jasper文件在classpath中并提交它用一个java源路径。

一步一步举例

我们将先前看到段落落实到实践上。我们想打印一个顺序列表用每个detail行顺序。使用JDBC连接(连接到Northwind数据库):用到的三个表是:Orders, Customers和“Order Details”.打开一个空报表。选择按钮并插入这条查询为父报表:

select * from orders

从这些有效的字段列表中选择ORDERID, ORDERDATE和CUTOMERID字段,以便你的例子简单一些。按OK按钮:这三个字段将被自动的注册到报表中(图9.4和9.5)。

图9.4

图9.5

拖拽这三个字段到detail中,保存报表用你喜欢的名字并在进行子报表之前对它进行测试(图9.6)

图9.6

图9.7

接下来我们就构造第一个子报表来显示以客户顺序来显示客户的信息。Next we will construct the first subreport to display the informationabout the

customer of each order (CUSTOMER).

同样,我们得构造报表控制,准备第二个报表通过添加“CUSTOMERID”参数列表,类型是java.lang.String 。子报表将使用这个参数来查询:

SELECT* FROM CUSTOMERS WHERE CUSTOMERID = $P{CUSTOMERID}.

图9.8

为了能正确的读懂查询字段,需要为参数设置一个缺省值(例如空的字符串“”)

图9.9

在子报表中所有的页的空白都被删除掉,因为这里将插入margins作为一个简单元素。保存子报表(用这个名字命名: customers.jrxml)并在空白处插入子报表元素。垂直尺寸不需要设置,因为打印时JasperReports将需要所有垂直空间(图9.10)。

图9.10

设置子报表的属性,打开元素属性窗口点”Subreport”选项。选择连接模式“Use connectionexpression”和指定内部参数$P{REPORT_CONNECTION}作为存储JDBC连接的表达式。

图9.11

In the 在“Subreport (Other)”选项中指定找到customer.jasper文件 (包含子报表的文件),以及如何修改参数的边,就是子报表和空白之间。

同子报表表达式一样,通过设定一个简单的jasper文件名之后,通过iReport,我们能确定子报表的位置,因为子报表它的目录被子报表包含在内,将自动的加到CLASSPATH中,所以子报表就能做为一个java源被发现通过ClassLoader 类。这样就需要定义一个子报表目录路径作为参数,定义表达式是:

$P{PATH_TO_SUBREPORTS}+ java.io.File.separator + “customers.jasper”.

图9.12

为了能够挑选出这些客户数据和看到他们在子报表中,我们就得填充customers.jasper参数。可以添加一个新行在子报表参数表中,通过指定子报表的参数名和用来为参数创建值的表达式。那么这个参数和表达式合起来就是:$F{CUSTOMERID}。那就是报表空白处相应字段的值。

编译 master.jrxml和customers.jrxml运行父报表

图9.13

如果每步都ok的话,你就能得到像图9.13的东西。接下来,有序的显示第二个子报表在detail中。再一次开始一个空报表,删除空白,定义参数连接到空白处; 既然这样ORDERID参数就要声明成java.lang.Integer ,并按顺序插入这条查询: select * from orderDetails where ORDERID = $P{ORDERID}

图9.14

不用设置bands的高度为0 (除了detail之外),在detail中插入我们想打印的字段(图9.15)。

图9.15

加这个子报表到空白处,并定义这新的子报表的文件名,而且要和ORDERID字段捆绑起来。

图9.16

这个文件将成为details.jasper (之前要保存子报表的名字为: details.jrxml).

添加ORDERID的参数用这个值$F{ORDERID} (图9.17)。

图9.17

再次编译和运行整个打印,你将看到像图9.18这样的结果。

图9.18

返回参数

JasperReports不提供外在机制在子报表填充结束以后来返回从子报表到父报表的参数,然而这个功能可能在许多情形下都要用到,比如你想在子报表中进行计算记录的总数,打印在父报表中, 或者在子报表中返回一个有详细细节的结果。在JasperReports所有的表达式必须返回一个对象;由于这个原因像“x = y” (that is an assignment)的表达式就是不允许的;而且父报表和子报表不能共享参数和变量来自于填满的子报表和可以看到结果的父报表。这就需要想一个诀窍来避免这两个问题。事实上,解决的办法要比你想象的简单的多:就是用java.util.HashMap参数来共享一个内存在父报表和子报表之间传递这个参数给子报表,我们通过put值填满HashMap,用预先指定的map指针后退。这中方式我们就不能给参数一个新的值(那是不可能的),但是我们将修改HashMap的内容,我们已经这么做了。

现在就可以找个方法来执行下面的指令:

((java.util.HashMap)$P{ReturnValues}).put(“PROCESSED_RECORDS”,

$V{REPORT_COUNT} )

这个表达式不能够生成值的,所以你可以用一个外部类的公共方法来生成这个表达式的结果并且返回任意值。

我们需要的这个类的简单的代码如下:

public class ReportHelper {

public static boolean addMapValue(Objectmap,

String key,

Object value)

{

if (key == null || value == null) returnfalse;

((java.util.HashMap)map).put(key,value);

return false;

}

}

这个类是简单的:The class is simple: 它仅有一个静态方法addMapValue,用来在HashMap中插入一个键,并生成一个boolean值(这个值永远是false)。

用这个方法就可以得到我们想要的值,我们可以虚拟一个元素(也就是一行)加到报表中(概要中的例子)并设置它的printWhenExpression为:

new Boolean (ReportHelper.addMapValue($P{ReturnValues},

“PROCESSED_RECORDS”,

$V{REPORT_COUNT} ) )

不需要关心元素的类型,因为它不会被打印,因为addMapValue返回值永远是false。选择正确的位置,插入元素到报表中,它允许我们无论什么时间,无论多少次addMapValue肯定都执行。

10 数据源

datasource是一个源来自于JasperReports,并取走数据用于打印。这儿有两种类型的datasources:一个是JDBC连接到关系数据库,在这个数据库上执行sql查询,这个对象继承JRDataSource接口,那个,像我们看到的,允许我们去管理详细的数据像这种XML文档或者一个JavaBean。

从一个关系数据(通过sql查询)找回数据来打印的这中能力来创建一个报表是非常简单的,因为可以通过鼠标点击“register”查询字段作为报表字段(没有指定每一个单独字段的名字和类型)。iReport可能关联每一个数据库,为数据库提供一个JDBC驱动,并且提出你配置的用来完成从sql查询开始创建一个报表的向导。当你不想存取数据通过JDBC (或者当你不想JasperReport不直接影响数据库),这时就需要用到JRDataSource(JasperReports数据源),这是一个接口允许存取数据好象他们被构造在表格中,被组织在lines和columns上 (lines是datasource指定的记录,columns是记录的字段)。

The JDBC连接或者JRDataSource不是通过JasperReports创建的,但是是通过调用报表的应用程序生成的。这个程序将传递JasperReports的fillReport方法来打开连接到数据库(一个java.sql.Connection对象)或者由于JRDataSource填充报表的情况。

第一个中,JasperReports将使用提供的JDBC连接去执行sql查询指定在报表中(明显的这个查询仅仅在你使用这种方法时想打印报表而指定)。查询的结果被包含在被JRResultSetDataSource的指定的JRDataSource中。以这种方式, JasperReports用JRDataSource对象联合这些数据去打印,表示一般的用这个库管理数据打印的接口。

在这章我们将在iReport的使用和配置时澄清JRDataSource的不同。而且我们将看到如何扩充JRDataSource ;有时扩充datasources需要我们超越JasperReports的限制,就像没有直接的支持交叉报表。

iReport中的数据源

iReport允许我们管理和配置不同类型的datasources来填充报表。以下是存储在iReport中需要我们配置和激活的datasources。

你可能使用到的datasources类型:

- JDBC connection

- XML DataSource

- JavaBean Collection Datasource

- CSV DataSource

- Custom DataSource

在报表生成时JDBC连接被打开并立即传递给JasperReports。XML DataSource 允许我们从XML文档中取数据。CSV DataSource允许你打开一个CSV(以逗号分割的值)文件在报表中使用。JavaBean Collection Datasource和Custom DataSource

允许你打印数据使用java类。Datasources被管理通过菜单 “Datasource → Connections /Datasources“ (图10.1), 打开配置连接列表。

图10.1

技术上connectiondatasource是不同的对象 (第一个总是需要一个关系数据库, 但是第二个表示一个简单的接口去存取数据结构在任意的表单中)。然而现在我们将使用这两个相似的单词。

即使我们保持任意数量的datasources准备去用,iReport工作仅仅使用一个源或连接。设置“active”datasource, 选择主窗口菜单“Build → Set the active connection” 并选择想要的datasources从提示列表中(图10.2)。

图10.2

如果没有datasource被选择,就不可能为报表提供数据。用报表向导配置一个能起作用的JDBC连接(仅仅一个允许执行sql查询)。

JDBC连接

JDBC (Java DatabaseConnectivity)连接允许我们去使用作为一个关系DBMS (或者无论那种更接近通过JDBC驱动的) driver). To set a设置一个新的JDBC连接,按“New”按钮依照图10.1提供的,将打开一个新的界面创建一个新的连接(或datasource)。

图10.3

首先为这个连接命名(可以用一个有意义的名字,像“Mysql – Test”)。iReport将使用这个指定的名字进行连接。

JDBC Driver区域是用来指定连接数据库的JDBC驱动的名字。这个选择框包含了常用的JDBC名字。

警告! iReport仅仅装载了Mysql和HSQLDB的JDBC驱动。

幸亏JDBC URL Wizard, 他可以自动的构造JDBC URL来连接数据库通过插入服务名和数据库名在恰当的textfield。按Wizard按钮创建URL。

插入用户名和密码去存取数据库。意思就是一个选择框可能保存连接密码。

警告! iReport将密码保存在清晰的配置文件并加载到<USER_HOME>/.ireport/config.xml

如果密码是空的,最好保存它。

插入所有的数据以后,需要按“Test”按钮来校验连接。如果一切都ok,将会出现以下提示:

图10.4

测试后,记着设置创建连接作为“active connection”去使用。

如果测试失败,可能是以下这些原因:

- ClassNotFoundException

- URL不正确

- 连接参数不正确(Database not found, user or password wrong, etc...)

ClassNotFoundException

这个异常出现当所需要的JDBC驱动在CLASSPATH中不存在,比如我们创建一个Oracle数据库连接。iReport缺省驱动中没有oracle的,但是在JDBC驱动列表中存在oracle.jdbc.driver.OracleDriver驱动,事实上当你测试连接时就会出现这个异常:

图10.5

我们并没有将oracle的JDBC驱动加到CLASSPATH(这里JVM可以搜索到的类)中,它是一个名叫classes12.zip的文件(或者老版本的classes11.zip). 当作iReport使用自己的Class Loader,需要拷贝完整的classes12.zip文件到iReport的lib目录下,然后重新测试就不会发生异常了。

Lib目录是插入jar档案的正确地方(扩展名为jar或zip)。如果这个驱动不是jar版本的,它就被作为未知目录加载(例如,com目录包含所有驱动类的级数),最正确的地方去动态的加这些类到CLASSPATH就需要拷贝驱动目录到classes目录(iReport的主目录)

URL不正确

如果指定一个错误的URL(例如指定一个错误类型的),不会发生什么事当你按“Test”按钮时。事实上会抛出一个StackOverflowError异常(堆栈报告被打印在控制台或者shell中在iReport被打开时)。

既然这样,最好还是用URL向导来建这个JDBC URL,然后再试一次。

连接参数不正确

这个错误是比较少见点的,它是你在建立数据库连接时用了错误的参数时发生的(用户名或密码无效,数据库不存在,等)。这个错误或多或少是比较直观的连接错误。

使用JDBC连接

当使用JDBC创建报表时,用户指定一个sql查询从数据库中查询记录用来打印。这个连接也能被在子报表或这例如,通过个性化的查找功能为详细的数据码。为这个原因, JasperReports安置我们的配置作为指定的参数,名字叫REPORT_CONNECTION,类型为java.sql.Connection,这个参数能被随意的使用,它的语法格式:

$P{REPORT_CONNECTION}

这个参数包含在正确的java.sql.Connection类传递给JasperReports来自于calling程序。

JDBC 或SQL 连接看来是最简单和容易的方法用来填充报表。如何创建sql查询将在第11章解释。

字段注册

为了能使用sql查询字段在报表中,需要去“注册”他们(需要注册所有已经选择的字段,以便能有效的使用)。每一个字段都需要指定名字和类型。以下是sql类型影射到相应的java类型:

SQL type

JAVA object

CHAR

String

VARCHAR

String

LONGVARCHAR

String

NUMERIC

java.math.BigDecimal

DECIMAL

java.math.BigDecimal

BIT

Boolean

TINYINT

Integer

SMALLINT

Integer

INTEGER

Integer

BIGINT

Long

REAL

Float

FLOAT

Double

DOUBLE

Double

BINARY

byte[]

VARBINARY

byte[]

LONGVARBINARY

byte[]

DATE

java.sql.Date

TIME

java.sql.Time

TIMESTAMP

java.sql.Timestamp

表格10.1

这个表格中的BLOB和CLOB类型不像其他指定的类型,像ARRAY, STRUCT,REF, 等... 这些类型不能被JasperReports管理(然而可能用他们通过一般的对象声明,也可以管理他们通过写一些支持静态方法。BINARY,

VARBINARY和LONGBINARY类型应该用类似的方法。)可以在java对象中依靠JDBC驱动包含sql类型。

用iReport影射自动的注册sql查询字段更为简单比表中提到的。

JRDataSource接口

进行探索datasources的不同之前,需要理解JRDataSource接口工作。每个JRDataSource都必须实现这两个方法:

public boolean next()

public Object getFieldValue(JRFieldjrField)

第一个方法是用来移动有用的指针到下一条记录:事实上我们说的那些数据被JRDataSource展示在表格中。Next方法返回true,如果指针正确指到后来的记录上时,但如果指到无效记录上,将返回false。

JasperReports每次执行next时,所有的记录被重新的填充到报表,所有的表达式(从那些关联的变量开始)被适当的计算; 随后将决定是否打印新组的头,以及新页,等。当next返回false时,报表就结束所有bands的打印(group footer, column footer, last page footer and the summary).next能被调用许多次。

getFieldValueis方法在next方法返回true以后被调用。 事实上,getFieldValueis 被执行为每个在报表中显示的字段(看第7章如何声明报表字段)。访问一个已经被传递的作为参数的JRField对象;它就是你像获得的字段值的名字,一个你期望得到的一个java类型对象以及这个字段的描述(不是去指定一些有用的datasource信息来取得字段值)。

getFieldValue方法的返回值的类型被适当的公告在JRField参数中,除非它返回一个null值。这些可能的返回值类型有:java.lang.Object, java.lang.Boolean, java.lang.Byte,java.util.Date,java.sql.Timestamp, java.sql.Time, java.lang.Double,

java.lang.Float, java.lang.Integer, java.io.InputStream,java.lang.Long,

java.lang.Short, java.math.BigDecimal, java.lang.String. 如java.lang.Objectis

被请求作为返回值的类型,这个方法就能返回任意类型。这个例子中的datasource不作为简单类型字段 (作为一个数据库记录的产生), 但仅仅一个字段来自于java对象和被用在表达式中通过一个例子: 在第7章一 字段被描述作为例子:它的语法格式是:

((it.businesslogic.Person)$F{MyPerson})

因为这个字段类型是被解释器知道的类型而被简单的作为Object.

JavaBean作为数据源

这个datasource允许我们使用一些JavaBeans作为数据来填充报表。JavaBean是一个java类,它里面都是些“getter”方法:

public <returnType> getXXX()

<returnType> (返回值) 是一个普通的java类或一个简单类型(像int,double,等)。

为了创建这个类型的连接,选择下图(图10.6)中的第一个选择框的值为“JavaBean setdatasource”。

图10.6

再一次要做的第一件事是指定这个新的datasource的名字。JavaBean将一个外部类(被叫做Factory)作为datasource来生成包含为报表提供数据的对象(JavaBean)输入你的java类(全名被指定在Factoryclass字段中),这个类有一个静态的方法来表示不同的JavaBeans 并返回他们作为收集器(java.util.Collection)或一个数组(Object[])。这个方法的名字和返回类型被指定在这个窗口的其他地方。

让我们看看如何写这个工厂类。假设你的对象是Person ;以下是这个类的代码,包含两个字段: name (这个人的名字) and age.

public class Person

{

private String name = "";

private int age = 0;

public Person(String name,

{

this.name = name;

this.age = age;

}

public int getAge()

{

return age;

}

public String getName()

{

return name;

}

}

这个类我们命名为TestFactory,它的结果类似于下面的结果:

public class TestFactory

{

public static java.util.Collection generateCollection()

{

java.util.Vector collection = newjava.util.Vector();

collection.add(new Person("Ted",20) );

collection.add(new Person("Jack",34) );

collection.add(new Person("Bob",56) );

collection.add(new Person("Alice",12));

collection.add(new Person("Robin",22));

collection.add(new Person("Peter",28));

return collection;

}

}

datasource将表现5个Person类型的JavaBeans:

Factory name: TestFactoryDataSource

Factory class: TestFactory

Method to call: generateCollection

Return type: Collection of JavaBean

JavaBean的一个字段作为数据源

The peculiarity of aJavaBean设置字段作为datasoiurce,这些字段通过getter方法暴漏出去。set datasource are the fields that are exposed through

the getter methods.意思就是如果JavaBean有一个getXyz()方法,那么xyz就是一条记录字段(thatis composed by the bean).

这个例子中,person对象中有两个字段:name和age;分别注册他们用string和integer类型在字段列表中。

创建一个新报表,打开值窗口添加这两个字段:

图10.7

移动这些字段到detail中并运行报表。图10.8展示了报表的设计过程,而接下来的图则展示了用javabean设置的字段的打印结果。

图10.8

图10.9

XML数据源

从0.4.0版本开始,iReport支持XML文档的datasource。而先前的版本支持特定的datasource。由于新版本的适应性,老版本就被打成左派。

A XML文档是一个有代表性的树型结构,那么我们就需要去了解已经被选择和提出作为XML文档的节点。这样做还要使用一个XPath (XML Path Language)表达式;通过它的一个节点可以定义。XPath必须有效在http://www.w3.org/TR/xpath页面上。

用一些例子来帮助了解怎样定义节点。考虑一下表格10.2的XML文件。这是一个假设的有不同人的地址薄,他们以类别来分组。

在一种类别列表的最后最喜欢的对象出现。

这个例子可能需要定义不同节点类型,这个类型就是你想组织的报表中的数据的类型。

<addressbook>

<categoryname="home">

<personid="1">

<lastname>Davolio</lastname>

<firstname>Nancy</firstname>

</person>

<personid="2">

<lastname>Fuller</lastname>

<firstname>Andrew</firstname>

</person>

<personid="3">

<lastname>Leverling</lastname>

</person>

</category>

<categoryname="work">

<person id="4">

<lastname>Peacock</lastname>

<firstname>Margaret</firstname>

</person>

</category>

<favorites>

<personid="1"/>

<personid="3"/>

</favorites>

</addressbook>

表格10.2

只选择这个种类的人的容器(所有的人在这个addressbook中)的表达式:

/addressbook/category/person

返回节点将是4:

<person id="1">

<lastname>Davolio</lastname>

<firstname>Nancy</firstname>

</person>

<personid="2">

<lastname>Fuller</lastname>

<firstname>Andrew</firstname>

</person>

<personid="3">

<lastname>Leverling</lastname>

</person>

<personid="4">

<lastname>Peacock</lastname>

<firstname>Margaret</firstname>

</person>

表格10.3

如果你想选择你中意的人的节点,表达式该这样写:

/addressbook/favorites/person

返回的节点将是 2:

<personid="1"/>

<personid="3"/>

表格10.4

这儿我们计划一个稍微再复杂一点的表达式比上个例子,为了表现Xpath的能力:这个想法是选择person节点属于work组。表达式是:

/addressbook/category[@name = "work"]/person

这个表达式只返回一个id = 4的节点:

<personid="4">

<lastname>Peacock</lastname>

<firstname>Margaret</firstname>

</person>

表格10.5

你已经知道怎样创建节点表达式,接下来创建一个XMLdatasource。

打开创建datasource的窗口,选择“XMLFiledatasource”连接。

图10.10

除此之外,还需要填写XML文件名和XPath表达式。

字段的注册

这个例子中XMLdatasource,定义报表需要的字段,除了类型和名字以外,还要插入字段描述的表达式。

作为datasource的目标总是选择设置一个节点,这个表达式是“相关的”和提供的节点。

选择提供节点的属性值的语法是:

 @<nameattribute>

定义一个字段用来存储一个人的id(这个节点人的属性id),需要创建一个新的节点,并命名一个任意的名字:

@id

一个相似的方法可以得到子节点从提供的节点中。比如你想得到lastname节点,person的子节点,用以下语法:

lastname

移动提供节点的父节点的值 (例如一个人所属的类别的名字) 用有点不同的语法:

ancestor::category/@name

 “ancestor”键表示你涉及到的父节点,具体的说是你涉及的第一个父节点的category类型,你想知道的name属性的值。

现在将在行动看到上面的每件事。准备一个简单的报表用已经注册过的字段像表10.6。

 

Field name

Description

Type

ID

@id

Integer

LASTNAME

lastname

String

FIRSTNAME

forname

String

CATEGORY

ancestor::category/@name

String

表格10.6

设置不同的字段到detail band(如图10.11)。表格10.2是要填充报表的XML文件。Xpath表达式:

/addressbook/category/person

所有的结果查看图10.12

图10.11

图10.12

XML和子报表

node set 可以识别连续的节点,从JRDataSource点查看一些记录。

然而,如果XML文档非常复杂的话,就需要查看其他的node sets在主节点上。

考虑一下下面的XML,它对表10.2做了一点修改,添加了hobbies节点包含了一个连续的hobby节点,还有一个或更多个email地址。

<addressbook>

<categoryname="home">

<personid="1">

<lastname>Davolio</lastname>

<firstname>Nancy</firstname>

<email>davolio1@sf.net</email>

<email>davolio2@sf.net</email>

<hobbies>

<hobby>Music</hobby>

<hobby>Sport</hobby>

</hobbies>

</person>

<personid="2">

<lastname>Fuller</lastname>

<firstname>Andrew</firstname>

<email>af@test.net</email>

<email>afullera@fuller.org</email>

<hobbies>

<hobby>Cinema</hobby>

<hobby>Sport</hobby>

</hobbies>

</person>

<personid="3">

<lastname>Leverling</lastname>

<email>leverling@xyz.it</email>

</person>

</category>

<favorites>

<personid="1"/>

<personid="3"/>

</favorites>

</addressbook>

表格10.7

我们想生成一个比目前看到的更为细致的文档:每个人能查看email地址和hobbies列表。获得这样的文档就需要用到子报表,在这部分你就需要一个你中意的人的email地址列表和hobbies。我们的兴趣可能是了解如何生成一个新的datasource来填充子报表。为这个目的,JRXmlDataSource有两个非常有用的方法:

public JRXmlDataSource dataSource(StringselectExpression)

和方法:

public JRXmlDataSource subDataSource(StringselectExpression)

他们之间的不同主要是前一个是从文档的根节点开始选择,而后一个是从所选择的节点开始。

这两个方法都使用子报表元素的DataSource Expression去生成动态的datasource传递给子报表。最重要的事情不但要我们生成datasource,还需要选择动态的节点表达式。

这个例子中,的表达式能创建这个datasource来提供给子报表email地址:

((net.sf.jasperreports.engine.data.JRXmlDataSource)

$P{REPORT_DATA_SOURCE}).subDataSource("/person/email")

也就是说 “从现有的节点(person)返回所有的这个person的直接后代email节点”。

这个表达式对于hobbies也是一样的,除非用以下这个方法:

((net.sf.jasperreports.engine.data.JRXmlDataSource)

$P{REPORT_DATA_SOURCE}).subDataSource("/person/hobbies/hobby")

报表的主字段在表10.6中。在子报表我们提供涉及到的节点值,所以字段表达式将会简化成一个点(.)。

表格10.13

继续建我们的三个报表:addressbook.jasper, email.jasper和hobby.jasper.

表格10.14

在“主”报表中,addressbook.jrxml,我们将插入一个名字叫CATEGORY的组,和它关联的表达式是CATEGORY ($F{CATEGORY})字段。在CATEGORYHeader band插入一个字段,哪儿我们将看到组的名字。照着做,不同的人的名字将被划分为组(就想XML文件中的一样)。在detail中我们安置“ID”, “LASTNAME”和“FIRSTNAME”字段。接下来定位子报表的位置,分别是hobby和后来的email地址。

 “email”和“hobby”子报表是一样的,除了表达式中的字段不一样。这两个报表是一样大小的子报表元素在主报表中,空白也都减小到零。

图10.15

编译并执行,如果一切ok的话,我们就能看到类似于图10.16的结果。你可以看到每个人的组在主窗口和工作组以及每个人在子报表中关联的列表中。

 

图10.16

可以看到XPath 提供的XMLdatasource的强大,它可以操纵节点选择精确的方式。

CSV数据源

CSV(Comma Separated Values)文档datasource是我们目前为止看到的最简单的。

创建一个基于CSV文件的连接,打开新建连接窗口选择File CSV DataSource 项。

仅仅需要定义的信息除了datasource的名字外,就是CSV的目录。

图10.17

这个datasource执行起来非常的简单,所以我们在下一段落来看如何应用这个datasource。然而容易却表现出了CSV细节上的不足: 事实上这个datasource不支持mulit-line记录,不管理溢出的序列和顶点,它采取通过“;”分开不同的字节。独立所有的它的限制,这种datasource非常适合用来说教用,它可以很快的在缺乏database时查询出数据达到测试的目的。

字段的注册

这种类型的datasource的所有字段都是string型的,他们能被注册用名字“COLUMN_n”,n表示字段的号(n的最小值是1)。意思就是说如果你有CSV字段包含三个字段,例如:

Davolio;Nancy;davolio1@sf.net

Fuller;Andrew;af@test.net

Peacock;Margaret;Peacock@margaret.com

第一个字段将命名为COLUMN_1, 第二个为COLUMN_2 ,等等。

JREmptyDataSource

JasperReports 安排了一个特殊的datasource叫JREmptyDataSource。它是用来创建报表的,当你按下按钮时。这个源的特权是能够返回true给next方法一个记录的号(确省值是1),并返回null,当调用getFieldValue方法时。就像有记录没有字段,一个空的datasource。

两个类构造器:

public JREmptyDataSource(intcount)

public JREmptyDataSource()

第一个可以显示返回多少条记录,第二条显示记录的条数。

实现一个新的JRDataSource

有时提供的JRDataSource 并不能完全的满足它的需要。在这些例子中,它可能自治的写一个新的JRDataSource。这个操作并不复杂:事实上所有的类都实现接口JRDataSource(表10.8),包含两个方法:next和getFieldValue

Package net.sf.jasperreports.engine;

public interface JRDataSource

{

public boolean next() throwsJRException;

public Object getFieldValue(JRFieldjrField) throws

JRException;

}

表10.8

next方法是用来通过datasource移动记录显示出来的。如果有新的记录它返回true,反之返回false。

如果next方法被调用,getFieldValue方法将返回需要字段的值(或者null,如果这个值未找到或者不存在)。。具体的说就是请求字段的名字被包含在JRField对象中作为参数传递。。JRField也是一个接口,它可以得到一个字段相关的三个信息:名字,属性,和java类型(我们有一个JRDataSource列表关于这三个类型在这章中)。

现在我们继续写我们个性化的datasource。这个想法比较的新颖,你可以写一个datasource来探索一个文件系统的目录并返回找到的对象(文件或目录)。这些字段我们将处理成我们的datasource:文件名,我们命名为FILENAME,,这有一个标记,就是说如果这个对象是一个文件或目录,我们命名为IS_DIRECTORY ,文件的大小,如果可用的话,我们命名为SIZE。

有两个构造器为我们的datasource:前一个接见作为一个参数目录去浏览,后一个没有参数(将使用以有的目录浏览)。

举个例子,datasource将寻找当前的文件和目录用指定的方法,加载数组文件。

next方法将增加变量的index,我们将保存位置延伸到数组files和返回true直到达到数组的末尾。

import net.sf.jasperreports.engine.*;

import java.io.*;

public class JRFileSystemDataSourceimplements JRDataSource

{

File[] files = null;

int index = -1;

public JRFileSystemDataSource(String path)

{

File dir = new File(path);

if (dir.exists() &&dir.isDirectory())

{

files = dir.listFiles();

}

}

public JRFileSystemDataSource()

{

this(".");

}

public boolean next() throws JRException

{

index++;

if (files != null && index <files.length)

{

return true;

}

return false;

}

public Object getFieldValue(JRFieldjrField) throws JRException

{

File f = files[index];

if (f == null) return null;

if(jrField.getName().equals("FILENAME"))

{

return f.getName();

}

else if(jrField.getName().equals("IS_DIRECTORY"))

{

return new Boolean(f.isDirectory());

}

else if(jrField.getName().equals("SIZE"))

{

return new Long(f.length());

}

// Field not found...

return null;

}

}

表10.9

getFieldValue方法将返回请求文件的信息。我们不执行关于返回类型的信息通过调用这个方法,但是它返回一个string类型的名字,标记IS_DIRECTORY作为boolean对象,文件尺寸作为long对象。

以下的段落我们将解释如何使用我们的datasource在iReport中,并测试它。

用iReport实现个性化的JRDataSource

为了iReport datasource是个性化的,当我们指定图形界面来显示它的使用方法是没用的。我们可能说datasource关于所有的个性化除了: -JRXmlDataSource

- JRBeanArrayDataSource

-JRBeanCollectionDataSource

事实上所有的这些都是由iReport自动管理的。

为所有其他的datasource,需要设置一个指定的连接,可以你想要的任一种JRDataSource,通过选择JRDataSource指定的“dirver”种类列表。这些“drivers”是一些简单的java类,他们是用来测试datasource或为报表提供数据,好象被执行通过具体的程序。

这个想法是我们看了JavaBean设置datasource之后有的,其实他们也都一样的:需要写一个java类通过静态方法创建datasource并返回它。

例如如果你想测试,我们有解释过在上一段,就需要创建向表10.10那样的简单的类。

import net.sf.jasperreports.engine.*;

public class TestFileSystemDataSource

{

public static JRDataSource test()

{

return newJRFileSystemDataSource("/");

}

}

表10.10

这个类中的静态方法将被调用时,将执行所有需要的代码来获得合适的datasource。在我们的例子中,我们将创建一个新的JRFileSystemDataSource对象,通过和指定根目录一样的方法(“/”)。

现在我们确定用这种方式来获得JRDataSource ,创建一个连接以备使用。

打开新建连接窗口,选择类型“Custom JRDataSource”,设置这个datasource名字为“TestFileSystemDataSource”(或者其他你愿意的名字)。

图10.18

在这之后,需要定义这个类和方法来获得我们的JRFileSystemDataSource的实例: TestFileSystemDataSourcetest.

通过这个datasource准备一个新报表。没有方法可以找到字段通过datasource。这个例子中我们知道管理三个字段和他们的名字和一个类型:一但你创建了这些字段,插入到detail中运行打印:

图10.19

打印已经被创建了。这个报表有被分开成两列,在column header的band中,file name和size tags被插入进去。指定的三个字段也被公告出来,FILENAME和SIZE被立即的插入到detail。然后这个两个位置被插入图象,一个表示文档,另一个是打开的文件夹。图形元素被安置在醒目的地方,表达式是: $F{IS_DIRECTORY}

图10.20显示了设计窗口中的图。

图10.20

这个例子中被命名为JRFileSystemDataSource的datasource非常的简单。然而它可能引发更多复杂的类,这个datasource被获得通过一个Enterprise Java Bean或WebService...

JavaBeanExtended数据源

iReport提供了详细的datasource,它是JavaBeanExtendedDataSource,它表现一个进化的datasource,比起JavaBean的datasource来说。这两datasouce之间的不同可以能就是移动字段在子类中,因此它是可能的,一如,打印一个假想的“street”字段的bean包含在“person”bean中。

图10.21显示了从bean中查找字段的工具,而且很容易使用这些对象

T已选的字段可能被注册为字段。iReport保存必须的方法来查找详细的字段在字段描述中。例如一个Address.Street提供datasource来查找,可以通过调用getAddress().getStreet()方法。

可用的构造器为这个datasource:

public JRExtendedBeanDataSource(Vectorbeans)

public JRExtendedBeanDataSource(Object[]beans)

一些请求的对象和字段都被datasource管理。

图10.21

设计者通过表达式来填充子报表。假设person对象有一个getHobbies()方法,这个方法返回类型是hobby对象的携带者,就需要表达式去填充子报表,这个hobby的打印应该是:

new JRExtendedBeanDataSource((java.util.Vector)$F{Hobbies})

Hobbies作为一个java.lang.Object被公告。

11 国际化

JasperReports 0.6.2介绍了一些新报表特点:国际化。国际化的报表意味着所有的静态文本(像labels,messages等)在设计期间可以被修改成locale选项:报表引擎可以用最合适的有效的转化来打印报表。

文本转化在不同的语言支持通过报表被存储在特殊的名为Resorurce Bundle的源文件中。

在这章将介绍内置的功能msg()和如何“本地化“非常复杂的动态创建。

Resource BundleBase Name

当一个报表是国际化时,就需要定义所有依照文本的地方,像labels和静态strings。键(一个名字)被关联到每个文本片段。这些键和有关系的文本转化被写在指定的文件中(每种语言),像表11.1。

Title_GeneralData=General Data

Title_Address=Address

Title_Name=Name

Title_Phone=Phone

表111.1

所有的包含这些信息的文件被保存以“.properties”文件扩展名。有效的文件名(也就是是没有文件扩展名和语言/国家代码—随后将看到)表示报表Resource BundleBase Name(例如:源文件i18nReport.properties的ResourceBoundle Base Name是i18nReport) 。在执行的时候,报表引擎将查看一个文件,它的名字由Resource BundleBase Name和扩展名“.properties”构成,在classpath中(所以在先前的例子中它将查看文件名为:i18nReport.properties)。如果这个文件被发现,它将读取本地文本。resource bundle base name 可以在报表属性窗口的“i18n”选项卡来指定(查看40页)。

当它被请求使用指定地打印,JasperReports寻找一个以resource bundle base name字符串开头的文件,接下来是请求地的语言和国家代码。例如,i18nReport_it_IT.properties是一个包含意大利本地化字符串的文件,而i18nReport_en_US.properties则被转化成美国英语。所以创建一个缺省的文件,它包含最普遍范围语言和和设置指定文件的语言用其他的语言的文件

缺省的源文件没有语言/国家代码在后,那么将仅仅使用源文件的值在转化文件时。这个源文件的值被使用仅仅如果没有

完整的源文件名应该是这样的:

<resourcebundle base name>[_language code[_country code[_other code]]]

这是一些有效的源文件名的例子:

i18nReport_fr_CA_UNIX

i18nReport_fr_CA

i18nReport_fr

i18nReport_en_US

i18nReport_en

i18nReport

 “other code” (可选择代码), 指语言和国家最右边的代码(例子中的“_UNIX”)是普遍并且也不使用在报表中,但却可以有效识别源文件。

iReport有能力管理源文件的本地化。唯一的情况是被本地化的源文件和本地的jrxml源文件在同一个目录,或者resource bundle base name和jrxml文件名(排除扩展名)相同。

访问报表源文件的列表,选择菜单“View

Internationalization”然后选择“Localization files”。

图11.1

从这个窗口你可以创建,修改或者删除报表的源文件。

图11.2

创建新的“locale”文件, 需要重写却省文件和修改它的后缀(language/countrycode),在之后添加base name 从新的完整的源文件名:布置必须依照先前的规则(更多的语言和国家代码和普遍的源文件名可以查看java文档)。

通过按“Modify file”按钮可以编辑选择文件的内容。

图11.3

按“Save”按钮保存修改的源文件,因为这个文件不会自动的被保存。

恢复本地化字符串

有两种方法可以找回本地字符串来插入到JaserReport表达式:你可以用内置的str(“key name”)功能或者用指定的语法$R{key name}。源键被转化成java变量在报表编辑期间,像字段,变量和参数:允许使用任意的名字作为源键,不用遵守java变量的规则(就像这样,你可以插入一个点“.”在这些名字中)。总直,最好不要使用空格“ “字符。这儿是一个表达式例子用来找回本地化字符串:

$R{text.paragraph1}

这个表达式能修改与其相关的文本用这个键“text.paragraph1”,使用最合适的变量转化为选择的地区。

格式化消息

JasperReports国际化的支持基于java。一个最有用的功能就是msg,它被用来动态的生成消息。事实上,msg使用字符串“模式”。 这些模式作为参数传递给msg功能,必须被放置。

安置点用braces之间的数字表示:The program extracted {0} as a random number。 0表示第一个传递给msg功能的值的点。表达式:

msg($R{text.paragraph1}, $P{number})

使用key text.paragraph1提到的这个字符串调用msg。第二个参数是第一个点被取代的string。如果text.paragraph1是字符串报表参数“号”的值是“100”,然后打印的文本变成:The program extracted 100 as a random number

原因是使用生成的message的取代像区分单个的子字符串[The program extracted] {0} [as a random number],有时第二个方法是不可能的。 定位器不能被创建以合法的适当的为所有的语言(例如:句子最后的动词的语言等。)

可以通过三种方式调用msg功能:(查看表11.2)。

public String msg(String pattern,Object arg0)

public String msg(String pattern,Object arg0, Object arg1)

public String msg(String pattern,Object arg0, Object arg1, Object arg2)

表11.2

他们之间的不同仅仅是传递点数量不同。

配置本地化报表

配置本地化报表的第一步,这是必然的对所有的属性文件,包含转变的字符串,且在classpath中。

JasperReports寻找源文件用ResourceBundlejava类中的getBoundle方法。想了解更多关于这个类可以查看网站:http://java.sun.com/docs/books/tutorial/i18n/这儿有主要的概念关于java对国际化的支持。

12 脚本

脚本是一个java类,它是用来执行指定的细节在打印期间。脚本中的一些方法被报表引擎的调用,当一些特殊的事件,像创建一个新页或者处理detail 行。

这章我们将介绍如何写一个简单的脚本,并使用在报表中。我们将看看iReport如何的运用脚本,处理一个报表用这种功能的用途。

JRAbstractScriptlet类

实现一个脚本就得继承这个java类:

net.sf.jasperreports.engine.JRAbstractScriptlet.这个类含有所有的抽象方法,运用在报表生成期间,提供存取所有的变量,字段和参数的数据结构给报表。

倘若这些简单的脚本直接执行通过JasperReports:它是JRAbstractScriptlet类,继承这个类并实现所有需要的抽象方法用一个没有返回值的方法体。

package net.sf.jasperreports.engine;

/**

* @author Teodor Danciu(teodord@users.sourceforge.net)

* @version $Id: JRDefaultScriptlet.java,v1.3 2004/06/01 20:28:22

teodord Exp $

*/

public class JRDefaultScriptlet extendsJRAbstractScriptlet

{

public JRDefaultScriptlet() { }

public void beforeReportInit()throws JRScriptletException

{

}

public void afterReportInit() throwsJRScriptletException

{

}

public void beforePageInit() throwsJRScriptletException

{

}

public void afterPageInit() throwsJRScriptletException

{

}

public void beforeColumnInit()throws JRScriptletException

{

}

public void afterColumnInit() throwsJRScriptletException

{

}

public void beforeGroupInit(StringgroupName) throws

JRScriptletException

{

}

public void afterGroupInit(StringgroupName) throws

JRScriptletException

{

}

public void beforeDetailEval()throws JRScriptletException

{

}

public void afterDetailEval() throwsJRScriptletException

{

}

}

表12.1

像你看到的,这个类是通过使用跟随在event或action名字(Detail Eval

or PageInit)的关键字after或者before形成的。这些方法map都能运用于脚本。他们概括如下表。

Event/method

Description

Before Report Init

在报表初始化(也就是所有的变量初始化之前)之前调用。

After Report Init

所有的变量初始化之后调用。

Before Page Init

创建一个新页时,所有变量有重设类型“page”被初始化之前调用。

After Page Init

创建一个新页时,所有变量有重设类型“page”被初始化之后调用。

Before Column Init

被调用当一个新列被创建时,所有变量重设列类型“column”之前,但如果这列已经被添满这个时间将不发生。

After Column Init

被调用当一个新列被创建时,所有变量重设列类型“column”之后,但如果这列已经被添满这个时间将不发生。

Before Group <x> Init

当一个新组<x>创建时,所有的变量有重设’group’且组名“<x>”被初始化之前调用

After Group <x> Init

当一个新组<x>创建时,所有的变量有重设’group’且组名“<x>”被初始化之后调用

Before Detail Eval

在detail band 被打印之前和所有变量新赋值时调用。

After Detail Eval

在detail band 被打印之前和所有变量赋当前值时调用。

表12.2

在脚本内我们提供所有的字段,变量和参数使用以下的maps(java.util.HashMap),来定义类的属性:fieldsMap,variablesMapparametersMap.

组(如果要显示在报表上的话)能被存取通过属性groups,一个JRFillGroup数组。

iReport处理脚本

如果我们需要为某些报表创建脚本的话,我们可以使用iReport运用它。

图12.1

这个例子中类实现了脚本,将被iReport完全运用。我们可以不使用脚本通过设置报表属性窗口(图12.1)或者指定一外部类(已经编译且放到classpath中)。在这个例子的最后,如果这个类被修改和重新编译,iReport将不可能使用我们最近编译的版本,取决与java类装载器,类在内存中的缓存。

如果脚本已经运用与iReport中,当报表被编译,一个和报表名字一样的新类,后缀是“Scriptlet.java”的文件被创建。例如,如果你有一个test报表,生成的脚本文件的名字就是testScriptlet.java.。

使用iReport生成的脚本不直接的继承JRAbstractServlet。

代替他们继承的是一个名叫IreportScriptlet的高水平的类,它在it.businesslogic.ireport包。除了这么多方法来处理报表之外,一个新类可以提供一些有用的特性来处理这一连串的数据(查看14章);其他的特性将在未来的iReport版本中添加进去。请注意,如果你想用iReport提供的图表,你得用内在支持的脚本。

在iReport中可以通过选择菜单“View → Scriptlet Editor”来修改脚本。 脚本源文件是独立与主报表源文件的,所以你需要在每次改变它之后按 “Save”按钮保存它(查看图12.2)。

图12.2

这个编辑窗口显示了脚本的所有方法/事件,在表单的上面的选择框中。左边显示了所有和脚本代码有关的java对象。双击设计对象,显示相应的代码。可以插入import标识,脚本中新的方法和类成员,选择“<imports and global declarations>”项从选择框中。大多数存取或方法使用表达式插入到脚本中。假设一个例子,你需要打印罗马符号的数字(I,II,III,IV,...)。在这个例子中,就可能要添加一个方法到脚本中,用来将整数转化成用罗马符号写成的数字字符串。就像这样:

public String numberToRoman(int myNumber)

这个语法就是用来转化的,调用这个方法插入到脚本中:

((it.businesslogic.ireport.IReportScriptlet)$P{REPORT_SCRIPTLET}

).numberToRoman ( < my number >)

请注意,我们需要一个外部的引用来调用这个方法numberToRoman ,因为报表引擎将$P{REPORT_SCRIPTLET}只看做一般的脚本。

在这个例子中,我们假设这个类:

it.businesslogic.ireport.IReportScriptlet包含一个名叫numberToRoman的方法。事实上并不是这样的,这儿没有一个numberToRoman方法在这个类中。你得计算REPORT_SCRIPTLET到你的真实的脚本类中

((MyScriptletClassName)$P{REPORT_SCRIPTLET}).numberToRoman( <

my number >)

用脚本部署报表

当报表和脚本一起被编译时,脚本被编译保存到和用来编译报表的jasper文件相同的目录。iReport将这个目录添加到classpath中作为确省的。以这种方式脚本类也将能看到从java和报表中。然而,当报表被配置(就像web application)时,脚本通常会被忘记,那么报表引擎就会抛出一个错误当填充报表时。所以,也需要将脚本类放到应用程序的classpath中。如果脚本继承IReportScriptlet类,你也必须将这个it.businesslogic.ireport.IReportScritplet类(这个类被发布在LGPL许可下)

也添加到classpath中。

13 模板

iReport中最有用的工具之一就是使用报表模板wizard来创建报表,一种pre-built模型作为基础来使用。这章我们将介绍如何建一个通俗模版和如何添加他们到那些已经使用的。

模版结构:

一个模版是一个正规的jrxml文件。当创建写报表时用到这个向导,jrxml文件和被选择模版被加载和修改依照用户的选择。这儿有两种类型的模版:columnartabular 类型。模型创建一组线为每个单独的记录成为静态文本,显示文件名,而textfield显示字段值(图13.1)。

图13.1

二选一,tabular类型显示所有的记录像表一样(图13.2)。

像我们说的那样,模版是jrxml文件(扩展名是简单的xml),他们被加载到templates目录。iReport承认这个名字,如果一个文件包含columnar或tabular的模版:如果一文件名以T结尾,将被用作tabular,如果以C结尾将被解释为columnar。

以下是iReport加载的模版列表:

File

Report type

classicC.xml

Columnar report

classicT.xml

Tabular report

classic_landscapeT.xml

Tabular report

graycC.xml

Columnar report

grayT.xm

Tabular report

gray_landscapeT.xml

Tabular report

表格:13.1

这个向导允许4组以上的创建 (每组的 Group HeaderGroup Footer是相互关联的).这些组将被创建用一个加长的完整的文件仅仅如果在向导执行期间用户用一个或多个标准来分组数据。用这个向导你只能选择一个字段名作为标准。

打开classicC.xml文件,就可以清晰的看到模版的构造。文件包含了四个组:Group1, Group2,Group3Group4 ,分别是:title band(group header)和group footer显而易见。Columns band是隐藏的(因为columnar 报表中的这个band没用),detail有静态的文本标签作为模版的标签,以便每个预备字段就像图13.1,textfield包含真正的字段。Text(或者textfield形式的表达式)依照简单的向导规格关联到text元素,具体的说就是每个组可以包含许多你想要的图形元素和包含简单文本的静态文本元素:

GnLabel

n表示文本元素被放置的地方的组的号,textfield元素包含以下简单的表达式:

GnField

这个元素用组表达式包含值。

图13.2

Detail必须包含最少的文本元素:

DetailLabel

Textfield元素使用表达式:

DetailField

向导复制这两个元素,创建和选择的报表字段一样多的静态text/textfield对。

所有其他的bands能包含任何元素;这些bands在文件从模板生成时将被复制。

Tabular报表模板的设计是一样的。图13.4显示classicT.xml如何生成。

一旦一四个组。他们有column header,需要插入将带的文本来使用作为模型为columns labels。

在detail band中有仅仅一个DetailField元素,它将作为所有columns的模型。

图13.3

Templates不可能被编译,因为在textfields中这些表达式不是有效的java表达式。

使用通用模板

所以,让我们看看如何创建一个通用模板(custom template)。最简单的方法就是打开一个现有的模板,选择一个和我们想法接近的。这时我们就可以编辑报表以我们喜欢的方式,改变现有的元素属性或添加和删除其他元素。

图13.4

为了使用这些模板,你必须放它到templates目录。记着用.xml作为文件后缀。就像图13.5那样命名文件名testC.xml 。记着在写后缀之前将C或T作为文件名的最后一个字符。

如果每件事都ok,通过执行向导,就能看到新的模板在columnar报表模板列表中(图13.6)。

图13.5

然而你可能已经看到了,我们的新custom template没有预览。可能只有查看一个最大150x150像素的gif格式的图片。(这个例子中是testC.gif)。

图13.6

图13.7向导窗口显示了事先的图片为我们的新模板。这个事先图片来自于报表创建时的一个屏幕截图。

模板的使用相对而言提高了报表开发的效率,通过共享图片。

如果你开发了一非常久经世故模板,你想共享它给其他的用户,你就可以将它上传到iReport网站上。

14 图表

JasperReports不是天生就支持显示图表的:他们被单独的生成,用一个或多个java open-source 库来生成图表和作为一个图形元素来显示图片。这个想法非常的简单,然而制作图表在run-time就需要非常好JasperReports 设计技术。需要用脚本来收集显示在图表上的数据。

使用0.4.0版本,iReport有一个无返回值的图表工具。用这个工具就可以通过配置主要的属性和查找数据来打印图表,更加的简单化。图表的创建就完全依靠一个名叫JFreeCharts(0.9.21版本)的javaopen-source库,它是由Object Refinery Limited的David Gilbert开发的,仅有少数的图表属性,但可以创建一个清晰的报表。

创建一个简单的图表

这段我们就来学习chart工具一步一步的创建一个包括3D饼图表,然后我们分析所有的chart管理的细节。

这个例子我们使用HSQLDB中的Northwind数据库作为datasource。

创建新的空白文档,打开查询窗口并输入:

select SHIPCOUNTRY,COUNT(*) AS ORDERS_COUNTfrom ORDERS

group by SHIPCOUNTRY

图11.4

这个想法是制作一个不同国家的销售图表。确定我们的查询ok:iReport将注册选择的字段。拖拽他们到detail中。(图14.1)

图14.2

重设bands的高度(除了summary和detail)。

选择chart工具并放置一个新的chart到summary中。

图14.3

iReport将提示你是否需要内部脚本处理:你选择是。从图表窗口选择饼图并按ok按钮。你将看到图14.2的情形。

接下来配置图表,打开元素属性窗口(双击元素),移动到“Chart”选项卡上,选择“Edit chartproperties”按钮。

图14.4

将看到图表管理窗口(同时显示图表元素创建,图14.5)。

图14.5

这个窗口由三个选项卡组成: Chart type, DataChart details. 第一个可以选择图表的类型:每个图表需要组织级别数据;级别需要通过chart information选择框中列出来的图表。

警告!每次选择不同的图表类型,那么插入到detail选项中data和chart都将被覆盖掉。

这个例子中我们需要标签(Labels)的级数和一个级数值(Serie1)。

移动到Data选项卡。你将看到两行用来输入这两个级的名字,以便满足已选图表的需要(图14.6)。

图14.6

有许多方法可以创建series。这时我们就用最简单:我们许可iReport管理它为我们。选择“Report series”按钮连接到报表的series管理窗口(图14.5)。

图14.7

创建一个新的series用“New series”按钮。在图14.8中将看到。指定series名字,设置“Reset When”为<none>,并指定你想生成的series的字段的表达式。在我们的例子中有string的series为SHIPCOUNTRY和一个series的完整数字(整数)为Series1。

图14.8

为了用表达式编辑,在表达式编辑上点鼠标左键选择“Use texteditor”.

一旦你添加了两个series,回到图14.6窗口选择新的series列表:选择SERIE_COUNTRY作为Labels series和SERIE_ORDERS_COUNT作为Serie1。

警告修改了图表,保存文件和并开始报表用按钮。结果显示在图14.9。

图14.9

级Series

Series表示一些由字符串或数字值组成的一组值。每个图表需要两个或多个数据的series以便更形象。当你选择图表类型(图14.5),窗口底部的表单可以指定已选择的的图表的series。如果你需要一个饼图(一种图表类似于饼的,我们在先前段落中看到的),需要两个series,分别是LabelsSeries1:这个表单包含了不同图表“片”的标签,后面的值表示片。通常当series的标签是“Labels“时,iReport期望series被composed通过设置string对象,另外还有numeric对象(像double或integer)。所有的series关联到同一个图表,并有同一个元素号码。

Series是一个简单的javavector(java.util.Vector)。它可能让iReport自动重建一个或多个series(查看前一段)通过脚本;如果你想更多的控制series(例如当你想创建图表在报表的不同地方),可能要手工的来管理,通过使用IReportScriptlet类的一些方法来放置series。

IReportScriptlet提供一个方法来得到series内容:getSerie()。这个表达式是用来打印series的内容到textfield:

""+((it.businesslogic.ireport.IReportScriptlet)

$P{REPORT_SCRIPTLET}).getSerie(“<seriesName>”)

getSerie方法返回对象,它里面包含了由空字符串联起来的字符串内容。图14.10显示了使用getSerie的例子:每次迭加期间,series对象和和包含在里面的值被打印出来。

图14.10

自动级

自动series是被iReport完全的管理。仅仅需要用户做的一件事就是定义你想生成的series的值的表达式。例如你想收集到值假设通过一个字段,那么series的表达式就应该是这样的:

$F{MyField}

MyField是一个字段名。

要创建自动的series,选择菜单View Report Serie. 这种方式可以得到公告在报表中的series的列表。按New series按钮来创建一个新的series,依照这章前面的例子来创建。

automatic series 存储了从datasource读取的行的数目的一个数字,或者是最后的重设置的series。如果“Reset when“值为series是<none>,在报表的最后series将准确的包含一个和从datasource读取的数字一样的值。“Reset when” 可能是<none>对报表的组的名字:在这个例子中每次重设series,组的表达式都被改变。

手动级

如果automatic series创建机制不适合去创建我们感兴趣的收集(例如,你想创建一个groupsubtotals 的series),就需要手工填充一些series。Series仅仅是一个简单的Vector:IReportScriptlet处理你的配置两个方法来管理Vector,你的series将表现的。这个方法是:

public Boolean addValueToSerie(StringserieName, Object value)

public Boolean resetSerie(StringserieName)

前一个方法允许你添加一个值到指定的series,后一个方法允许你删除series包含的所有的值。

这两个方法都返回boolean对象的值为false。在JasperReports中不可能执行任意的没有用脚本的java指令(像需要填充series的)。然而,下面我们将介绍一个比较游泳技巧来避免这种局限性。这个想法就是在报表中插入一个假的元素,它将永远不会被打印:在这个元素的“printWhenExpression”将执行返回对象值是false的代码。这儿是一个可能的表达式:

((it.businesslogic.ireport.IReportScriptlet)

$P{REPORT_SCRIPTLET}). addValueToSerie(“TEST”,”ciao”)

这个结果是一个值为false的boolean对象,但是当你用addValueToSerie方法添加一个新的元素到“TEST”series时,将被初始化。Manualseries没有在任何地方被公告;他们被创建了,如果不存在,在第一次运行addValueToSerie方法。

现在,让我们看一个简单的例子来模仿这种automatic series的手动机制;创建一个空白文档并设置查询SELECT * FROM ORDERS;

表ORDERS有不同的字段,我们想收集记录中的SHIPCITY字段的假值,并保存名为“TEST”的series的顺序。在detail中插入一小行(line元素),将元素的PrintWhenExpression写入。

((it.businesslogic.ireport.IReportScriptlet)

$P{REPORT_SCRIPTLET}).addValueToSerie("TEST",$F{SHIPCITY})

选择属性以便JasperReport在没有插入line元素时正常运转。

在summary插入一个text元素,那儿将表示已经创建的series。就这样做,用这个表达式为被指定为“TEST”的series的打印:

""+((it.businesslogic.ireport.IReportScriptlet)

$P{REPORT_SCRIPTLET}).getSerie(“TEST”)

结果将是一个空白的detail在报表的最后,所有的城市列表将按照已选择的顺序打印。

通常,一个元素被加到series,这个series被指定当JasperReports求printWhenExpression的值时,在这儿将插入调用的addValueToSerie方法,此时假元素也包含在PrintWhenExpression中被报表引擎遇到;在这个例子中,这个元素通过放置在detail band的line表现。配置同样的元素在不同的band(例如page footer),那么series也就不同了(具体来说就是它被composed通过每页最后一行的元素)。

除非允许准确控制当添加元素到series时,用这个表达式加这个值在这种情形下,

考虑一下下面的表达式例子:

new Boolean(

($F{SHIPCITY} != null &&$F{SHIPCITY}.length() > 3) &&

(((it.businesslogic.ireport.IReportScriptlet)

$P{REPORT_SCRIPTLET}).addValueToSerie("TEST",$F{SHIPCITY})

.booleanValue()))

以上可以简化为:

new Boolean( <expression> &&false )

<expression> 表示:

($F{SHIPCITY} != null &&$F{SHIPCITY}.length() > 3)

FALSE通常调用addValueSerie方法。这两个表达式都是true的话就返回true,如果JVM校验<expression>结果失败,它将不会继续为第二个表达式赋值,以避免去执行addValueSerie方法并发挥false。

Series被识别为简单的字符串,series号也是任意定义的。

“ghost”元素能欺骗addValueSerie方法的执行来重设series的值,通过调用resetSerie()方法。

这些调用被引见在表达式编辑器的规则中(图14.11)。

图14.11

图表类型和属性

iReport允许管理六种不同类型的图表,他们中的每一中通过一些属性来定义,这些属性中的一些能定义所有的图表类型,另一些是各自的特性。

如果series表现数据来画一个图表,这些属性可以修改它的样子,可以在图表属性窗口(图14.12)的“Chart Details”选项卡来修改。

图14.12

以下是对所有图表的通用属性的概括。

 

Charts basic properties

Width

图表的像素宽度,通常也是元素的宽度

Height

图表的像素高,通常也是元素的高度

Zoom

表示图表图象质量的要素:预置值是2,也就是图表图片的高度和宽度都为2。

Chart title

图表的标题,如果不指定,图表就没有标题

Subtitle

图表的副标题,如果不指定,图表就没有副标题

Title position

依照图表确定标题的位置;能值是: Top, Bottom, Left和Right和显示图象的位置:

                         |

 

 

                         |

Chart Background

图表的背景色(包括画title,legend, 等时)

Plot Background

图表的背景色(图表轴之间的扁平区域)

Antialias

指定是否使用平滑

Show tooltips

指定是否显示tooltip,这是一个黄色的标签用来显示图表点的值(或者是用来说明饼图的薄片)

Show legend

指定时候显示图例

表格14.1

饼图

饼图是最简单的图表在iReport中,它可以形象化的用数字表示series(Serie1)用series标签(Labels)。它没有除了公共属性以外的特殊属性。

图14.13

3D饼图

3D饼图和饼图是一样的,只是使用了三维效果。

图14.14

Pie3D chart properties

 

Depth factor

表示饼图的高度值(图14.14使用的值是0.2)

Foreground Alpha

图表的透明度(图14.14使用的值是0.33)

柱状图

在iReport中除了饼图(简单和3D),其他所有图表都使用CategoryDataset数据结构,它是以种类组成的一组series值。为柱状图表,也为其他图表,需要三级值:Values,CategoriesSeries。他们被解释以下面的方法:每个和series相关的作为同一类别。如果你仅仅想要一组值,series是一样,而类型是变化的。

Valore

Serie

Categoria

1.0

Serie 1

C1

4.0

Serie 1

C2

3.0

Serie 1

C3

5.0

Serie 1

C4

5.0

Serie 1

C5

7.0

Serie 1

C6

7.0

Serie 1

C7

8.0

Serie 1

C8

如果你保持category的数量和改变series,你将有仅仅一个标签(category值)和一种颜色为每个series:

Valore

Serie

Categoria

1.0

Serie 1

Type 1

4.0

Serie 2

Type 1

3.0

Serie 3

Type 1

5.0

Serie 4

Type 1

5.0

Serie 5

Type 1

7.0

Serie 6

Type 1

7.0

Serie 7

Type 1

8.0

Serie 8

Type 1

如果你想更形象化不同categories,你需要指出series和categories所属的每个值。

Valore

Serie

Categoria

1.0

Serie 1

Type 1

4.0

Serie 2

Type 1

3.0

Serie 3

Type 1

5.0

Serie 4

Type 1

5.0

Serie 1

Type 2

7.0

Serie 2

Type 2

7.0

Serie 3

Type 2

8.0

Serie 4

Type 2

通常这对(Value, Category)被看成X和Y轴的值。这个series允许为同一个category设置同一个值。

Bar chart properties

 

Plot orientation

Bars方向;以前例子中预先设置的值是vertical,这儿是一个水平方向的例子:

Foreground Alpha

图表的透明度(适合具有彩色背景)

Value label

Label为axe(XY轴)的值

Category labela

Label 为categories axe

3D柱状图

Bar3D图表和Bar的特性一样,除了具有三维外表。

图14.15

线图

线型图表被penalized(处罚)通过使用CategoryDataset ,因为因为最后一个不工作和x,y相陪的值,在Y轴和X轴的“categories”。

图14.16

和柱状图一样,每个series有相应的颜色,线在“categories”没有有意义数字时被断开。

这个问题将在未来的iReport版本中解释XYDataset的Line Chart。

Line chart和柱状图有一样的附加属性。

区域图

最后一个是区域图。它和Line chart工作原理一样,但X轴和线之间的区域被完全的涂上颜色。通过适当的选择Foreground Alpha属性,可以使图表非常的独特。

图14.17

此时iReport管理JFreeChart的可能性很小:图表的特性将在未来发布的版本中管理的越多越好。

15 插件和附加工具

它可能扩充iReport的功能依靠plugins,外部的应用程序模型设计来执行多方面的任务,比如安置一个元素用特殊标准,或者将编译的jasper文件放到BLOB数据库中。

Plugins在iReport启动时被加载通过选择菜单“Plugins”(图15.1)。

 

图15.1                            图15.2

图15.3

选择菜单“Tools Plugin configuration”可以打开插件列表配置他们(图15.3)。

每个插件被创建通过继承抽象类it.businesslogic.ireport.plugin.IReportPlugin和写一个XML文件包含插件展开的指示。这个类必须添加到classpath中,XML文件也必须放到iReport根目录下plugin目录下。所有的XML文件在这个目录被处理来启动相应的插件。

iReport伴随两个插件Massive compilerText Wizard,此外还有一个简单的“Hello World!”插件作为例子。

插件结构XML文件

插件结构XML文件,使用展开的描述符,是很简单的(这儿是DTD描述他们的标记)。

<?xml version="1.0" encoding="UTF-8"?>

<!--

Document : iReportPlugin.dtd

Created on : 19 maggio 2004,8.09

Author : Giulio Toffoli

Description: This DTD definethe XML descriptor for an iReport plugin.

-->

<!--

iReportPlugin is the rootelement.

ATTRIBUTES:

name The name of plugin

class The class that extends

it.businesslogic.ireport.plugin.IReportPlugin

loadOnStartup If true, theplugin will be instanced on iReport startup

hide If true, this pluginwill be not visible on plugin menu

-->

<!ELEMENT iReportPlugin (Author?,Description?, IconFile?)>

<!ATTLIST iReportPlugin

name NMTOKEN #REQUIRED

class NMTOKEN #REQUIRED

loadOnStartup (true | false)"false"

hide (true | false)"false"

configurable (true | false)"false">

<!ELEMENT Author (#PCDATA)>

<!ELEMENT Description (#PCDATA)>

<!--

Icon file should be a file in the classpath i.e. com/my/plug/in/icon.gif

Is used as optional icon formenu.

Dim: 16x16

-->

<!ELEMENT IconFile (#PCDATA)>

根元素是iReportPlugin以及他们的属性:The root element is iReportPluginand here are their attributes:

Name  是插件的名字;

class   是实现插件的java类;它必须放到和所有必须的类一样都添加到classpath中;如果需要一个jar来运行插件,你还得把它放到iReport的lib目录下;

loadOnStartup  iReport保持在内存中的一个plugin实例:设置属性为true就可以强制iReport在启动时实例化plugin,而不需要等待用户的指令;

hide  如果设置为true,这个属性能被隐藏在plugin中(将被隐藏在所有和插件有关的菜单入口);

configurable  如果设置为true,iReport将激活“Configure”按钮为plugin,在窗口显示图15.3。

如果你想指定作者的名字为plugin(,现在不使用Author标签),一个小plugin描述(标签描述)和一个16x16像素图标,这个图标被使用在菜单中:自图标文件被加载作为java源,这标签的值必须是classpath中的路径(例如:/it/businesslogic/ireport/icons/menu/new.gif)。

以下是XML文件用来激活“Example 1”插件以便iReport加载。

<iReportPlugin

name="Example 1"

class="it.businesslogic.ireport.plugin.examples.HelloWorld"

loadOnStartup="false"

hide = "false"

configurable = "true">

<IconFile>/it/businesslogic/ireport/icons/menu/new.gif</IconFile>

<Description>

This example shows how to create a very simple

plugin for iReport.

</Description>

</iReportPlugin>

要卸载插件,只要删除plugin目录下的XML文件即可(或者改变它的扩展名,只要和.xml不同就可以)。

it.businesslogic.ireport.plugin.IReportPlugin类

最困难的部分就是讲述plugin程序的编写。你需要创建一个新的java类继承it.businesslogic.ireport.plugin.IReportPlugin类。这个类包含两个“切入点”,他们是configurecall方法;第一个仅仅在plugin有“configurable”标签时被调用,和更正确当用户使按钮可见时图15.3(theuser hits the button

“Configure” visible onfigure 15.3)。第二个方法是在用户选择菜单中plugin名字时被调用(图15.1)。

这儿是IReportPlugin类的源代码。

package it.businesslogic.ireport.plugin;

importit.businesslogic.ireport.gui.MainFrame;

/**

* This class must be extended by alliReport plugin.

* To install a plugin into iReport, put theplugin xml in the plugin

* directory of iReport.

* See plugin documentation on how to createa plugin for iReport

* This is the first very simple interfaceto plugin. I hope to

* don't change it, but we can't say whatit'll happen in he future...

*

* @author Administrator

*/

public abstract class IReportPlugin {

MainFrame mainFrame = null;

String name = "";

/**

* This method is called when the plugin isselected from the plugin menu

*/

public abstract void call();

/**

* This method is called when the pluginconfiguration button on plugin

* list is selected.

* Configuration file of plugin should bestored in

* IREPORT_USER_HOME_DIR/plugins/

*/

public void configure(){}

/**

* Retrive the plugin name. Please note thatthe plugin name must be

* unique and should be used as filename forthe configuration file if

* needed. This name can be different fromthe name specified in XML,

* that is the name used for the menu item.

*/

public String getName(){

return name;

}

/** Getter for property mainFrame.

* @return Value of property mainFrame.

*

*/

publicit.businesslogic.ireport.gui.MainFrame getMainFrame() {

return mainFrame;

}

/** Setter for property mainFrame.

* @param mainFrame New value of propertymainFrame.

*

*/

public void setMainFrame(

it.businesslogic.ireport.gui.MainFrame mf){

this.mainFrame = mf;

}

}

你已经看到了,仅仅有一个抽象方法call。事实上,configure方法是被实例化了(没有返回体),这是因为没有更多意义来强迫用户去实例化它当用户没有使用插件时(也就是当插件不是可配置的)。

这是个好想法来定义一个插件构造器,不需要争议和设置一个值为这个类的name属性。Plugin一被实例化,iReport就调用plugin的setMainFrame方法来填充mainFrame属性,这个属性涉及到iReport的核心类:通过这个类你可以访问报表,你可以编译,你可以修改iReport的结构等等。

现在我们把焦点放到方法call上。我们已经谈论过这个情况,iReport为每个plugin创建并保存一个实例在内存中:意思就是说call方法不是线程安全的。这就是建议我们继承IReportPlugin的类应该是一种容器为真正的plugin;call方法应该在入口出运行plugin代码。根据这点可以用两种方式来描述plugin:一个是简单的持久实例化,但要避免调用两个连续的plugin,另一个是多重的“不稳定的“实例化,在plugin代码结束时消失:意思就是说当plugin每次被执行时创建一个新的实例,当call方法被实例化时。

以下是一个plugin用持久实例化工作的例子清单。

public class MyPlugin extends IReportPlugin{

MyPluginFrame frame = null;

Public MyPlugin()

{

setName(“my sample plugin”);

}

/**

* This method is called when the plugin isselected from the plugin menu

*/

public t void call()

{

if (frame == null)

{

frame = new MyPluginFrame();

}

if (!frame.isVisible())frame.setVisible(true);

}

}

这个例子中的MyPluginFrame类是plugin的核心类,它展示在任何时间,当用户从菜单上选择这个plugin时。Massive compilerplugin就是以这种方式工作的。 Plugin窗口能被打开关闭很多次,但却从来不会分开,永远保持一个状态。

如果你想创建一个不同与plugin核心类在plugin每次被执行时被实例化,需要对call方法做一些修改:

public class MyPlugin extends IReportPlugin{

Public MyPlugin()

{

setName(“my sample plugin”);

}

/**

* This method is called when the plugin is selectedfrom the plugin menu

*/

public t void call()

{

MyPluginFrame frame = new MyPluginFrame();

frame.show();

}

}

这个例子中,当用户启动这个plugin时,一个新的MyPluginFrame类型的窗口将被打开。

这里包含了plugins的所有信息,我们使用一部分和iReport有联系的代码:

MainFramemf = MainFrame.getMainInstance();

这种用法返回一个和MainFrame有关的对象;

mf.getActiveReportFrame();

这个调用返回现行的报表窗口(JReportFrame),从这个窗口可以通过调用getReport()方法找到报表对象。

我们非常支持开发新的插件。如果你有任何关于这个话题的建议,或者可以澄清如何实现一个新的插件,不要害怕和我们联系。:)

大型编译器插件

Massive compiler是一个编译大型jrxml文件的工具。它是有用的当你想迁徙到一个新的JasperReports版本:在这个例子中,为避免版本冲突,你还得重编译老的源文件。

图15.4

当plugin被启动时,将显示一个窗口用来选择编译的文件。你可以输入或者用“browse“按钮选择存储在编译目录中的文件(你可以强制plugin在子目录中查找,通过选择可选框” Search Sub Directories “)。按”find“按钮,将列出所有一.jrcml或.xml结尾的文件。我们仅仅选择这些文件来编译,通过按“Compile selected file(s)”按钮。

如果你想你可能替代这个老的.xml文件用新的.jrxml文件。如果.jasper文件已经存在详细的文件,它可能会创建一个备份,创建新报表之前拷贝老文件。

如果有错误放生当编译文件时,一个警告图标显示在左边的文件名上。双击连接到这个叫人厌恶的文件,你就能看到错误细节(图15.5)。

图15.5

文本向导插件

plugin Text Wizard被创建是用来简单化文本报表的生成(基于字符的报表)。目的是用标签和字段建一个列表格式的报表。

当你启动这个插件,他确定打开的报表的宽度和改变宽度。通过按“Check for fields widths”按钮,包含变量的报表字段被刷新。字段名字的右边,有其他两列;第一个包含了最小值,就是需要显示的全部内容的字段的数目(这个信息可以通过用JDBC驱动的ResultSetMetaData返回来得到);第二列可以手动的改变字段的最小长度:这个值被切断后的所有字符。

按“Add elements”按钮添加标签和字段安置到报表中。每一个Textfield都将设置一个表达式来截短包含的值,就像这样:

( (($F{XYZ}!=null)&& ($F{XYZ}.length() >50)) ?

$F{XYZ}.substring(0,50) : $F{XYZ})

这个例子上的字段,XYZ可能有一个最小长度值是50个字符。

图15.6

如果字段的值的长度超过50,它将被截短。

16 常规问题解决方案

这章我们将处理一些我们在使用iReport和JasperReport过程中遇到的常见问题。他们是iReport论坛上常见的问题,但JasperReport官方文档也没有清楚的解决方案的。

打印百分比

经常需要在报表上显示一个字段的值和与这个值有关的百分比。考虑表16.1中的这几行。

A

B

C

香蕉

10

20%

橘子

25

50%

草莓

15

15%

表格16.1

这个例子的百分比插入在C列,它表示B列中的值所占的百分数。用以下公式计算得出:

C = (ΣB*100) / B             (1)

ΣB =所有B列的值的和

尽管这个公式看起来很容易就算出了百分比,但公式(1)不适合在JasperReports中计算。这是因为公式使用的值是无效的在公式被使用时;具体来说ΣB是获得报表最后的值,就是当所有的记录被处理以后。然而,你要使用的B的值仅仅在计算(1)记录结果时。这儿没有简单的方案为这个问题。唯一的计算总数的方式就需要最终的百分比(先前例子中的ΣB )。当你预先计算你需要的值,你可以将它作为参数传递给报表。公式(1)就将变为:

newDouble(($P{TOTAL_OF_B}.doubleValue()*100)/$F{B}.doubleValue())

TOTAL_OF_B代表包含你计算的值的参数

计算组的发生数

每个组在JasperReports中和一个表达式关联。在报表生成期间,表达式的值一改变,一个新组开始发生一些事情。有时必须计算组的数量(计算组的值改变了多少次)。照这样做,需要一个变量:我们将命名为GRP_COUNT;基本思路就是仅仅当变量<group name>_COUNT 等于0时增加变量。<group name>_COUNT是一个JasperReports的内置变量,它包含当前组<group name>的记录数目。自一个任意组的变量<group name>_COUNT等于0仅仅一次,GRP_COUNT将正确包含组出现的次数。

图16.1

图16.1中的例子用到的查询:

 “select * from customers order by country” 和COUNTRY组的表达式:$F{COUNTRY}.

声明变量GRP_COUNT :

Class: java.lang.Integer

Calculation type: Count

Reset type: Report

Variable expression: (($V{COUNTRY_COUNT}.intValue() == 0) ? "" :null)

这个表达式是说:如果你计算当前组的实例的第一条记录(记录号为0),然后返回一些非空的东西,也返回null值。自我们选择count作为计算类型,

变量GRP_COUNT将增加仅仅当表达式的值非空时,就说当当前组的第一条记录被计算时。

图16.2

显示这个值到textfield,你设置元素表达式的赋值时间到这个组来计算发生次数,在我们的例子中使用COUNTRY组(图16.3)。

图16.3

图16.4

图16.4可以看到打印结果。在空白框中显示了组号。

如果evaluation time设置到“Report”, 组发生的总次数就将被打印出来。

分离detail

有时需要将detail分开成更多的bands。主要是为了在一些情形发生时在一个指定的detail band中用另一个来替代。这些情形必须用band PrintWhenExpression 测试过。可能有任意数量的detail bands创建新组,这些新组用一个组表达式,这个表达式在每条记录后改变值。你可以用来作为记录的关键字段表达式或一个计算变量。使用这种方式,此外在detail band中,你将有每条记录的group header和groupfooter,不能用同样的方式使用这个detail band。

图16.5可以看到报表的设计,detail band被隐藏到一对新组的header bands的剩余空间,这个使用一样的组表达式:这条记录关键字。

选择选项为第一组,我们能一页打印一条记录。

图16.5

插入一个页

JasperReports不提供任何方法来插入一个页和band合用。意思就是说你在一个页上呈现多个detail。下面的例子中将分detail在两页上:第一页我们想显示客户的名字的代码,第二页打印客户地址。

完成这个例子,我们将打印每条记录在一个新页上:这种方式是我们期望在一页上有一条记录在两页的内容。

让我们一步一步来,首先我们将创建一个组在一个空白报表上,我们指定组的表达式$V{REPORT_COUNT}和检查组标“Start on a new page”:我们用这种方式得到每条记录的在同一页上。现在我们去分开detail。接下来我们使用一个没有任何连接和datasource(我们设置子报表的连接属性为“Don’tuse connection or datasource”)的子报表。准备创建这个子报表通过一个简单空白文档,且设置margins为0。

图16.6

也设置所有的bands的高为0(title band和summary band除外)。在我们用做子报表的报表属性选择选项“Title on a newpage”和设置“When no data”值为AllSectionNoDetail

所有来自与主报表字段的值将作为参数传递;所以我们声明所有需要的参数。我们例子中需要四个字段:

- CUSTOMERID

- COMPANYNAME

- CITY

- REGION

那么放所有你需要的textfields到报表中。请注意所有插入到title band中的元素被打印在第一页,另外,放在summary band中的字段将在第二页被打印。返回到主报表,将字报表插入到detail band中。

图16.7

我们填充子报表参数用正确的表达市在主报表中(更准确的说,我们填充子报表参数表在“Subreport(Other)”选项卡,查看图16.8)。

图16.8

编译主报表和子报表并运行打印,如果一切ok,将看到类似图16.9的结果。

图16.9

交叉报表

JasperReports不支持交叉报表,指报表的行和列都变化的报表。

以下表格是一个交叉报表的记录,显示了所有有效年代的生产记录:

Prodotto/anno

2003

2004

2005

Fragole

900

950

1000

Lamponi

400

500

600

年代不可预言的,取决与取到的数据。

这种情形,最常用的方法为这种报表就是去固定一个列的最小号显示,手动填充一个datasource(例如JRJavaBeanArrayDataSource)来组织每行的值。这种方式我们很难想象到将出现的数据。

如果供应许多的列比你需要的(例如,报表能显示后5年的信息,但是你仅仅有前3前的信息),你的工作就是加一个假值做为字段值替代null或空白字符或短字符(-)。

使用多重连接找回数据

有时你需要重新找回更多的数据比在单独一个datasource,在同一时间。去达到这个,解决方案依赖你严密的想法。通常执行多个问题的方法就是使用子报表。此时你可以说点什么关于我们必须连接子报表,你能设置不同的表达式为每个子报表。你可以使用两个连接中的一个作为参数传递给报表。

如果不能分别找回数据通过不同的datasource用子报表,你得实现一个“lookup”方法,就像用一个静态类,或者添加它到报表脚本中。Lookup方法可以重新找回数据从任意的datasource。

以下的例子表现了一个简单的lookup类。用这个类去解码一个国家的名字给一个国家的代码。这个方法被传递一个已经打开的JDBC连接和代码作为参数去解码

Publicclass LookUp {

public static String decodeState(java.sql.Connectioncon, int code)

{

java.sql.Statement stmt = null;

java.sql.ResultSet rs = null;

try {

stmt = con.createStatement();

rs = stmt.executeQuery(

"select STATE_NAME from STATES wherecode=" + code );

if (rs.next())

{

return rs.getString(1);

}

return "#not found!";

} catch (Exception ex)

{

return "#error";

} finally {

if (rs != null)

try { rs.close(); }

catch (Exception ex2) {}

if (stmt != null)

try { stmt.close(); }

catch (Exception ex2) {}

}

}

}

调用这个方法,传递作为不同数据连接,你可以得到你想要的数据从不同的数据库。

如何使用存储过程

JasperReports不支持使用存储过程来找回数据去打印。为避免这个局限性,你可以在运行报表之前执行存储过程。

重新找回数据用存储过程能被插入在临时表格中,你可能执行一个查询,或者如果他们很少,你可以把他们作为参数传递给报表。在最后,这个临时表将被删除。如果你的存储过程可以返回一个ResultSet,你可能包含它在一个datasource用JRResultSetDataSource 

原创粉丝点击