Birt 报表参数的使用

来源:互联网 发布:查看mac激活时间 编辑:程序博客网 时间:2024/05/16 01:47

序言

参数是 birt 提供的一种很重要的机制,在 birt 中,参数具有变量的作用,它为 birt 报表的生成提供了一种灵活强大的机制。本文基于 Birt 2.1.2 讲述 Birt 报表中一些重要的用法以及 birt 源码级的参数使用机理,为报表开发者以及报表应用程序开发者提供一个参考。

本文的示例是基于 Birt RCP designer 2.1.2 开发的,在阅读本文前,最好有 eclipse 相关经验,并且已经能够使用 Birt 插件制作一些简单报表,并了解 Birt 报表的一些基本概念,比如 Data Source(数据源),Data Set(数据集)等。基本报表制作过程可见 developerworks 相关文章"BIRT:基于 Eclipse 的报表"。

本文示例使用 Birt 自带的 Sample 数据源,用到的数据基于图 1 所示的实体关系模型。从这个模型中可以看出,文中示例用到三张数据库表分别为 customers,orders 和 orderdetails。其中 customers 表的 customernumber 字段作为外键出现在 orders 表中,而 orders 表的 ordernumber 字段做为外键出现在 orderdetails 表中。

图 1. 实体关系模型
实体关系模型

1 标量参数(Scalar parameter)

在使用 BIRT 参数的时候,首先要了解 BIRT 分为报表参数和数据集参数。 报表参数定义于整个报表内,而数据集参数定义于某个数据集(Data Set)中。 数据集参数使用的时候通常需要链接到某个报表参数或者利用绑定表(binding tab)和一个嵌套表中的某个数据元素绑定。

标量参数是Birt报表中最简单也是最基本的一类参数,标量参数可以分为静态和动态两种,其中静态参数从用户界面获得用户输入的数据值,而动态参数则可以关联至某一个数据集,因此可以获得一个数据的集合,供用户选择。 下面分别介绍这两种参数。

1.1 静态标量参数

右键点击Outline面板中的Report parameter选项,在弹出的上下文菜单中点击“New parameter”,弹出图2所示编辑参数对话框,在name域输入参数的名字,本例中使用的参数名字为“customernum”,此时List of value项默认为static。 点击OK后返回到开发主界面。

图 2. 编辑参数
编辑参数

接下来定义Data Set。Data Set定义的对话框如图3所示。 在这个对话框中首先定义“Query”。 我们可以看出Where条件中的customernumber字段通过”?”代表的参数传入参数值。

图 3. 数据集中的“查询”定义
数据集中的“查询”定义

点击”Parameter”,弹出在数据集中定义参数的对话框。 数据集中的参数需要链接至某一个报表参数。 在本例中将数据集参数链接至前面定义的报表参数customernum。 点击OK,我们就完成了数据集中参数的定义。当报表运行时,Birt会使用由报表参数customernum传入的值填充where条件,生成结果数据集。 如图4所示。

图 4. 数据集中的“参数”定义
数据集中的“参数”定义

1.2 动态标量参数

动态参数可以提供一个数据值的列表供用户选择,这种功能能够极大增强报表设计用户界面的交互性。

在本例中,我们首先定义一个数据集,这个数据集不使用参数,它从订单表中查询出所有的订单号,为报表参数提供一个数据值的列表。 如图5所示。

图 5. 数据集“ordernum”
数据集“ordernum”

接下来,我们定义报表参数,这个参数链接至前面的ordernum,因此可以根据数据集中的参数ordernum动态的获得可选值。 如图6所示。

图 6. 报表参数“ordernumpara”
报表参数“ordernumpara”

如图中所示参数的display type选成Como Box,List of value选择为Dynamic,其链接至的Data Set选择为前面定义的ordernum数据集,同时选定Select value column为数据集ordernum中的某个字段,这里ordernum数据集只有一个字段,故选择为ordernumber。 这样就将报表参数和数据集参数关联起来。但这不是我们的最终目的,我们的目的是以报表参数ordernumpara为中介,向另一个数据集提供参数。 因此,我们定义图7所示的数据集。

