JapertReports & iReport的开源报表实战[1]

[入库:2006年2月23日] [更新:2007年3月24日]

本文简介:

       JasperReports+iReports ,  类似于CrystalReport的开源报表系统,最主要能帮助我们在设计时把数据和表示分开,帮助我们实现Web报表的分页打印,分组合计,变量的加减处理,输出的格式化,还有导出Excel、pdf等,反正用过了的人都不肯回去重新自己画html页面出报表了。

    google上有入门教程,非常容易。但一遇到复杂的报表,入门那套很快就玩不转了,如果没有中级的研究,可能又得乖乖回去用html画报表。
    首先网上有一份JasperReport收费文档,不过老实说,这份文档收费的话显得太单薄了。
   
    1.自定义数据源,传入VO数组而不直接在JasperReports里查询SQL.

    1.1 为什么要自定义数据源
          简单的报表,当然用不着自定义数据源,直接在JasperReports里编写SQL就可以了。
          但查询复杂起来时,还死守着一条SQL写完会让SQL变得又长又难读,从来都最讨厌  别人在SQL上炫技。这时候,在JasperReport外部的Java程序里进行数据的采集(还可以进一步把相近的查询封装到一个数据采集类中),把结果通过自定义数据源传入JasperReports,而JasperReport只负责数据的显示,更符合数据与显示分开这个普适的模式。
    搞定了可分解重用的数据源后,我才真正敢把JasperReports用到系统上。否则,无法想象怎么在JasperReport文件里维护那么多的SQL.

    1.2 自定义数据源的机制
dori.jasper.engine.JRDataSource 接口非常简单,只要实现两个方法:

public boolean next() throws JRException;
public Object getFieldValue(JRField jrField) throws JRException;
       看函数名字都知道其意义了。所幸,我们连这两个方法都不用实现,Jaspert已经有两个VO Bean的默认实现了。它们是dori.jasper.engine.data.JRBeanArrayDataSource和dori.jasper.engine.data.JRBeanCollectionDataSource 。看名字可知,一个用Array来放bean,一个用Collection 。
 
       很可惜如果VO有内嵌对象,不能用$F{order.customer.name}这样的语法读取。
       也不支持Hibernate的HQL查询结果,因为查询返回的每一row是Object[],只能按index而不能像ResultSet那样按名取值,也就不支持getFileldValue(field)函数了,hibernate.org上有折衷的方法,但都不好。

     1.3 Sample代码与解释

//封装了大量查询的reporter类
MooncakeReporter mooncakeReporter = new MooncakeReporter();
//建立VO的Map,因为需要多次执行查询,需要快速找回VO来赋值,因此采用Map.
Map map = new HashMap();
rs = mooncakeReporter.findAllVaildProduct();
while (rs.next())
{
  MooncakeVO mooncakeVO = new MooncakeVO();
  String goods_no = rs.getString("goods_no");
  String goods_name = rs.getString("name"); 
       mooncakeVO.setName(goods_name);
       mooncakeVO.setCode(code);

       map.put(goods_no, mooncakeVO);
}

//调用Reporter封装好的查询函数获取数据,并通过主键goods_no获得VO来赋值。
rs = mooncakeReporter.findSaleOrderByShopType("shop");
while (rs.next())
{
   String goods_no = rs.getString("goods_no");
   MooncakeVO mooncakeVO = (MooncakeVO) map.get(goods_no);
   if (mooncakeVO != null)
   {
      mooncakeVO.setShopCount(new Integer(rs.getInt("count")));
   }
}

//如此重复执行查询若干步
.....

//因为JRBeanCollectionDataSource需要Collection或者Array,把Map转化为List。
List result = new ArrayList(map.values());

//对result进行排序,通过BeanUtils的beanComparator来实现,在下一小节会讲到。
Collections.sort(result, new BeanComparator("code"));

//最后把result赋给JRBeanCollectionDataSource
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters,
new JRBeanCollectionDataSource(result));

    1.4 扩展
    1.用BeanComparator进行排序
      用map来存放的VO是没有顺序的,必须对其进行排序。 用jakata commons-beanutils的BeanComparator类,可以动态改变排序的列,比自己实现Compare()接口好。

  Collections.sort(result, new BeanComparator("code"));
     对于"Order by lastName, firstName"的情形,还可以写成这样,其中ComparatorChain属于jakata commons-collections包。
     ArrayList sortFields = new ArrayList();
     sortFields.add(new BeanComparator("lastName"));
     sortFields.add(new BeanComparator("firstName"));
     ComparatorChain multiSort = new ComparatorChain(sortFields);
     Collections.sort(rows,multiSort);

2.<box>元素, 终于不用手工划表格线了

   iReports终于出了0.41版, 支持 JasperReports 0.64。

   为什么这么重要呢? 因为从0.63开始,JasperReports支持了千呼万唤始出来的box属性,可以像其他商业报表工具那样,设置表格的四周是否有线。而在以前,虽然人人都说神仙好,但一想起要手工划表格线,还要精确的在两个field之间在留1个像素,头皮就一阵阵发麻。

    另外,新的box在excel下也表现良好,不再需要为Html和Excel制作两个不同的模版文件.

3.iReport报表的快速设计

本文关键:JapertReports & iReport的开源报表实战
  相关方案
Google
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top