jasperReport+iReport的使用

(1)JasperReports是一个开源的java报表制作引擎
iReport是JasperReports的一个GUI工具,用来生成JasperReports的jrxml文件。JasperReports的报表是用XML文件来定义的,约定用jrxml作后缀名。一个典型的jrxml文件包含以下元素:    * <jasperReport> - 根元素    * <title> - 报表的标题,一篇报表里只在开头打印一次    * <pageHeader> - 页眉,报表每页开头打印一次    * <detail> - 报表正文    * <pageFooter> - 页脚,报表每页末尾打印一次    * <band> - 定义报表部件,以上所有元素都包含一个band元素作为他们唯一的子元素·Summary:可能需要对几页(你的报表可能有几个页组成)的统计值。比如50个销售记录共占用了3页,那么放置这些统计记录的统计值最好的地方就是summary。·groupHeader:每个表的内容可能需要根据某个属性进行划分显示内容和计算内容,比如希望以月份为单位每组分开显示销售记录,那么就可以定义一个组(组的定义参考后文),groupHeader就是放置组说明或是组标志最好的地方。·Groupfooter:放置组的统计或是说明(2)各元素分析:static text:静态文本,只是用来在报表中显示;$P--->表示是参数;
如:"20"+$P{statement_current_date}
$F--->表示是textfield变量.
如:$F{account_code}
此变量是在<field name>中定义的.其值是在<queryString>中,通过select数据库后,得到的.
select的列名 = field name$V--->表示一个变量
如:$V{balance}
变量的默认值是在报表中设置的.一般设置为0.其真正的值是通过 $P或$F来获得的.(3)A,报表中的QueryString语句,可以通过界面上的DataBase中的Report SQL Query来进行添加-->会自动生成相应的TextField.若不行,则可自动手动添加.B,如果要直接修改代码,可以选择界面上的'编辑'-->'直接编辑XML Source'-->先进行保存-->就会出现代码界面.C,如果要修改JASPER REPORT的属性,可以选择界面上的'预览'-->'报表属性'E,添加group,可以通过点击界面上的相应'group'按钮来添加.F,隐藏不要的区域,要设bank=0,而不能删除为空.删除为空,则为默认值G,IReport中的左栏中的各元素的后面的[X,Y]内的数据,是指此元素偏离'左上角'的X,Y距离.H,设置子报表时,要将子报表的属性中的"上边界,下边界,左边界,右边界"全部设置为0,否则会出现子报表传回来的数据,在主报表中没法对齐的现象.(4)当没有数据(是指QueryString语句SELECT出来的数据为NULL)时,设置怎样显示:
相关代码:
whenNoDataType="NoPages / BlankPage / AllSectionsNoDetail"
NoPages:当没数据时,会弹出一个对话框提示你没数据,然后显示一个没激活的框.
BlankPage :不会提示,只是显示一个白纸.
AllSectionsNoDetail:不会提示,但那些静态的文本,以及从上一层或JAVA文件中传来显示的参数,都可以显示.(5)内置的报表变量:
$V{PAGE_NUMBER}:(常用)
这个变量保存当前的页号,在报表装填结束的时候,这个变量就保存着最终文档的总页数。所以要在JasperReport的文本字段中显示页号和总页数你都可以用它。
A,
只需要添加一个系统的变量:$V{PAGE_NUMBER};
对于$V{PAGE_NUMBER}:当evaluationTime="Now"时,即是计算当页所在哪一页.   (now:即时执行此表达式.)
                    当evaluationTime="Report"时,即是计算当页所在哪一页.(Report:整个报表执行完后才执行此表达式)