图 7. 数据集“ordersdetail”
数据集“ordersdetail”

点击“Parameter”项,进入数据集参数定义界面,如图8所示。

图 8. 将数据集内的参数连接至报表参数“ordernumpara”
将数据集内的参数连接至报表参数“ordernumpara”

将本数据集的参数num链接至ordernumpara,就完成藉由一个报表参数为中介将一个数据集的字段值链接到另一个数据集的参数的功能。

2 Cascading Parameter

除了使用动态报表参数提供数据值的选择列表,报表开发过程中用户经常需要用到互相关联的参数。 比如要选择某个客户的某个订单号标识的所有订单的内容,用户并不愿意列出所有可能的订单号,比较理想的情况是给出一个客户编号的选择列表,根据这个列表的内容再给出每个客户的所有订单号的列表,这样用户就可以选择相应的客户对应的某个订单号,从而查询出此客户的这个订单号标识的所有订单的详细内容。 Cascading parameter 一方面增强了报表逻辑的功能;另一方面,通过将一部分应用逻辑转移到界面操作上,进一步降低了报表内部逻辑和SQL查询语句的复杂性。

首先定义一个customer数据集,这个数据集 包含customernumber和customername两个字段。如图9所示。

图 9. 数据集“customer”
数据集“customers”

接着定义一个名字为orders的数据集,如图10所示。

图 10. 数据集“orders”
数据集“orders”

在“Orders”数据集中使用一个数据集参数,这个数据集参数将要引用接下来将要定义的层叠参数中customer参数。 定义了以上数据集之后,我们就可以来定义层叠参数了。

右键点击Outline面板中的Report parameter选项,在弹出的上下文菜单中点击“New Cascading Parameter”,弹出以下对话框,在Cascading Parameter name域输入参数的名字,本例中使用的参数名字为“custorder”,Data Set Model选择为Multi Data Set。 在紧接着的Parameters表中定义一个名为customer的参数,并将其关联至customer这个数据集,其取值为customer数据集中的customernumber字段,这样customer这个层叠参数的取值就是一个customernumber的列表。 Customer此时也成为一个动态参数。 如图11所示。

图 11. 层叠参数定义1
层叠参数定义1

完成customer的定义后,我们紧接着定义另一参数order,方法和定义customer相同,最后order参数和数据集orders关联,其取值为orders数据集中的ordernumber字段。 由于数据集orders的局部参数需要和前面定义的customer参数关联后才能产生数据结果集合,因此,在下一步将数据集orders与参数customer完成关联后,order这个层叠参数也将成为一个动态参数,它也成为一个数据值的选择列表,这个列表的值是由某个customernumber决定的所有可能的订单号。 如图12所示。

图 12. 层叠参数定义2
层叠参数定义2

接下来将orders数据集中的参数param1关联至层叠参数customer,如图13所示。

图 13. 关联数据集“orders”中的参数至层叠参数“Customer”
关联数据集“orders”中的参数至层叠参数“Customer”

最后,定义生成报表的数据集orderdetail,如图14所示。

图 14. 数据集“orderdetail”
数据集“ordersdetail”

然后将其局部参数param1关联至层叠参数order,如图15所示。 这样我们就完成了具有Cascading parameter功能的数据集的定义。

图 15. 关联数据集“Orderdetail”中的参数至层叠参数“Order”
关联数据集“Orderdetail”中的参数至层叠参数“Order”

从主开发界面中将orderdetail数据集拖拽到主开发面板上就完成了这个简单的报表的制作。见图16

图 16. 层叠定义完成后的主开发界面
层叠定义完成后的主开发界面

点击preview,会弹出如图17所示对话框。 从这个对话框中我们可以看到层叠参数customer的数据是customers数据库表中的所有客户,选定一个客户后,层叠参数order的列表将只出现客户TechnicsStoreInc的所有订单,选择其中一个订单后,就会从orderdetail数据表中选出这个订单号标识的所有订单的详细内容。

