最近的这个项目本来用润乾报表,但大家都知道润乾很贵,而我们这个项目只是一个100w左右的项目,于是考虑使用开源报表,由我和一个同事来调研比较流行的jasperreport和birt报表。经过调研总结,jasperreport的一个致命伤是不支持导出doc格式,虽说可以导出rtf格式,但大家都知道它们不一样,就单说导出的表格中的文本竟然是一个个的文本框,客户当然不会满意。在说导出的excel,很多行和列都隐藏了,与自己在excel中输入的数据显示差别太大。究其原因,我觉得jasperreport的工作区其实就是个画板,如同photoshop一样,拖拽组件到工作区,靠得是xy绝对定位,这样导出到word,excel这些相对定位的软件中必然会出现如文本框之类的问题。而birt的工作区如同Dreamweaver,是相对定位,把组件拖拽到工作区就和在Dreamweaver中几乎一模一样,能导出doc,xls,ppt,pdf等格式,并且导出后非常兼容,客户也比较满意,我们就决定使用birt。
对于birt的入门网上也有很多,就不写了,这里写几个项目中比较实用的功能。
1、数据源为JAVABEAN:这个功能其他一些报表如jasperreport也有,个人认为用javabean做数据源既有安全方面的优点,又有处理复杂业务数据来源的好处。安全是因为如果数据源直接连接到jdbc,如果别人通过下载你这个报表文件可以很容易看到数据库地址等信息,即使不能下载也享受不到连接池的好处。当然你可能会说了,我用连接xml的方式可以用连接池啊。恩,是的,这个目的达到了,但如果我们的业务很复杂,单纯用sql语句无法得到我们想要的数据怎么办呢?不行了吧?因此要么你在数据库中写好存储过程来作为数据集,要么就用javabean吧。
使用javabean做数据源的具体操作,我也是从网上找的一篇文章才会的。具体到项目中,其实就是在struts的action里写一个方法,来返回一些数据,比如一个list,list里是一个javabean。而在birt里新建数据源时要选择Scripted Data Sourse,新建数据集时选中刚建的数据源,在Output Columns中自己建和javabean里一模一样的属性。之后选中这个数据集,在工作区视图中选择Script视图,在其中的open、fetch和close中写一些类似java有类似JavaScript的语句。
比如在open中写
importPackage(Packages.youraction);
myparams = reallyAction.getparams();
iteratorparams = myparams.iterator();
在fetch中写
if(iteratorparams.hasNext() == false ){
return false;
}
var params = iteratorparams.next();
row[1] = params.getName();
row[2] = params.getPwd();
...
return true;
在close中写
myparams=null;
iteratorparams=null;
params=null;
之后在视图中把整个dataset拖拽到工作区中就可以显示了。
2、嵌套表:就是在一个大表格(dataset1)中的一个单元格内嵌套另一个小表格(dataset2),这个小表格的其中一个字段是外键,是大表格的主键。小表格即dataset2数据集要加入where 外键=?,再把小表格拖拽到单元格中后,在Binding中的Dataset Parameter bingding...中选择外键的值为大表格的主键,确定后预览就可以看到效果了。
3、批量替换数据源:我们有很多的报表文件,开发用的数据源和部署的数据源地址是不一样的,这样必须每个都要修改其中的url,user,pwd等等,非常麻烦,虽然可以新建数据源时从文件中读取数据源,但也必须要打开每个报表文件,重新再导入这个文件,也是非常的繁琐。其实报表文件就是一个xml文件,我们只需要解析这个xml文件的data-sources及其下面的标签就可以了,我自己做了一个工具,用户输入要更新报表的数据源名称,再选择一个报表文件或整个报表文件夹,之后输入要更新的url,user,password,点击执行就可以了,当然这里password的Base64加密也处理了。可以点击下面的附件下载这个工具。
4、birt的标签:一般使用birt都会使用它的标签,在网页中显示一般使用report标签,这里注意一下,又一个属性reportContainer如果不写,则默认birt显示在一个iframe里,我觉得放在iframe里最不好的地方就是由于报表一般都很大,这样除非你把iframe设置的宽度和高度非常大,否则是有滚动条的,这样有时你会看到有两个滚动条。而且有时报表是动态的,这样很不好控制iframe的大小,所以我加入了reportContainer="div"属性,这样就用div而不是内嵌一个iframe了,所以最多只有一个滚动条了。
再有一般报表都比较大,而我们的界面一般使用框架,导致报表不能全屏显示,这时可以在页面加载后用js把其他的frameset置为0,并把报表放在一个div中,报表页面中加个返回按钮,按钮的js恢复frameset大小,并把报表的div隐藏,就ok了。当然有可能由于页面有一些select的查询条件不能盖住,那就加个iframe的z-index为1,报表的z-index为2就行了。
最后要注意:报表文件最好放在WEB-INF下,防止别人下载。
对于birt的入门网上也有很多,就不写了,这里写几个项目中比较实用的功能。
1、数据源为JAVABEAN:这个功能其他一些报表如jasperreport也有,个人认为用javabean做数据源既有安全方面的优点,又有处理复杂业务数据来源的好处。安全是因为如果数据源直接连接到jdbc,如果别人通过下载你这个报表文件可以很容易看到数据库地址等信息,即使不能下载也享受不到连接池的好处。当然你可能会说了,我用连接xml的方式可以用连接池啊。恩,是的,这个目的达到了,但如果我们的业务很复杂,单纯用sql语句无法得到我们想要的数据怎么办呢?不行了吧?因此要么你在数据库中写好存储过程来作为数据集,要么就用javabean吧。
使用javabean做数据源的具体操作,我也是从网上找的一篇文章才会的。具体到项目中,其实就是在struts的action里写一个方法,来返回一些数据,比如一个list,list里是一个javabean。而在birt里新建数据源时要选择Scripted Data Sourse,新建数据集时选中刚建的数据源,在Output Columns中自己建和javabean里一模一样的属性。之后选中这个数据集,在工作区视图中选择Script视图,在其中的open、fetch和close中写一些类似java有类似JavaScript的语句。
比如在open中写
importPackage(Packages.youraction);
myparams = reallyAction.getparams();
iteratorparams = myparams.iterator();
在fetch中写
if(iteratorparams.hasNext() == false ){
return false;
}
var params = iteratorparams.next();
row[1] = params.getName();
row[2] = params.getPwd();
...
return true;
在close中写
myparams=null;
iteratorparams=null;
params=null;
之后在视图中把整个dataset拖拽到工作区中就可以显示了。
2、嵌套表:就是在一个大表格(dataset1)中的一个单元格内嵌套另一个小表格(dataset2),这个小表格的其中一个字段是外键,是大表格的主键。小表格即dataset2数据集要加入where 外键=?,再把小表格拖拽到单元格中后,在Binding中的Dataset Parameter bingding...中选择外键的值为大表格的主键,确定后预览就可以看到效果了。
3、批量替换数据源:我们有很多的报表文件,开发用的数据源和部署的数据源地址是不一样的,这样必须每个都要修改其中的url,user,pwd等等,非常麻烦,虽然可以新建数据源时从文件中读取数据源,但也必须要打开每个报表文件,重新再导入这个文件,也是非常的繁琐。其实报表文件就是一个xml文件,我们只需要解析这个xml文件的data-sources及其下面的标签就可以了,我自己做了一个工具,用户输入要更新报表的数据源名称,再选择一个报表文件或整个报表文件夹,之后输入要更新的url,user,password,点击执行就可以了,当然这里password的Base64加密也处理了。可以点击下面的附件下载这个工具。
4、birt的标签:一般使用birt都会使用它的标签,在网页中显示一般使用report标签,这里注意一下,又一个属性reportContainer如果不写,则默认birt显示在一个iframe里,我觉得放在iframe里最不好的地方就是由于报表一般都很大,这样除非你把iframe设置的宽度和高度非常大,否则是有滚动条的,这样有时你会看到有两个滚动条。而且有时报表是动态的,这样很不好控制iframe的大小,所以我加入了reportContainer="div"属性,这样就用div而不是内嵌一个iframe了,所以最多只有一个滚动条了。
再有一般报表都比较大,而我们的界面一般使用框架,导致报表不能全屏显示,这时可以在页面加载后用js把其他的frameset置为0,并把报表放在一个div中,报表页面中加个返回按钮,按钮的js恢复frameset大小,并把报表的div隐藏,就ok了。当然有可能由于页面有一些select的查询条件不能盖住,那就加个iframe的z-index为1,报表的z-index为2就行了。
最后要注意:报表文件最好放在WEB-INF下,防止别人下载。