使用jasperReport实现动态表头

更新时间:2023-05-11 02:51:02 阅读: 评论:0

使用jasperReport实现动态表头
2007-07-05 17:17
        最近在我公司drp(运营分销系统)开发中,需要大量报表,由于本人有过jasperReport的开发经验,所以选用了它,jr确实不错,开源,可扩展性很好,缺点就是免费的文档很少,更可气的是,代码中的doc少的可怜,基本上没有参考价值.
        由于我们的产品是用于服装行业的,在服装行业有一个尺码组,非常的麻烦,在制作含有尺码组的报表时,表头的各种尺码不能写死,要从数据库查询出来.但是,一般的报表工具都是不支持表头动态化的(我理解,报表嘛,是呈现给特定人物如老板看的特定内容,表头应该是设计好的,不会经常性的更改),jasperReport也是一样,并不直接支持,细究它的实现过程,我们还是可以扩展从而解决这个问题的.
      先看jasperReport的流程图.
           从上图可看到,jrxml文件要通过JRXmlLoader解析为一个JasperDesign的对象,从源码中可以看出,此对象用java类去描述了报表的整个设计,比如,columnHeader,detail,columnFooter等等.然后由JasperCompileManager编译为一个JasperReport对象,其实,如果你用ireport(jasperReport报表的可视化设计器)制作报表,你完全可以不必理会怎样生成jarReport对象.ireport对此有很好的支持.
        了解了以上过程,我们可以看出,如果要动态的加入设计元素,只能在JasperDesign对象中下手.加入需要的动态元素,我的需求是在columnHeader中加入一个尺码组的表头,代码实现如下.