图 17. 层叠参数用户界面
层叠参数用户界面

3 Parameter Group

在某些情况下,在创建报表的时候需要提供大量的参数,为了在界面上更加有效地对这些参数进行组织,BIRT提供了parameter group的功能。 用户可以使用parameter group将相关的parameter组织在一起。

Parameter group的使用比较简单。 首先需要创建一个parameter group。在outline视图中用鼠标右键点击report parameters标签并选择new parameter group。 创建完parameter group后便可以为其创建parameter。 为一个parameter group创建parameter有两种方式。一种方式是用鼠标右键点击parameter group标签并选择new parameter创建新的parameter;另一种方式是将已有的parameter添加入parameter group,只需要使用鼠标将所需要的parameter拖拽入parameter group中。 如图18所示是parameter group的一个例子。

图 18. Parameter Group示例
Parameter Group示例

4 使用parameter实现nested tables

前面的例子展示了如何将BIRT中的report parameter与data set parameter进行binding。 作为BIRT parameter的另一个例子,我们下面通过介绍data set parameter与data colummn的binding实现nested tables。 本节将通过JDBC Dataset和Scripted Dataset分别介绍实现过程。

Nested table主要用于存在外键关联的两个或几个表。 比如customer与order是1:N的关系,order表中存在外键custmernumber。 有些时候,我们要将customer与相应order的信息一起进行展现,这时就需要使用nested table。

4.1 使用JDBC Data Sets

首先,在Birt数据源的基础上创建两个数据集CustomerSet(OuterSet)和OrderSet(InnerSet)。

CustomerSet用于获取所有Customer的信息,在layout视图下右键点击“Data Explorer”中的“Data Sets”图标并选择“New Data Set”,选择数据源并填写Data Set名称为CustomerSet;然后点击next填写数据源的query语句。 OrderSet用于获取指定Customer的Order信息,与CustomerSet的创建过程类似。 由于OrderSet作为内嵌表,需要关联参数CumtomerNumber,因此需要在创建OrderSet的时对查询语句提供where子句“where CLASSICMODELS.ORDERS.CUSTOMERNUMBER=?”。 CustomerSet和OrderSet的创建过程如图19,20所示。

图 19. 数据集CustomerSet
数据集CustomerSet
图 20. 数据集OrderSet
数据集OrderSet

然后为其创建相应的dataset parameter,在“Data Explorer中”双击OrderSet,创建一个dataset parameter名称为CNo,设定其DataType为integer,DefaultValue为任意整数,如图21所示。

图 21. 数据集参数Cno
数据集参数Cno

在创建好数据集的基础上,我们就可以在报表界面上面创建nested table了。 首先创建显示一个customer信息的外层OurterTable,编辑OuterTable的Data Binding并设置与其绑定的DataSet为CustomerSet,然后在OuterTable中并添加需要显示的字段信息并为nested table预留一个空白列。 如图22所示。

图 22. 外层表示意图及数据集绑定
外层表示意图及数据集绑定

下一步在OuterTable中空白列的detail行中创建显示order信息的InnerTable,设置与其绑定的DataSet为OrderSet,并添加需要显示的字段,如图23所示。 最后为InnerTable创建DataSet parameter binding,在InnerTable的Data Binding对话框中点击“Dataset Parameter Binding”按钮,设置参数CNo的value是row[“CUSTOMERNUMBER”],如图24所示。

图 23. 内嵌表
内嵌表
图 24. 数据集参数绑定
数据集参数绑定2

至此,nested table的创建过程完成,我们可以通过选择preview视图查看报表的输出结果如图25所示。

图 25. 程序执行结果
程序执行结果

4.2 使用Scripted Data Sets

本小节中将介绍如何使用两个Sripted Dataset实现nested table。 仍然以customer和order为例,并以CustomerName作为关联外键。

