利用复合的javabean构造基于jasperreports的子报表

最近非常高兴看到新版本的jasperreports和ireport发布,虽 然只是增加了一些不实用的功能(编译期错误处理还值得称道),虽然感觉修正的bug不如新出现的bug多-_-!!,虽然新的版本一如既往的难以使用…. 但无论怎么说,开源的jasperreports和开源的ireport仍然为我们的报表开发带来了很多方便之处。
闲话少说^_^,这几天公司开发的系统基本完工了,考虑到后期客户需要,在统计 和查询模块可能需要添加报表下载功能,查询还好办,统计的话就涉及到报表的嵌套。比如我们在统计一个公司的业绩时,需要在公司总表中列出各个部门,并对各 个部门(不确定的部门个数)进行统计并汇总到公司总表中。甚至的,部门下面还可能有子部门…,提供报表下载时,对部门的统计需要做成子表嵌到公司表中,而 且,部门表统计的数据源是取自公司表数据源中的一部分….。
情况大体如上面所述,按照一般的报表设计思路,我们可能是先通过数据库查询公司 总表,获取公司的部门id号并把id号传递给部门子表,再分别让部门子表去从数据库获取数据进行统计。这样做我们必须在处理前把jdbc connection传递给jasperreports,让jasperreports进行数据库的读取操作。而在我们的系统中,统计的数据其实已经在后 台处理完并封装到了一个复合的javabean中(复合bean:比如一个表单vo对象中还有其他的vo集合),之所以不使用jasperreports 处理统计主要是考虑到了业务处理的需要。单一的.jasper很难根据多种业务需求进行变通,如果使用javabean,我们可以利用web服务器的缓存 避免重复的数据库连接操作,而且在javabean中,我们实际上可以在下载前对统计数据进行一定的变动,比如可以再次进行人工处理….
前次,我曾经介绍过可以通过使用 JRBeanCollectionDataSource()返回一个JRDataSource,当时javabean 的数据类型都是原始类型,不曾碰到过使用集合类的复合javabean。这次考虑仍然使用javabean 来构造数据源,由于对ireport的datasource的处理机制不是很熟悉,经过很多次尝试后才摸索出一个往子报表插入特定数据源的办法(不是传递 父报表的数据源,而是将父报表的一个变量当成数据源传递给子报表!)
DEMO:
准备工作:
一、程序准备:
1、 创建复合javabean :MainVO.java:(getter和setter方法自写)

package com.test;
import java.util.List;
public class MainVO {
private String title;
private String time;
private List subList;
}


2、 创建子表javabean:SubVO.java(getter和setter方法自写)

