iReport使用教程(三)
(2011-12-07 17:41:18)
标签:
ireport使用教程杂谈 |
分类: 技术杂记 |
六、独立性与易集成性
前面可能把整个过程讲述的很复杂,其实,在整个建立与输出报表过程中,是一气呵成的。iReport与JasperReport是紧密相关的,而除此之外,它们的独立性非常好。
利用jasperReport+iReport生成并输出报表,可以方便的嵌入“胖客户端”以及WEB工程,以公安项目为例。
此项目是基于Struts结构的,浏览器端的请求是通过ActionServlet来传递的,依照项目要求,我们只要把已经做好的jasperReport实例导入到项目里即可。导入方法可参考如下:
首先,把相关jar包导入到工程的lib文件夹下,搭建必需的环境;
其次,新建Action类,并将其对应的路径等相关信息加入xml配置文件中;
然后,如同输出html文件一样,将输出代码拷贝到Action类中,实现流的输出即可;
最后,将原实例中的相关处理类拷贝到项目中,调整包的路径,使之正常运作即可。
这时,只要修改某些页面的链接即可完成报表的输出。
七、其他相关问题
如何使用图片?
很容易,用Image控件就可以了. 在Image Express 里面可以用String来表示图片的路径, 或者用InputStream, File 对象.不过不管用File 还是String 对象, 都不得不用绝对路径, 这显然很不灵活.解决办法是,穿入一个$P 的参数,表示图片所在的目录,然后用$P 和文件名拼接出完整的绝对路径. 或者通过代码来控制, 比如System.getProperty("user.dir")+"\\report.jpg"就表示图片的绝对路径。更好的方法是用InputStream, 例如his.getClass().getResourceAsStream ("report.jpg") ,这时只要把图片放在当前.jasper所在的 目录就可以了,不必考虑什么参数,什么路径。
动态控制某些Field 是否显示
每个Static Text, Text Field 甚至整个Band 的属性里面都有Print When Expression, 比如设成new boolean(!$P{isDisplay}.equalsIgnoreCase("yes")), 那么只有当参数display的值为yes 的时候才显示。
使用Sub Report, 如何使用相对路径
和使用图片类似,最好使用InputStream 或者传入参数。
Query里面如何使用参数
$P!{xxx} 或者 $P{xxx} 后者只能用于类似PreparedStatement参数绑定, 而前者可替换Sql 的任意部分. 在需要动态排序的时候, 前者特别有用. 比如select a,b,c from t order by $P!{orderClause} 不管用$P 还是$P!, SQL最终是以PreparedStatement 方式执行的, 不必太担心性能问题 注意:参数是不能嵌套的,比如$P{a} =''$P{b}'' , $P{b}=''value'', 不要指望$P{a}能被替换成''value''
如何使用图表(Graph)
JasperReport 本身没有图表功能, 只有显示Image 的功能,iReport 里有个Graph 向导, 其实质是通过jFreeChart 生成Image. 另外, 更直接的做法是放一个Image控件, Image Express Class 设置成java.awt.Image, 在Image Expression 里通过自定义的类返回java.awt.Image对象.
例如GraphProvider.getImage($P{REPORT_DATASOURCE},title, subtitle.....);GraphProvider是自己的类, public static Image getImage(JRDataSource, ....)
如果显示多个图表
在一张报表上显示一个图表和显示多个图表是不同的. 假设Query 是selectname,price,qty from xxx, 第一张图显示name-price, 第二张图显示name-qty, 如果还是按上面的方法, 第二张图根本显示不出来! 为什么 因为传入的是JRDataSource, 而JRDataSource仅仅是对ResultSet的简单封装, 在第一张图处理完后, 游标已经到了eof 位置了, 在开始处理第二张图的时候,就必然抛出游标耗尽的异常! 怎么办?自己写个JRDataSourceAdapter,把JRDataSource对象里面的值预先保存到一个Collection (相当于一个Offline的数据集), 然后把这个Collection传个getImage方法. 具体是, 建一个Variable mydate, 类型是java.util.Map, Calculation Type- System,Initial Value Expression 是JRDataSourceAdapter.JRDataSource2Map($P{REPORT_DATA_SOURCE}, new String[]{"NAME","PRICE","QTY"},
new Class[]{java.lang.String.class,java.lang.Double.class,java.lang.Double.class}); JRDataSource2Map 是自己写的一个Adapter. 然后在Image 的Expression 里面换成如GraphProvider.getImage(mydata,title, other params...), 当然得修改getImage方法
Export到Excel的问题
如何去掉报表头
直接把不需要的Band 删除(把其高度设为0). 如果仅仅是export 到Excel 的时候不需要报表头, 而输出到PDF 等仍然需要保留, 那么使用print when expression, 见前面
如何让Excel 看起来整齐
不要有空白地方,首先把所有的Field 设成一样高, 对齐! 把所在Band 的高度也设成和Field 一样高, 让Field 正好放入Band. 然后调整Field 的宽度, 让每个Field 都相邻,没有空隙.(如果设置正确,所有的Field 边框在鼠标点中的时候显示蓝色,否则是绿色) 最后,记得设置参数:
exporter.setParameter(JRXlsExporterParameter. IS_REMOVE_EMPTY_SPACE_BETWEEN _ROWS , Boolean.TRUE);
如何保留GridLine
首先, 设置参数exporter.setParameter (JRXlsExporterParameter. IS_WHITE_PAGE_BACKGROUND , Boolean.FALSE);然后,把每个Field 或者Static Text 框的''Transparent''属性都勾上
如何使字段名只显示一次
如果把字段名放在ColumnHead 区域, 那么输出到Excel, 会每个Page 都显示一遍. 在设计Report 时候, 一般会设定Page 大小. 然而对于Excel, 这个Page设定仍然存在,而且往往很讨厌, 因为在Excel 里, 通常希望得到连续的数据, 然而Jasper 仍然会''自作多情''进行分页. 比如说, 设计JasperReport 的时候, 设定page size为Letter, Portrait, 那么输出到Excel 的时候每隔大约30 行(具体取决于Field 的高度), page header, column header, column foot, page foot 会被重复一次,而且还附带一个高度为0 的Excel Row, 表示Page Break 的地方. 把字段名放在title band 里, 可以解决字段名重复的问题, 当然page header也不要显示了. 如果需要, 可以把title band的print when expression设成只有输出Excel的时候才显示为什么Excel 里面的数据是从第二行,第B列开始显示的。
因为第一行和第A列分别是用来表示page top margin 和 page left margin的.对于Excel 来说, 纯粹多余. 解决方法是把page margin 设成0. 不过如果这个report 还需要以PDF 等显示, 那么设成0 就不好看了. 最好能动态的改变pagemargin. 当然,这个改变只能在外部(调用eport 的地方) 进行, 在设计Report 的时候是无能为力的. 不幸的是, JasperReport 类居然没有setMargin 的方法,只有getter.折中的方法只能是reflect 了. 代码示意如下:
//use reflect to set the private field of JRBaseReport
java.lang.reflect.Field margin =
JRBaseReport.class.getDeclaredField("leftMargin");
margin.setAccessible(true);
margin.setInt(jasperReport,0);
margin =
JRBaseReport.class.getDeclaredField("topMargin");
margin.setAccessible(true);
margin.setInt(jasperReport,0);
margin =
JRBaseReport.class.getDeclaredField("bottomMargin");
margin.setAccessible(true);
margin.setInt(jasperReport, 0);
如何去掉Excel 中隐藏的行
如前说述, 由于page break 的关系, Excel 中每隔几十行,就有一个高度为0 的row, 即使把page botom margin设为0, 把page footer去掉都没有办法. 唯一的解决办法是把page height 设为很大. 同上面一样, 不得不使用reflect:
java.lang.reflect.Field pageHeight=
JRBaseReport.class.getDeclaredField("pageHeight");
pageHeight.setAccessible(true);
pageHeight.setInt(myRpt, Integer.MAX_VALUE);
八、HTML的Bar3D图表输出心得
图表在ireport中是利用其他开源包生成的图片插入而生成,本人使用的版本是使用jfreechart1.0.0开源包实现。Ireport对jfreechart的支持不算完美,只是实现了部分的图表生成,但对于一般项目,也是足够用的。
对于图表的数据来源,和报表一样,也有多种来源,并不局限于数据库,而本人推荐的依然是javabean。用户只要在定义好图表的各项数据(比如:横坐标数据,纵坐标数据,横坐标标签,纵坐标标签,分类标准等等),jasperreport+jfreechart会自动进行数据的分类统计输出,这点是很人性化的。
看过jasperreport的源代码,发现,图表在HTML格式输出的时候,首先是输出一张图片,或者放在具体目录下,或者放在临时的response里,然后进行调用、输出展示。(如果选用后者的输出方式,需要注意:1.x版本后的输出需要对web.xml进行配置,配置一个servlet进行输出。)这样就造成了一个问题,就是当多用户同时访问页面的时候,用户看到的数据是正确的,但是图片却可能是别人产生的图片!
这可能是由于HTML浏览器对图片的引用时机不对,解决的方案是这样的:由于HTML格式的输出是字符形式的(PDF是二进制流形式的),所以我们选择首先把整个图表输出到字符缓冲区中,然后进行一次性输出,这样,我们辅助浏览器完成对图片引用时机的修正。当然,也可以这样做:通过修改源代码,把图片输出到不同的临时目录,这样的话,想引用错基本都不可能了J
在HTML输出的时候,一定要记得设置编码格式,通过exporter的CHARACTER_ENCODING属性来设置。而且,在HTML中输出的时候,可以不对报表进行分页操作,即取消分页。
还有,jfreechart默认输出的图片是进行抗锯齿处理过的。对于图形来说,这样会让图像显示的更圆润,而对于文字来说,可能就会显示变得模糊。解决方案:修改源代码。可以修改jasperreport的源代码,也可以修改jfreechart的源代码,只需按照如下代码进行改进即可:
jfreechart.getRenderingHints().put(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
上面的代码将图片输出的文本抗锯齿关闭,而图像依然有抗锯齿处理,所以图片相对好看。不过,有一点需要注意:字体尽量是宋体,字号最好在12到14之间,这样能达到最好的显示效果。