第一步创建数据集。 首先创建一个Scripted Data Source,然后以此创建两个数据集CustomerSet和OrderSet,在CustomerSet中创建两列CustomerNo和CustomerName,在OrderSet中创建三列OrderSet、Content和CustomerName。 最后为OrderSet创建一个DataSet Parameter CName,Data Type为String,Direction为Input,Default Value为任意整数,如图26所示。

图 26. OrderSet的数据集参数CName
OrderSet的数据集参数CName

第二步在报表界面上创建外层表(OuterTable)和内嵌表(InnerTable),并设置与其绑定的Dataset分别为CustomerSet和OrderSet,步骤与4.1小节类似。 然后为InnerTable创建Dataset parameter binding,设置参数CName的value为row[“CustomerName”]。

由于我们使用的是Scripted Data Set,因此在本例中我们需要使用Birt Sript构造一些数据,并实现数据集的数据获取。 首先,在报表的beforeFactory方法中构造数据,代码如下所示。

报表的beforeFactory方法
importPackage( Packages.java.util );importPackage( Packages.java.lang );var outerMap = new Hashtable();var innerMap = new Hashtable();var customer = new Array(2);for(var i=0;i<2;i++) {var array = new Array(2);    array[0] = ""+i;    array[1] = "customer_"+i;    customer[i] = array;}outerMap.put(1, customer[0]);outerMap.put(2, customer[1]);var order = new Array(5);for(var i=0;i<5;i++) {    var array = new Array(2);    array[0]=i;    array[1]="order_"+i;    order[i]=array;}var orderList1 = new ArrayList();orderList1.add(order[0]);orderList1.add(order[1]);var orderList2 = new ArrayList();orderList2.add(order[2]);orderList2.add(order[3]);orderList2.add(order[4]);innerMap.put(customer[0][1], orderList1);innerMap.put(customer[1][1], orderList2);reportContext.setPersistentGlobalVariable("outerMap", outerMap);reportContext.setPersistentGlobalVariable("innerMap", innerMap);

然后,为CustomerSet和OrderSet添加script代码。

CustomerSet的open方法代码如下所示。

CustomerSet的open方法
outerMap = reportContext.getPersistentGlobalVariable("outerMap");iter = outerMap.entrySet().iterator();

CustomerSet的fetch方法代码如下所示。

CustomerSet的fetch方法
if( iter.hasNext() ) {customer = iter.next().getValue();row["CustomerNo"] = customer[0];row["CustomerName"] = customer[1];return true;} else {return false;}

OrderSet的open方法代码如下所示,其中inputParams[“CName”]就表示了绑定的Detaset parameter CName的值。

OrderSet的open方法
i = 0;customerName = inputParams["CName"];iMap = reportContext.getPersistentGlobalVariable("innerMap");orderList = iMap.get(customerName);

OrderSet的fetch方法如如下所示。

OrderSet的fetch方法
if (orderList == null)    return false;if (i < orderList.size()) {    order = orderList.get(i);    row["OrderNo"] = order[0];    row["Content"] = order[1];    row["CustomerName"] = customerName;    i++;    return true;}else return false;

至此,使用Scripted数据源的nested table的创建过程完成,我们可以通过选择preview视图查看报表的输出结果如图27所示。

图 27. 程序执行结果
程序执行结果

5 源代码级的参数使用

对于报表应用程序开发者而言,有时他们需要在源码一级控制报表参数。 接下来我们将讲述birt报表在源代码一级是怎样处理报表参数的。

下面的程序片段是使用birt提供的API进行应用程序开发的一个基本框架,如果想获得更加详细的内容,请参考Birt API的源代码。

清单1主要是进行报表引擎的设置和初始化,其主要目的是将Birt Home设置为Birt runtime下ReportEngine的安装目录。

清单1
//创建一个报表引擎配置对象EngineConfig config = new EngineConfig();//设置 BIRT报表引擎的安装路径config.setEngineHome("C:/birt/");

清单2就是打开一个报表设计文件。 报表设计文件就是指我们利用Birt报表开发工具开发的XML格式的,以.rptdesign为后缀的文件。

