最近在我公司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的对象.有三个关键方法.重新设置columnHeader的height;重新设置静态内容的形状和大小,添加新的元素到columnHeader中,其实,这儿有一个不太容易理的东西:类中有一个flagTextKey的属性,它是标识报表设计中动态内容的一个样板元素,为什么要这个样板元素了,因为用它承载动态内容的样式,要比在用代码实现方便的多.请看loneBean()方法,实际上是克隆样板元素对象. 这个类设计的太具体于应用,应该写成一个抽象方法,让子类来具体实现加入动态元素的过程,我相信大家的需求和我不太一样.由于时间关系,我没有仔细考究.毕竟这只是一个参考实现. 最后,在用于ireport画报表时就要注意了,一呈不变的元素该怎么画就怎么画,但样板元素的位置一定要放好.动态内容起始的位置和样式就靠它来定义,大多数时候,它是一个标签.只不过它的"key"属性和上面类的"flagTextKey"要保持一致. |