由于最近使用到了ireport,把使用过程当中所遇到的问题跟大家一起来分享下。
1:首先这个工具它是面费的,同时又是用java来编写的。整个界面看起来视觉效果还是比较好的。
2:支持使用存储过程、函数、试图等方法。灵活。
3:它在编译的时候生成.jasper 和 .xml。用的时候只需要把这两个文件copy到你用的服务器地址下即可。
下面是一些基本的说明:
入门
另外附上入门的基本操作,不过现在已经是2.0的版本了,并且是一个极其简单的到处都有的例子,数据源是oracle.
前提是需要配置classpath(java都是这一套),如果是oracle,那么只要ojdbc14.jar即可,如果你有安装oracle企业版本,或者oracle的管理工具可以在目录D:\oracle\product\10.2.0\db_1\jdbc\lib\下找到(我们假设是安装在d:\oracle),无需到网络下载,或者到处copy。
1)配置数据源.
选择 DATA-资料/来源 (估计这个是台湾或者香港或者海外华人翻译的菜单),然后在出现的界面选择NEW.
点击next后,按照出现的下图,选择JDBC驱动以及数据库链接路径,输入用户和密码.(假设安装的时候有hr方案).
2)新建一个文档或者说是新建一张报表,菜单是档案->开启新档 (CTRL+N)典型的台湾翻译.
"字段数“原文是column count,其实翻译为”列数“更好一些,意思是一个页面按照纵向分为几个部分,例如有输出为
id, name .如果你选择字段数=2,那么输出的就是形如:
1 Jack 4 BeckHam
2 Mike 5 Rose
3 Tony
自己试验下最清楚。
3)设置需要的表格区域.
默认的可用区域包括(这在所有的报表中英文都是band):TITLE,PAGEHEADER,COLUMNHEADER,DETAIL,COLUMNFOOTER,PAGEFOOTER,LASTPAGEFOOTER,SUMMARY.
不是所有的表格区域都是需要的,常用就是title,columnheader,detail,pagefooter,summary我们可以把不需要的隐藏起来. 在报表空排区域右键单击,在弹出的菜单上选择"栏的属性",把bandheight参数设置为你需要的值,如果不想显示该区域(或者是band或者是栏)可以设置BANDHEIGHT=0.
4) 输入sql
建议用快捷的图标,就是最上一排,大概中间靠右的地方有个圆柱体的图标(鼠标移动到上面会出现database的提示),
点击一下,在出现的窗口输入sql语句如下:
5)摆放字段和设置标题
有工具还是好的,否则工具就没有什么意义了. 点击菜单预览->docking panes->document structure,然后你自己摆放好文档结构栏板,在出现的栏板上展开fileds节点,如图:
注意,这里很重要的: 选中"姓名",按住左键不放,拖到detail 栏目上,然后依次拖动其它三个字段.
顺便说一下,这样的操作对于document structure 中的variables和parameters中的成员也是成立的,对于LIBRARY中变量也是一样的(就是上图的下面部分,显示"page number"等等的地方).
至于对齐这些报表元素,不用说了吧? 看看最下面一栏的快捷按钮你应该明白的.
从最上面一排快捷按钮中找到"不回动的文字"(别扭的翻译),其实就是文本标签. 先点击左键然后放开,然后移动鼠标到columnheader区域,再按住左键不放,在区域中拉出一个矩形区域,则可在该区域放上一个文本标签.依次操作放上其它三个,也可发挥ctrl+c,ctrl+v的功能完成其它三个.
6)设置pagefooter和summary内容.
通常我们都会在页脚放置诸如 "x页/共y页"的字样. 按照前面所说的拖动方法,从library栏板中拖动"page x of y"到pagefooter区域. 然后你可以分别修改需要显示的内容为:"第 " + $V{PAGE_NUMBER} + " 页 " ,"共" + $V{PAGE_NUMBER} + "页".
7)第一次预览.
8)加sql参数条件和计算行数.
通常我们的SQL都会有条件存在的,首先我们假设要查询月薪>=特定数值的员工的报表,则先在DOCUMENT STRUCTURE 栏板(或者面板)中右键单击,选择菜单 add->parameter,
如果你自己不知道应该选择什么类型,但是又需要知道新的参数是什么类型,那么最好的办法是查看detail区域上月薪字段的数据类型,一看是java.math.BigDecimal,那么好,就设置为java.math.BigDecimal.
如果是字符串类型,一般你就不要new然后再转换了,直接输入字符串即可,不过需要加上引号.
修改sql(如前,点击圆柱体图标即可),加上以下语句:
where salary>=$P{salary} ,注意$P表示参数的前缀,$V表示变量的前缀,$F表示字段,名称则在中括号输入.
在summary 栏板中添加变量report_count,然后修改数据类型为字符串,并修改表达式为:"累计人数:"+$V{REPORT_COUNT}.
9)试验一个简单的ireport 折线图
做图是比较有意思的地方,因为美啊! 必须说明的是,例子用的ireport 是2.0.0.
本来想下载jasper的说明,一看要钱,还是$的,就打消了主意,还是自己来吧。
做折线图是比较常见的,没有什么特别的,不过有几点还是需要注意的:
1)构建可用的sql语句,这里有很奇怪的技巧要求,也许以后jasper会修改它们的解析机制.
2)设置图数据集,包括x,y轴的参数,
3)把chart图放置在正确的打印区域(band)
9.1 正确的sql
首先从sql说起,由于在设置series expression(不知道如何翻译更加妥贴一些,暂时翻译为分组表达式)时候是务必要有值的,如果用x或者y的值去作为表达式,直觉来说是不恰当的,所以想想是不是用个常量了,结果还真是.
例句:select mons,cjl,10 N from test_value where jjr='LZF' ORDER BY MONS.
以mons作为x轴,以cjl为y轴,那么N就是连线变量了.N是什么值什么类型不重要,可以是字符串可以是有理数.
这样就可以形成了报表的字段变量$F{MONS},$F{CJL},$F{N}
如果你想多画几条线,那么就用一个会变化的字段来替代N,譬如可以假设有sql如下:
select mons,cjl,jjr n from test_value ORDER BY MONS.
9.2 设置x,y等图象要素
在图上右键点击,在弹出的菜单上选择"char properties",然后在弹出的窗口中选择“char data"页面,然后选择"char data"页面中的“details"子页,这是关键的地方,然后点击“ADD"按钮,在下图中填入:
"Label expression(optional)"可以不要输入,这是可选项目。"item hyperlink"可以不要理睬,这是用于设置元素超链用的,暂时不要搞这么复杂的.
然后就是设置图的显示属性,如下图(这是选择"chart properties"时候首先就出现的部分):
基本名词解析:
chart title expression 图标题表达式
chart subtitle expression 图副标题表达式
show legend 显示图例
category axis label expression x轴标签表达式(意译了)
value axis label expression y轴标签表达式
9.3 放置在正确的区域
对于chart务必不能放在detail区域,否则会有奇怪的显示,不知道是本人不精熟还是ireport的bug(也不能要求太多,毕竟这是个非盈利产品,除了它的部分资料).
如果放置在detail区域,那么当sql结果集存在多个行的时候,图就会被画对应的次数,譬如有N行,则图也会出现N个一样的。 所以通常放置在汇总区域(即summary band),不要越界.
最后,用ireport自带的预览工具,可以看到下图:
一条线的,series是固定值。
多条线的,series是变值
总结:
其实,用ireport做个报表还是很简单的,至于其它比较复杂的东西需要自己去挖掘.例如图表,复合报表,分组等等.对于初学者,很好的利用wizard(向导)可以快速地入门.
其它例子
已经开始使用ireport 3.0 了,发现功能比以前有了不少进步,例如有兼容性设定,例如更好的排列,方便了不少,提高了不少的速度。
SQL> select * from test_m2;
RQ DQ DM DD
--------------------------------------- ---------- --------------------------------------- ---------------------------------------
20080801 华东 300 200
20080802 华东 198 312
20080803 华东 400 98
20080804 华东 763 564
20080801 华北 456 223
20080802 华北 52 744
20080803 华北 345 98
20080804 华北 763 333
新建一个sql :
select rq,dm,dd,case when dm=0 then 0 else round(dd/dm,2) end bl
from test_m2 where dq='华东'
然后可以做了以下几个例子--多轴曲线图,饼图,堆叠柱状图
饼图和堆叠图都不复杂,就是第一个多轴曲线稍微复杂一点点。
多轴曲线十分有用,因为尤其是当需要在一个图上画几条曲线,但是其标尺相差又非常大的时候,如果用同个标尺,那么显示的效果很差,有可能其中一条曲线看清楚。这个时候,需要有不同的标尺,而多轴曲线图就是这个用处。至于如何设置,实在没有太多值得说的,按照字面去操作,就可以了,当然细节变化还是不少。
另外一个值得说的是堆叠柱状图,这也解决了空间拥挤(有限的问题)。
关于yx_bar
这是一种金融上比较有用的柱状图,和时间密切相关。
y,x表示时间上的两个点,以yx的时间距为底边,以值为高,就画出一根柱子,闲话少说,看了例子就明白了。
SQL> select to_char(id,'00') id,to_char(t1,'hh24:mi') startTime,to_char(t2,'hh24:mi') endTIME ,value from test_xy;
ID STARTTIME ENDTIME VALUE
--- --------- ------- ---------------------------------------
01 12:28 12:58 100
02 14:29 14:59 200
03 16:29 16:59 300
04 18:29 18:59 400
用于反应股票的单日时段均值也是不错的,或者汛期单日河流流量也可以的,当然取值应该是yx之间的均值比较妥当(看具体需要)。
关于经典xy数轴曲线图
在课堂上我们学习的基本上是y=f(x)类型的函数,图都叫数轴图。一个x轴,一个y轴,基本可以表示绝大部分的简单函数的形式。jasper的xy经典数轴图,除了这个还有一些比较奇怪的地方,那就是关于x轴值得体现。
有一个表格,test_xy2(id int ,xvalue number,yvalue number),xvalue=[0.1,20],yvalue=sin(xvalue),不过比较遗憾的是,sin(xvalue)居然从来没有等于1的时候(因为sin(x),必须要求x是圆周率,而不是角度,取得pi值必须用acos(-1))。步幅长度为0.1,共200条记录。
下面就是示意图:
有没有看到什么不一样的地方? 看仔细喽!
就是x轴的坐标,只有显示21个,包括原点坐标,而不是200个坐标。这样图比较美观,但也不妨碍意思的表达,所以应该是不错的表现方式。
关于时间序列图
这种图是专门为按照时间间隔显示数据而准备的,而且画的也比较漂亮,和证券交易所的股票行情图那样。
可以有取多种时间间隔尺度:年,季度,月,周,日,时,分、秒等等。
基本上能够达到上图的效果
关于多个子报表
带有一个子报表的就不说了,看了都会!
这里要说的,是关于多个子报表的话题. (还在使用3.0x版本).
如果是用其它报表工具,相信应该是很容易的,其实用ireport实现多个自报表也是非常容易,它的秘诀在于两个地方: report group ,group expression.
翻译为中文就是:报表群组,分组表达式.
大概步骤是这样:
1)添加群组,这里例子因为有三个子报表,所有增加了两个群组.
2)设置主群组的group expression ,最关键的一步.jasper通过这个来确定分组的方式.
3)摆放子报表,按照希望输出的结果来摆放子报表即可.
4)预览.
演示步骤如下图:
----------------------------------------------------------------------------------------------------------
设置好的主报表! 第一个子报表放在主报表的detail band,
第二个子报表放在g2 footer,第三个子报表放在g1 footer.
添加并设置主分组,及其表达式,其中适当分组依据表达式. 如果希望每次在这个分组开始新的页面,在"start on a new page"前打勾. 具体图略.
添加并设置分组2.
预览结果,可以看到三个子报表.
如果需要更多分组,添加更多的group 即可.
关于交叉报表
交叉报表,并不复杂,尤其是按照wizard来操作的话,当然要知道如何编辑分组,不过我觉得这比powerbuilder的那个好画(比较久了,不知道现在如何)。
步骤1:按照wizard设置
具体略。
步骤2:调整分组和变量
分别参考下图:
设置group和设置变量都是比较简单,不再赘述.
步骤3:排列主窗口
就是在设计窗口中排列字段和变量,这个方面的技巧,可以看后文。
变量DD_RQ_TOTAL,DM_RQ_TOTAL,M_DQ_TOTAL是自己定义的变量(工具上叫measures).
其中变量 M_DQ_TOTAL=$F{DM}.add( $F{DD}) (java.math.BigDecimal就得这么麻烦)
变量放在不同区域会有不同效果,例如M_DQ_TOTAL放在DETAIL/RQ区域,就显示按照一日所有地区的累计,如果是放在rq/dq 区域,那么就是所有日期和地区的一个累计.
步骤4:调整
得预览一下结果,如果满意就不调整,于是完成。
步骤5:完成
其它参考:1) 如何设置特定的排序方式 http://lzfhope.blog.163.com/blog/static/6363992200893053628683/
关于表达式
常常在 print when expression 处看到。
在上图中,希望大米数量》=200的时候打印一个框框,大豆》=300的时候打个勾。
这个时候就需要分别设置表达式:
new java.lang.Boolean($F{DM}.compareTo(java.math.BigDecimal.valueOf(200))>=0)
new java.lang.Boolean($F{DD}.compareTo(java.math.BigDecimal.valueOf(300))>=0)
如果您不熟悉java的语法,一定会被弄的晕头转向! 这也是Java让人恼火的地方,区区一个BigDecimal也要搞得那么复杂。
还有,好像,在编译的时候还是使用jdk1.4及其以下版本的jre来编译,本来很简单的
Integer i=10;
i++; 或者i=i+1;
需要修改为 i=i.intValue()+1Intger.valueOf(1); 很麻烦,所以,如果不是很熟悉的话,可以使用wizard来实现,例如
new java.lang.Integer( ($V{COLUMN_NUMBER}.intValue()) +($V{COLUMN_NUMBER}.intValue()) )
关于排列
画格子,线的技巧
关于画线,画格子其实是有点折磨人视力的活儿,不小心很容易近视。但是ireprot3.x以上版本改变了这个情况。
看看工具栏,就会明白这个。预览->toolbats->Elements Formatting .
那么多,不想每个都说,有的一看就明白了,值得介绍的是几个关于band的按钮:
1)Enlarge between margins ----和页边距等宽
2)Enlarge to band height ---- 和区域等高
3)Enlarge between margins and to band height --和整个区域一样大小
4)Center between margins or in the cell -- 位于边距中间或者格子中间
5)Vertically Center in band/cell --位于区域垂直中间
6)center in band/cell --位于区域中间(水平和垂直两个方面)
那个都不错,不过常常使用到2,和区域等高,以前为了变面画出来的线有重复的感觉,累得半死,不停调试,现在好了,一个按钮就解决。 不错,看来工具还是很重要的。
一些技巧
除了一些主要需要了解的内容,还有一些小技巧是值得注意的.
1)灵活的页号.
举例来说,有个报表,内容是关于客户一段时间的电话明细清单.现在电话公司需要按月提供给客户清单.当然每张清单上都应该在页脚注明如"第x页/共y页"的信息,自然地,页脚应该是这样的:
张三 第1页/共3页,第2页/共3页,第3页/共3页
李四 第1页/共6页,第2页/共6页,第3页/共6页,第4页/共6页,第5页/共6页,第6页/共6页
.....
那么如何实现了?
关键依然是分组,分组中reset page number,其次是对象本身设置"print when group change ,选择恰当的group.
---------------
还有一种方式,就是使用子报表,不过那个麻烦了些.
2)关于样式(类似于css的概念,让表格可以显式丰富的样式),参见http://lzfhope.blog.163.com/blog/static/6363992200810553754612/
3)画线的技巧
常常画线条,是免不了的事情。如果用pdf作为输出,通常对于线条的位置不是要求很严格,但是如果是html方式的输出,则会有一些问题(也许可以归咎于jasper还没有很好地想去解决这个,毕竟是opensource,free),不过也不是不能解决的,解决的方式就是正确地设置left ,top,height,weight属性。
例如一纵向直线A,其left ,top,height,weight,值分别为[10,10,20,0],另外一条是位于A下方的B线条(横直线),其坐标值[0,19,0,100],则此2线存在交叉,因为A线的下端的位置为10+20=30 ,30>19 ,只要A线的下端<=B线的TOP,那么作为HTml输出的线条都可以看见。 同理,所有交叉的线条或者对象,只要边际的位置刚好重合,则双方都可以显示,否则就有一方不能显示出来。
4)导出为pdf.
在现在的版本情况下3.0.0以下,把含有中文的pdf报表save as 为*.pdf,那么可能有会不同的情况。由于某些需要,我得使用1.2.7,结果save as 为pdf的时候,会报告错误(但暂时没有在其它机器上试验)。如果是3.0.0的版本,则不会出现错误。当然对于中文,必须设置两个关键的参数为如下:
pdfFontName="STSong-Light",pdfEncoding="UniGB-UCS2-H"。否则就是没有报告错误,也会使得导出的内容为空白页面。
5)一个特殊的效率问题
这是一个关于列太多,而截为几个子报表的问题,不具有代表性,但是可以考虑,和oracle相关。
http://lzfhope.blog.163.com/blog/static/636399220081013115348831/
6)使用变量存储每行的数据
可能存在着这样的一个应用:数据并不是很多行,通常10行左右,每行大概3-5个列。但是这些字段在报表上的排列又不是很规整的,例如表现得如一张规规矩矩的表格那样,实际上,完全可能是毫无顺序,格式也各有不同。当然实现的方式有不少,这里就说我自己偶尔会采取的办法。
例如sql="select rownum as r,tname from tab where rownum<4";
则可以这样定义变量:
<variable name="T2" class="java.lang.String" resetType="Report" calculation="Nothing">
<variableExpression><![CDATA[($F{R}.compareTo( new java.math.BigDecimal(2) )==0 ? $F{TNAME} : $V{T2} )]]></variableExpression>
</variable>
注意resetType="Report",这表示基于整个报表生成过程计算。整个表达式的意思是如果行号为2,那么取tname,否则取变量自身。因为这个变量是不断计算的,所以,最终会保留第二行的数据.