清单2
//创建一个报表生成引擎ReportEngine engine = new ReportEngine(config); //打开一个报表设计文件IReportRunnable design = engine.openReportDesign("C:/temp/test.rptdesign");

清单3、4、5是处理报表参数,清单6是创建生成报表的任务,清单7是将处理好的参数设置给报表。 清单8是进行一些输出选项的设置,比如生成什么格式(pdf,html等)的报表,结果输出到哪里(文件,输出流等),最后就是运行生成报表。

其中清单3、4、5负责处理参数。 清单3使用前面一步创建的设计文件对象生成一个IGetParameterDefinitionTask类型的paramTask,paramTask调用getParameterDefns方法获得报表中所有参数的定义,注意这里参数使用false,其效果是将报表中的parameter group 扁平化,从而以标量的形式返回所有的参数。 这样可以将参数处理的复杂性进行封装,为应用程序开发者提供简单的使用接口。 清单4是属于用户定制的步骤,因此本文没有给出相关源码。 在这一步里,用户可以通过GUI 对话框或者HTML表单动态的输入参数值,参数值一般存储到一个HashMap中。 清单5主要负责将第四步获得参数值赋给清单3中获取的参数定义。这三部分合起来就构成了birt API中处理参数的主要步骤.

清单3
//以打开的报表设计文件为参数,创建一个获取参数的对象IGetParameterDefinitionTask paramTask = engine.createGetParameterDefinitionTask(design); //获取报表设计文件中的参数定义Collection parameters = paramTask.getParameterDefns(false);
清单4
接受由html表单或GUI弹出的对话框输入参数值,假设输入的参数及其值以名/值对的形式存储在一个HashMap类型的变量paramValues中。
清单5
//为获取的参数定义赋值HashMap parameterMap=evaluateParameterValues(parameters,paramValues);
清单6
//创建生成报表的任务对象IRunAndRenderTask task = engine.createRunAndRenderTask(design);
清单7
//为报表生成任务设置参数集合对象task.setParameters(parameterMap);
清单8
//创建报表render选项对象IRenderOption options = new RenderOption();//设置输出格式(PDF,HTML等)options.setOutputFormat( format );// 设置输出文件options.setOutputFileName( targetFile );//设置render options对象task.setRenderOption( options );

清单9为最终运行生成报表的方法。

清单9
//运行生成报表task.run();

清单10是具体为报表中定义的参数赋值的过程。 其主要思路是遍历清单3中获得参数集合,将其与清单4中传入的参数值以名/值对的方式存储在一个HashMap中。

清单 9
//为报表设计文件中定义的参数赋值private HashMap evaluateParameterValues( Collection paramDefns,   HashMap params) {  HashMap inputValues = new HashMap( );  Iterator iter = paramDefns.iterator( );  while ( iter.hasNext( ) )  {    IParameterDefnBase pBase = (IParameterDefnBase) iter.next( );    if ( pBase instanceof IScalarParameterDefn ) {      IScalarParameterDefn paramDefn = (IScalarParameterDefn) pBase;      String paramName = paramDefn.getName( );      String inputValue = (String) params.get( paramName );      int paramType = paramDefn.getDataType( );      try {        Object paramValue = stringToObject( paramType, inputValue );        if ( paramValue != null )  {          inputValues.put( paramName, paramValue );        }      }      catch ( BirtException ex ) { }    }  }  return inputValues;}

6 结束语

Birt是一款非常强大的报表开发工具,它为报表开发提供了非常多的功能强大的特征,参数就是其中最重要的一种。 本文总结了birt报表开发过程中对参数的各种用法以至源代码级的使用,旨在为报表开发及报表应用程序开发提供一个有益的参考。

参考资料

  • BIRT官方网站 http://www.eclipse.org/birt
  • BIRT Community Wiki http://wiki.eclipse.org/index.php/BIRT_Project
  • BIRT:基于 Eclipse 的报表 http://www.ibm.com/developerworks/cn/opensource/os-ecl-birt/
  • 浏览 developerWorks 上的全部 Eclipse 文章和Eclipse 教程。
0 0
原创粉丝点击