java 代码
1. package com.dynamicHeader;   
2.  
3. import java.io.File;   
4. import flect.InvocationTargetException;   
5. import java.util.Iterator;   
6. import s.beanutils.BeanUtils;   
7. import net.ine.JRException;   
8. import net.ine.JasperCompileManager;   
9. import net.ine.JasperReport;   
10. import net.ine.design.JRDesignBand;   
11. import net.ine.design.JRDesignStaticText;   
12. import net.ine.design.JasperDesign;   
13. import net.l.JRXmlLoader;   
14.  
15. /**   
16. * @author yaer
17. */ 
18. @SuppressWarnings("unchecked")   
19. public class ReportDesignProcess {   
20.     private static final String flagTextKey = "customFlagText";   
21.  
22.     public static JasperReport getJasperReport(String xmlFilePath,   
23.             String[][] sizeGroup) throws JRException {   
24.         JasperDesign design = getJasperDesign(xmlFilePath);   
25.         JRDesignBand columnHeader = (JRDesignBand) ColumnHeader();   
26.  
27.         reSetColumnHeaderHeight(columnHeader, sizeGroup);   
28.         reSetshapeAndPosition(columnHeader, sizeGroup);   
29.         addElementToColumnHeader(columnHeader, sizeGroup);   
30.         pileReport(design);   
31.     }   
32.     private static JasperDesign getJasperDesign(String filePath)   
33.             throws JRException {   
34.         return JRXmlLoader.load(new File(filePath));   
35.     }   
36.     private static void reSetColumnHeaderHeight(JRDesignBand columnHeader,   
37.             String[][] sizeGroup) {   
38.         columnHeader.Height() * sizeGroup.length);   
39.     }   
40.     private static JRDesignStaticText getFlagTextInDesign(   
41.             JRDesignBand columnHeader) {   
42.         return (JRDesignStaticText) ElementByKey(flagTextKey);   
43.     }   
44.     private static void reSetshapeAndPosition(JRDesignBand columnHeader,   
45.             String[][] sizeGroup) {   
46.         JRDesignStaticText flagText = getFlagTextInDesign(columnHeader);   
47.         Iterator children = Children()   
48.                 .iterator();   
49.         JRDesignStaticText element;   
50.         while (children.hasNext()) {   
51.             element = ();   
52.             if (X() > X()) {   
53.                 element.X() + Width()   
54.                         * sizeGroup[0].length);   
55.             }   
56.             if (!flagTextKey.Key())) {   
57.                 element.Height() * sizeGroup.length);   
58.             }   
59.         }   
60.     }   
61.     private static void addElementToColumnHeader(JRDesignBand columnHeader,   
62.             String[][] sizeGroup) {   
63.         JRDesignStaticText flagText = getFlagTextInDesign(columnHeader);   
64.         veElement(flagText);   
65.         for (int i = 0; i < sizeGroup.length; i++) {   
66.             for (int j = 0; j < sizeGroup[i].length; j++) {   
67.                 try {   
68.                     JRDesignStaticText newElement = (JRDesignStaticText) BeanUtils   
69.                             .cloneBean(flagText);   
70.                     newElement.tText(sizeGroup[i][j]);   
71.                     newElement.X() + Width() * j);   
72.                     newElement.Y() + Height() * i);   
73.                     columnHeader.addElement(newElement);   
74.                 } catch (IllegalAccessException e) {   
75.                     e.printStackTrace();   
76.                 } catch (InstantiationException e) {   
77.                     e.printStackTrace();   
78.                 } catch (InvocationTargetException e) {   
79.                     e.printStackTrace();   
80.                 } catch (NoSuchMethodException e) {   
81.                     e.printStackTrace();   
82.                 }   
83.             }   
84.         }   
85.     }   
86.
      很遗憾,没有写注解,原因是我看了一本书叫<<测试驱动开发>>,里面有一句话"意图导向编程",意思是说,用手段比如容易理解,贴切的类名,方法名,属性达到让读者轻易理解代码.从而少写注解,让代码更简捷.如果大家不大明白以上代码的意思,那就是我写的不够好,还要继续努力.
  此类只有一个方法,根据传来的报表文件路径和一个二维数组式的尺码组生成一个jarReport的对象.有三个关键方法.重新设置columnHeaderheight;重新设置静态内容的形状和大小,添加新的元素到columnHeader,其实,这儿有一个不太容易理的东西:类中有一个flagTextKey的属性,它是标识报表设计中动态内容的一个样板元素,为什么要这个样板元素了,因为用它承载动态内容的样式,要比在用代码实现方便的多.请看loneBean()方法,实际上是克隆样板元素对象.
        这个类设计的太具体于应用,应该写成一个抽象方法,让子类来具体实现加入动态元素的过程,我相信大家的需求和我不太一样.由于时间关系,我没有仔细考究.毕竟这只是一个参考实现.
  最后,在用于ireport画报表时就要注意了,一呈不变的元素该怎么画就怎么画,但样板元素的位置一定要放好.动态内容起始的位置和样式就靠它来定义,大多数时候,它是一个标签.只不过它的"key"属性和上面类的"flagTextKey"要保持一致.
4、常见问题
1)、iReport中提示框输入中文是不能正常显示,请将iReport下lib中的这个包删除tinylaf.jar
  2)、在iReport中运行报表时如果出现乱码问题,请检查itext-1.02b.jar和iTextAsian.jar这两个包是否加到CLASSPATH