package com.test;
public class SubVO {
private String name;


3、 创建JRAbstractBeanDataSourceProvider:TestSubReport.java

package com.test;
public class TestSubReport extends JRAbstractBeanDataSourceProvider {
public TestSubReport() {
super(MainVO.class);
}
public JRDataSource create(JasperReport arg0) throws JRException {
/**
*测试数据,在使用中,不需要继承JRAbstractBeanDataSourceProvider,
*只需要把集合类封装到JRBeanCollectionDataSource中就可以了
**/
List mainList = new ArrayList();
List list = new ArrayList();
MainVO vo;
/**测试数据自写*/
……
return new JRBeanCollectionDataSource(mainList);
}

4、 创建外部测试类:TestMain.java:

public static void main(String[] args) {
String filename = "bin/SubReport.jasper";
String outFileName = "bin/Out.html";
/**测试数据mainList自写*/
try {
JasperPrint print = JasperFillManager.fillReport(filename, new HashMap(),new JRBeanCollectionDataSource(mainList));
JRExporter exporter = new JRHtmlExporter();
exporter.setParameter(JRExporterParameter.OUTPUT_FILE_NAME, outFileName);
exporter.setParameter(JRExporterParameter.JASPER_PRINT, print);
exporter.exportReport();
} catch (JRException e) {
e.printStackTrace();
}
}

5、 创建Scriptlet:reportScriptlet.java
注意: 如果你从父报表传给子报表的数据源是个集合类型,且不需要任何的数据处理,这步可以省略,但需要注意我在第二部分的第7步骤的提示。
该类是用来进行类型转换的,要想让jasperreports识别数据源就必须把集合类封装到JRDataSource中。由于父报表把数据源传递给子报表是在afterDetailEval()方法之后,因此只需要重写该方法:

package com.test;
public class reportScriptlet extends JRAbstractScriptlet {
/**其余方法省略*/
@Override
public void afterDetailEval() throws JRScriptletException {
System.out.println("afterDetailEval...");
List subList = (List)getFieldValue("subList");
JRDataSource jr = new JRBeanCollectionDataSource(subList);
/**
*该值是在父报表中定义的一个变量Variables,
*类型为net.sf.jasperreports.engine.JRDataSource
*(需要手动填写Class Type)
**/
setVariableValue("other", jr);
}
}

该Scriptlet供父报表使用
二、报表准备
由于ireport的汉化很不完整,这里就使用英文的界面做demo(有兴趣汉化的,可以编辑位于ireport.jar包的it.businesslogic.ireport.locale下的Ireport_zh_CN.properties)。
1、 创建父报表:SubReport.jrxml,通过菜单栏:Data -->Connections /Datasources -->new选择JRDataSourceProvider定义如图:

[img]/upload/attachment/108376/a9467d0d-08c7-3b36-bb64-cb2e2e1fc00e.png[/img]


Test 成功后(前提是先在ireport的classpath中设置工程编译文件夹路径)save。
2、 设置另一个数据源(给子报表用)在这里我选择了使用Custom JRDataSource

[img]/upload/attachment/108378/087b16c3-557c-31fd-812d-6b4d6cf324dc.png[/img]


使用Custom JRDataSource这里我必须在项目中编写一个额外的类用于测试:

package com.test;
public class CRDSFactory{
public static JRDataSource createDatasource(){
List list = new ArrayList ();
/**测试数据自写*/
……
return new JRBeanCollectionDataSource(list);
}
}

Test 成功后 save。
3、 注册字段Fileld
利用菜单中的Data --> Report Query -->DataSource Provider 获取字段,然后全选获取到的字段点击确认注册。

[img]/upload/attachment/108380/f9434cec-28da-3360-be76-32921aa7ef99.png[/img]


4、 添加变量Variables
该变量用途是作为父报表传递给子报表的数据源,所以类型为JRDataSource
如图:

[img]/upload/attachment/108382/ef373796-411b-3831-9185-6b615a890223.png[/img]

5、 创 建子报表: SubReport_subreport0.jrxml,(名字由系统生成) 点击工具栏中的”SubReport”图标,并确定好子报表的位置,利用系统的wizard一步一步设置,注意在第2步设置 ”Connection/Datasource ”时最好选择”no connection or datasource”,因为我们的datasource是父报表中的一个变量)
6、 将ireport的Files视窗的其他报表文件关闭(大概需要这样,前几次因为没关闭出了点问题,不清楚什么原因)如果看不到Files视窗,可以通过菜单的View --> Docking panes -->Files 回显。单独选择刚才为该子报表而设置的数据源“custds”,通过刚才的Report Query -->JavaBean Data Source读取子报表相关的javabean属性。选择后点ok将其注册到Fields中。如图:

[img]/upload/attachment/108384/d9d0b2d8-991b-3845-a3bc-81c8e89fc828.png[/img]

7、 打开父报表,在设计窗口的子报表上右键,选择Properties -->SubReport,设置由父报表传递给子报表的数据源:

[img]/upload/attachment/108386/2dd1fe49-ff8f-34c7-a3d7-f8c3c1c0ccd5.png[/img]


提示:如果你略过了第一部分的第5步,这里的“ $V{other} ”要改成“ new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($V{other})”

8、 依 次编译(使用动态连接)子报表、父报表(注意数据源的对应关系),如果能通过父报表看到子报表的内容被填充,则说明测试成功了!如果不成功,检查刚才设置 是否有遗漏的地方,最好重新创建子报表,有时并不是我们设置问题,ireport目前还不是很稳定,在编译和保存数据时很容易出错,有时连子报表都不认 -_-!!
9、
效果图:(没有修饰,确实很难看…)

[img]/upload/attachment/108388/950db3ac-764c-3fa7-aced-cad7fa2d36c7.png[/img]


注意事项:
♦ 熟悉jaspereports的以手动编辑代码为主, ireport为辅,使用ireport时有时也必须手动编辑jasperreport,特别是在编译出错的时候。
♦ 不能把父报表的一个变量同时传递给多个子报表,不然可能只能显示一个或什么都不显示,如果需要这么做,请定义多个变量。
♦ 子报表的添加不要用旧报表,即使你的旧报表是刚才使用的子报表。
♦ 如果子报表还要嵌套子报表的话,可以通过为子报表编写一个Scriptlet实现。
不过要清楚的是子报表有可能不执行afterDetailEval()和beforeDetailEval()(比如使用jdbc连 接,这也许跟子报表的数据源选择有关),最好先测试,具体原因希望达人告知!
♦ 在使用ireport进行开发时,当修改了某个类时,就需要重启ireport才能看到修改的效果,即使是使用ireport的Scriptlet编辑器也一样。
♦ 不是越高版本越好用,主要是缺少使用文档,连javadoc资料都很贫乏,推荐1.3.0,1.3.0的已经有出document了,不过需要$才行,也不好买到。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值