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.TRUE
3.
/*
在主报表中:
子报表的返回值有一个问题:它们是在当前区域的所有元素都被处理之后才返回的。
所以,为了能在主报表中的子报表所在的同一区域显示返回值,我们必须延迟文本域表达式的处理时机。这是通过加入一个无效的分组让表达式在分组结束时处理来实现的,而这个无效分组的效果就是数据源中的每条记录就是一组,而且它自己没有组头和组尾区域。
*/
在主报表中:
添加一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>


(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)
报表的分层显示方法:
外层,在主报表中查询循环显示;
下层,在子报表中查询循环显示.

你可能感兴趣的:(java,mysql,report,HashMap,Class,报表)