B,
并将其转换为String的类型.
C,总体代码:
<textField evaluationTime="Now">
<textFieldExpression class="java.lang.String">
"Page " + String.valueOf($V{PAGE_NUMBER}) + "   Of"
</textFieldExpression>
</textField><textField evaluationTime="Report">
<textFieldExpression class="java.lang.String">
String.valueOf($V{PAGE_NUMBER})
</textFieldExpression>
</textField>$V{REPORT_COUNT}:
当evaluationTime=Report时,将记录报表的总记录数.
当evaluationTime=Column时,将记录报表从开始到当前页的总记录数.Variable COLUMN_NUMBER
这个变量将记录当前的列号。
Variable PAGE_COUNT
这个变量纪录当前页中处理的record的数目。
Variable COLUMN_COUNT
这个变量纪录生成当前列时所处理的record的数目。
(6)field的动态显示+动态显示不同的格式:
有些报表可能需要对同种类型的数据根据重要性不同而显示不同的风格。例如,要在订单列表中加亮显示金额超过100$的订单.
而文本域的现实格式不能动态改变,我们如何实现这种功能呢?
解决办法是:
在同样的位置放两个文本域来显示相同的内容,但是设置不同的显示格式,一个正常显示,一个加粗并加亮显示红色,同时还要为他们设定<printWhenExpression>元素,让他们可以根据条件表达式来切换。这里的表达式就是$F{value} < 100(正常显示的文本域)和$F{value} >= 100(加亮显示的文本域)。(7)创建子报表
1)
在代码中,将子报表以参数形式加载:
JasperReport sixUnitPrice = (JasperReport)JRLoader.loadObject("jasper/TrendAve_ItemIntel_6MonthUnitPrice.jasper");
parameters.put("sixUnitPrice", sixUnitPrice);
2)
在主报表中,创建上面的相应参数sixUnitPrice. 其类型为:net.sf.jasperreports.engine.JasperReport
3)
在iReprot中添加,划拉出一块子报表.
在subReport项中,选中:' use connection expression '
在subReport other项中:
设置image expression class=net.sf.jasperreports.engine.JasperReport
设置subreport expression中填写代码中的相应参数:$P{sixUnitPrice}
4)
设置要传到子报表的参数,并在主报表中创建相应的参数.
5)
新建子报表,创建一参数(与主报表传递的参数一样),来接收从主报表传来的参数.-->即可应用了.
说明:
位于多层之下的子报表,也需要从主报表开始时,就可以加载,传递下去,否则加载不了.因为一开始,都是从JAVA文件中从传过来,然后一层层传下去的.
(8)hashmap参数在报表间传递值的用法1)
如何带参数:
在某层子报表中创建一个新的子报表,此新子报表,必须从:报表java类中定义-->主报表-->各上级父报表中对此新子报表进行定义(定义此参数+各父报表添加此新报表参数,以便其子报表可以获得)-->目的子报表
2)hashmap参数在报表间传递值的用法
如上的专题记录,$P{group_total_hash}此参数是一个hashmap,从其定义是在子报表中的,最终用:是在主报表中,作为统计数据.
怎样用:
1.
先在主报表,以及子报表中都要定义hashmap,并在子报表的各上层报表进行赋值,使参数可以主报表与子报表中间进行传递:
<parameter name="group_total_hash" isForPrompting="false" class="java.util.HashMap">
<defaultValueExpression ><![CDATA[new java.util.HashMap()]></defaultValueExpression>
</parameter>
2.
在子报表中,在区间的显示属性中添加:
$P{group_total_hash}.put();如下:
$P{trayout_hash}.put("trayout",$F{totalqty}) == null?
Boolean.TRUE:Boolean.TRUE3./*在主报表中:
子报表的返回值有一个问题:它们是在当前区域的所有元素都被处理之后才返回的。
所以,为了能在主报表中的子报表所在的同一区域显示返回值,我们必须延迟文本域表达式的处理时机。这是通过加入一个无效的分组让表达式在分组结束时处理来实现的,而这个无效分组的效果就是数据源中的每条记录就是一组,而且它自己没有组头和组尾区域。*/
在主报表中:
添加一Field,设置数据类型为Double,且Evaluation time=Column(否则数据出不来)
$P{group_total_hash}.get();如下:
new Double
(
((Double)$P{trayout_hash}.get("trayout")).doubleValue()
-
((Double)$P{trayin_hash}.get("trayin")).doubleValue()
)4.
具体可以参考ACCOUNT中的PL报表,或SCM中的item intelligence报表中的设置及用法:
主报表:
ProfitLoss_basic.jrxml
用于计算各部分total的子报表:
ProfitLoss_basic_subReport_profit_loss_total_year_list.jrxml

TrendAve_ItemIntelReport.jrxml
TrendAve_ItemIntel_trayout.jrxml.(9)Group的用法:用法一:(分类显示及计算)假设有两表:
mysql> select * from A;
+------+------+
| id   | name |
+------+------+
|    1 | hk   |
|    2 | hk   |
+------+------+mysql> select * from B;
+------+------+------+-------+
| id   | Aid | name | value |
+------+------+------+-------+
|    1 |    1 | sz   |     1 |
|    1 |    1 | cz   |     1 |
|    2 |    2 | zh   |     1 |
|    2 |    2 | gz   |     1 |
+------+------+------+-------+报表要分两层,第一层循环查询A表,第二层(即子报表)循环查询B表在属于A表的记录.
若不用group,则会出现(-->后面是各组件中iReport中的位置):
ID    Name value -->放于报表中的pageHeader
1     hk     1     -->放于第一层报表中的detail -->循环每一条记录且显示
1   sz     1     -->放于第二层报表中的detail
2   cz     1
2     hk     1     //name与上相同
1   zh     1
2   gz     1若采用group按照name进行分组,则jasper会把name相同的放入一组,只显示一次.
采用name分组后的效果:
ID    Name value -->放于报表中的pageHeader
1     hk     1     -->放于第一层报表中groupHeader,将所有相同的name集合在一起,只显示一次
1   sz     1     -->放于第二层报表中的detail
2   cz     1
1   zh     1
2   gz     1
sum value: 5     -->放于第一层报表中groupFooter补充说明:
对于上面的group,须先点击"group"按钮进行定义(如:nameGroup).同时,可以以group的基准进行计算(结合变量variable),放于groupFooter.
(1)
在iRport中,新建变量sumValue,定义如下:
variable type: Double
caculation type: sum
Reset type: Group
Reset Group: 上面自定义的group名(如:nameGroup)
variable expression:(即进行计算的表达式) $F{value}
(2)
在groupFooter添加一field:
须定义:
Evaluation time : group,而不是now
Evaluation Group: 上面自定义的group名(如:nameGroup)jasper报表,子报表内容显示重叠在jasper中,若在detail区域中,把两个一模一样的子报表上下放置.则在循环输出时,会出现上下子报表输出内容相遮掩的结果.
解决方案:用group分离显示.
把两个子报表,分别放于两个不同的group中,分组条件为主报表的每一个ID,这样,主报表循环显示时,就会将各分组一一显示出来,不会影响其显示.用法二:利用group来进行分组和实现子报表返回值:
第(8)点的返回值,只适合于非循环性的.
若在主报表的detail区域,需要让每条record都将子报表返回值到对应的record中,则要采用这种方法.上面的方法实现不了.
因为子报表的返回值有一个问题:它们是在当前区域的所有元素都被处理之后才返回的。如果你想在子报表所在的主报表区域显示它的返回值,你最终将看到它们返回的太晚了。具体实现方法:
1)
先在主报表,子报表建立一个同名的hashmap容器,且将主报表的这个参数作为子报表的传递参数,传到子报表中.
2)
在报表中,对窗口进行加值:
方式一:
在子报表中,在summary区域的属性中添加:
$P{trayout_hash}.put("trayout",$F{totalqty}) == null?Boolean.TRUE:Boolean.TRUE
方式二:
在子报表中,在summary区域中添加一个不可见的直线元素,且在其中设置:
<line>
<reportElement x="0" y="0" width="0" height="0">
    <printWhenExpression>
      $P{trayout_hash}.put("trayout",$F{totalqty}) == null?Boolean.FALSE:Boolean.FALSE
    </printWhenExpression>