3)、在jsp或rvlet高度报表时出现乱码或不显示,请检查你在报表设计过程中所设置的字体及其编码
比如:pdfname、pdfencoding
因为工作需要,最近我要用iReport设计报表并用JasperReport展现出来.
之前我并没有接触过这东西,而且时间相当紧迫,留给我的时间只有一天半.
经过我的一番努力,我终于做出一张跟客户给的纸质合同(采购合同)的"电子版"了!
给客户看过以后,他们挺满意,但是他们提出的一个貌似不大的要求却给我带来巨大的工作量:他们要求合同(采购)明细显示成固定10行.意思是说:如果明细够10行,那正好;如果不够,要用空行补上.
我用的是JDBC连接的方式.这种方式要用SQL语句做到补空行,的确是个难事.也许SQL语句中有这样的功能(比如用临时表 with语句),但是我觉得钻研这种直接连数据库的方式倒不如向报表中传递对象来得更层次分明,更符合整个项目的架构.
我看了一下iReport中的Connections/Datasources的连接方式,发现有Hibernate connection,我很兴奋!建立连接的时候,我就纳闷了:怎么不让我选择我的配置文件呢?按"test"测试连接,果然提示找不到l了.之后我把项目的class路径和项目的所有jar包添加到iReport的Classpath中,再试,发现测试连接的时候不提示任何信息.这让我觉得没办法.
无奈之下,我只好尝试用其他方法连接.我看到custom JRDataSource时,觉得这个应该好用.因为这个是可以子定义的.到网上一查,果然有很多相关的文章.
我仔细看了看,发现重复的东西太多,全部是一个示例(最多改改字段名),没有什么新的写法.我照着做一遍以后,测试成功!因为传递的是datasource,我可以在内存中先把datasource构造好.既然要显示10行,我可以在记录不够的时候,创建一些空对象放到一个collection中.客户提出的问题迎刃而解.
问题是解决了,但是程序却无法让我满意.因为要做报表的地方很多,这种构造datasource的方法却只能为一个对象所用.莫非要我为每个要生成报表的对象写一个这样的datat类?显然我不愿意.于是我尝试用java的反射机制来完成我的想法.程序写完,没有任何问题!并且我可以取到hibernate对象中直接引用的对象的字段值.
其实这个程序还可以扩展,那就是用递归的方式取任何直接或间接相关联的"祖先表"的值.程序如下:
;
import flect.Field;
import flect.Method;
import java.util.List;
import java.util.Vector;
import net.ine.JRDataSource;
import net.ine.JRException;
import net.ine.JRField;
/**
* jasperreport的数据源
* @author shill
* @date 2008-01-03
*/
public class CommonJasperDataSource implements JRDataSource
{
private List objects = new Vector();
private int index = -1;
/**
* 无参数构造方法
*/
public CommonJasperDataSource()
{
}

/**
* 初始化构造方法
* @param objects
*/
public CommonJasperDataSource(List objects)
{
  this.init(objects);
}

/**
* 初始化方法
* @param objects
*/
public void init(List objects)
{
  if (objects!=null)
  {
    this.objects = objects;
  }
}

/**
* 根据字段信息到datasource中取该字段的值
*/
public Object getFieldValue(JRField jrfield) throws JRException
{
  String jrFieldName = Name();
  Object object = (index);
  Class cls = Class();
  Field []objFields = DeclaredFields();
  for (int i = 0; i < objFields.length; i++)
  {
    Field objField = objFields[i];
    String fieldName = Name();
    int idx = jrFieldName.indexOf(".");
    if (fieldName.equals(jrFieldName))
    {
    String getterName = "get" + fieldName.substring(0,1).toUpperCa()
      + fieldName.substring(1);
    try
    {
      Method getter = DeclaredMethod(getterName, new Class[0]);
      return getter.invoke(object, new Object[0]);
    }catch (Exception e)
    {
      return null;
    }
    }el if (idx>0 && jrFieldName.startsWith(fieldName))
    {
    String refJrFieldName = jrFieldName.substring(idx+1);
    String getterName = "get" + fieldName.substring(0,1).toUpperCa()
      + fieldName.substring(1);
    try
    {
      Method getter = DeclaredMethod(getterName, new Class[0]);
      Object refObject = getter.invoke(object, new Object[0]);
      Class refCls = Type();
      Field []refObjFields = DeclaredFields();
      for (int j = 0; j < refObjFields.length; j++)
      {
      Field refObjField = refObjFields[j];
      String refFieldName = Name();
      if (refFieldName.equals(refJrFieldName))
      {
        String refGetterName = "get" + refFieldName.substring(0,1).toUpperCa()
          + refFieldName.substring(1);
        Method refGetter = DeclaredMethod(refGetterName, new Class[0]);
        return refGetter.invoke(refObject, new Object[0]);
      }
      }
    }catch (Exception e)
    {
      return null;
    }
    }
  }
  return null;
}

本文发布于:2023-05-11 02:51:02,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/579645.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:报表   没有   动态   连接   对象   设计
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图