</reportElement>
</line>
3)
在主报表中,添加一个分组,以每条记录作为一个分组.操作如下:
A,点击GROUP按钮.
B,填写组名;
C,分组表达式: $F{item_code}.(也可以id作为分组) -->分组的关键所在
D,选择:是否start on a new page -->让最后所得的分组,是否以分页的形式显示.
4)
对于detail区域中,要返回值的field,这样设置:
<textField evaluationTime="Group" evaluationGroup="itemcodeGroup">
<reportElement x="335" y="50" width="175" height="15"/>
<textFieldExpression >
    $P{trayout_hash}.get("trayout")
</textFieldExpression>
</textField>采用Group实现返回值的说明:
子报表的返回值有一个问题:它们是在当前区域的所有元素都被处理之后才返回的。如果你想在子报表所在的主报表区域显示它的返回值,你最终将看到它们返回的太晚了。
所以,为了能在主报表中的子报表所在的同一区域显示返回值,我们必须延迟文本域表达式的处理时机。这是通过加入一个无效的分组让表达式在分组结束时处理来实现的,而这个无效分组的效果就是数据源中的每条记录就是一组,而且它自己没有组头和组尾区域。
<group >
<groupExpression>$F{item_code}</groupExpression>
</group>用法三:在group header进行数据统计:
1)
对于group的统计,一般情况下,统计的结果位于group footer中。这时,只须定义变量将其设置为sum,reset type=group,reset
group=目标group即可,iReport中,直接调用此变量即可。
2)
现要在group header显示1)中的统计数据时,若用上面的方法,即会显示为null.只能显示于footer中。
完善方法:
在调用变量的field中,将其属性:Eval time=not-->group,且设置Eval Group=目标group即可。(10)若数据类型设置为Double,则须:
$P{trayout_hash}.get("trayout")-->Object类型;
((Double)$P{trayout_hash}.get("trayout"))-->转换成Double类型;
((Double)$P{trayout_hash}.get("trayout")).doubleValue()-->转换成double类型,进行计算;
new Doubel(A-B)--->将最终结果转换成Double,因为上面设置类型类型时,用了Double.
如下:
new Double
(
((Double)$P{trayout_hash}.get("trayout")).doubleValue()
-
((Double)$P{trayin_hash}.get("trayin")).doubleValue()
)(11)变量还可以声明来完成引擎内建计算的求值,如:count、sum、average、lowest、highest、 variance等等。一个完成Quantity字段sum计算的变量定义如下:<variable name="QuantitySum"class="java.lang.Double" calculation="Sum"><variableExpression>$F{Quantity}</variableExpression></variable>我们还可以通过制定初始化级别来改变计算过程,默认的级别是Report就是变量仅在报表开始处初 始化一次,一直到报表结束完成计算。
我们可以选择更低的级别让变量在每个Page、Column或者Group级别重新初始化。假如我们想计算 计算每页的总数,变量声明如下:<variable name="QuantitySum" class="java.lang.Double"
resetType="Page" calculation="Sum">
<variableExpression>$F{Quantity}</variableExpression>
<initialValueExpression>new Double(0) </initialValueExpression>
</variable>
变量将在每一页的开始处被初始化为0。
(12)变量的resetType解释:
报表变量的值可以在每一次迭代(iteration)中被改变,但也可以在装填过程中的某一特定的时间(specified moments)通过它的初始的value表达式恢复其初始值。这一行为是由resetType属性控制的,这一属性规定了报表装填过程中当报表变量在何时需要重新进行初始化(或恢复到初始值)。该元素有五种选项值:
4.1
No Reset:变量将不会使用其initial value expression对自身进行初始化,而将仅报表从变量表达式中所求得的值(resetType=”None”)。
4.2
Report Level Reset:变量将在报表填充过程的起始阶段使用其初始化表达式初始化一次(resetType=”Report”)。
缺省的属性为resetType=”Report”
4.3
Page Level Reset:变量将在每一页的起始时被重新初始化(resetType=”Page”)。
4.4
Colunm Level Reset:变量将在每个新列的开始被初始化(resetType=”Column”)
4.5
Group Level Reset:变量将在每次resetGroup属性提供的break的地方被重新初始化(resetType=”Group”)。
Reset Group
如果存在的话,resetGroup属性包含了报表的组的名字并且仅与resetType=”Gropu”的resetType属性相关联。(13)报表的分层显示方法:
外层,在主报表中查询循环显示;
下层,在子报表中查询循环显示.(14)field 的一写法:
A.只有一个field,值是:$F{A}+" "+$F{B}
B.有二个field, 值是:$F{A}      $F{B}
这种写法的好处是:
B写法的不足之处在于:当原设置A,B两field的距离过大时,当fieldA,B实例内容过小时,也使 A,B的值相隔过远;相反情况,则会A,B内容相重叠。
A的写法,则不会。(15)如何设置分页显示:分页的方法有:1.采用分页线。在“编辑”--“插入”--分页线;2.将title/summary band设置为独立一页,与其它数据分开显示。   设置方式:“编辑”--“页面属性”--切换至第三界面,选择title/summary。现有情况:要让两个报表,一个显示summary数据,一个显示detail数据。要让此两个表示显示于一张报表中。---即如何实现分页。实现方法:将summary报表以子报表方式放于detail报表的title/summary band区域,且用第二种设置分页方式,实现强制分页效果。3.设置报表每页显示20条记录,每显示20条记录后,一段说明文字。
方法:
添加一个分组,设置分组为分页形式,且分组表达式为:
new Integer($V{COLUMN_COUNT}.intValue()/21) -->后面的数字为每页的记录+1;
在此分组的footer中,添加要显示的文字即可。(16)获取子字符串:"OSYYM[9]1234567".substring(8)对于iReport中数字/字符串存在有哪些内置函数,可以通过field--"properties editor"中,field的不同类型,可以查看各种数据类型的处理方法!!!(17)iReport,快捷构造子报表:
子报表经常用于主报表中某些列的统计。
快捷构造:
1.可以直接将另一报表中的子报表直接复制粘贴到当前报表中,不用去自己新建。只须修改参数即可。
2.对于iReport中的参数,变量,也可以直接从一报表中直接得到到另一报表中。只须去修改,不用去新建。
3.常常子报表的统计列要跟主报表的列相对齐,这时,只须将主报表的相应行直接复制粘贴到子报表中,即可保持子报表列与主报表列对齐。不用自己去新建,再慢慢去调整主报表子报表列的对齐。--大省时间。4.在iReport中,能从A报表直接copy,在B报表中直接粘贴。  (18)格式化数据:
若要求数据格式化为(123,456.00),且向右对齐,不能用: 左括号field+数据+左括号field-->这样显示出来,若数据长度过短,会出现空格,如:(   123.4);
若直接在一个field中添加括号,及数据列,又不能对数据进行格式化。所以,须用方法对数据进行格式化
"("+
new DecimalFormat("#,##0.00").format($F{loanInt})
+")"(19)对于主子报表的对齐,可以通过主子报表中的左与上的标尺来定位。!!!!!(20)如何设置当report没数据时,在报表中打印一些文字提示,如:"- no matching record is found -".
说明:一般情况下,通过iReport只能设置当没有数据时,显示为noPage,或all section但包括detail.(在报表属性中设置)。但却不能设置如上效果,当没有数据时,显示特定的文字提示。
报表的数据是以javabean方式传入。
1.
在报表的传入参数中,添加一参数为:reportParams.put("numberOfRecords",数据集.size())
2.设置summary长度不为0,添加"- no matching record is found -"文字。
3.
然后在报表中的各个band的显示条件中,添加:
只在有数据时显示:new Boolean($P{numberOfRecords}.intValue()>0)
只在没数据时显示(对summary):new Boolean($P{numberOfRecords}.intValue()==0)
4.
对于有嵌套子报表的,如有title中有一子报表,此子报表完全是一个summary型的报表,与主报表(detail型报表)没关系的报表。
只须在主报表中将java传入的子报表的datasource的size()传入子报表,再按上面设置即可。
param: numberOfRecords
value: $P{subReportDataSource}.size()(21)在报表中插入图片,可以用哪下的路径(获取系统root+相对路径):
System.getProperty("user.dir")+ "/jasper/img/logo_abc.JPG"(22)报表各种格式的导出:1)
在jasperReport中,可以将报表导出为不同的格式,如:PDF,Rtf,doc,execel等。就输出而言,jasperReport定义了统一的接口类:JRExporter,各实现类有JRPdfExporter,JRRtfExporter,JRXlsExporter等等。接口有两个方法,在进行输出时一定要定义:
setParameter(),exportReport().
在设置参数时,有三个参数是经常使用的:
xxxExporter.setParameter(JRExporterParameter.JASPER_PRINT,jasperPrint); -->一定要设置。
对于输出到PC的,须定义输出文件名,如:
xxxExporter.setParameter(JRExporterParameter.OUTPUT_FILE_NAME,"C:/ReportingLimitControllingReport.rtf")
对于输出到网络的,须定义输出流:
xxxExporter.setParameter(JRExporterParameter.OUTPUT_STREAM, out);2)
输出到硬盘实例:
String reportPath=ReportPathUtil.genReportPath("abc.jasper"); HashMap<String, Object> reportParams = new HashMap<String, Object>();
reportParams.put("companyName","123456");try {
        //rtf,word
    JRRtfExporter rtfExporter = new JRRtfExporter();
    JasperPrint jasperPrint = JasperFillManager.fillReport(reportPath,reportParams, new JRBeanCollectionDataSource(inputData));
    rtfExporter.setParameter(JRExporterParameter.JASPER_PRINT,jasperPrint);
    rtfExporter.setParameter(JRExporterParameter.OUTPUT_FILE_NAME,"C:/abc.rtf");
    rtfExporter.setParameter(JRExporterParameter.OUTPUT_FILE_NAME,"C:/abc.doc");
    rtfExporter.setParameter(JRExporterParameter.CHARACTER_ENCODING,"utf8");
    rtfExporter.exportReport();
  
//    //execel
    JRXlsExporter execelExport=new JRXlsExporter();
    JasperPrint jasperPrint2 = JasperFillManager.fillReport(reportPath,reportParams, new JRBeanCollectionDataSource(inputData));
    execelExport.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint2);
    execelExport.setParameter(JRExporterParameter.OUTPUT_FILE_NAME, "C:/abc.xls");
    execelExport.setParameter(JRExporterParameter.CHARACTER_ENCODING,"utf8");
    //设置是否每个sheet只显示一页
    execelExport.setParameter(JRXlsExporterParameter.IS_ONE_PAGE_PER_SHEET,Boolean.TRUE);
    execelExport.exportReport();
  
    //html
    JRHtmlExporter htmlExporter=new JRHtmlExporter();
    JasperPrint jasperPrint3 = JasperFillManager.fillReport(reportPath,reportParams, new JRBeanCollectionDataSource(inputData));
    htmlExporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint3);
    htmlExporter.setParameter(JRExporterParameter.OUTPUT_FILE_NAME,"C:/abc.html");
    htmlExporter.exportReport();
   } catch (Exception e) {
    // TODO: handle exception
   }//pdf,除了用上在的方式构造外,还可以用以下的方式生成
    File f = new File(reportPath);
        InputStream reportInputStream = new FileInputStream(f);
JasperRunManager.runReportToPdfStream(reportInputStream,new FileOutputStream(new File("C:/abc.pdf")),reportParams,
                                      new JRBeanCollectionDataSource(inputData));
3)
输出到网络实例:
请见:http://blog.csdn.net/Rachael1001/archive/2007/03/02/1519492.aspx

猜你喜欢

转载自201109055547.iteye.com/blog/1582375