翻了翻博客,由于太忙,已经很久没认真总结过了。html
正好趁着今天老婆出门团建的机会,记录下最近这段时间遇到的大坑-JasperReport。java
六月份的时候写过一篇利用poi文件导入导出的小Demo,JAVA实用案例之文件导入导出(POI方式)。算法
虽然简单,可是企业应用的原理基本上也就是这样,只不过是封装的更好些,不像我以前写的那样每一个Cell都须要定义,其实poi的方式也是我目前最推崇的方式之一了。主要缘由是jxl不支持xlsx,JasperReport坑又太大,哎。下面进入正题,来介绍下今天的猪脚JasperReport或者叫它ireport亦或jasperstudio,固然后面两个是它的可视化工具。数据库
这货其实在国内用户也很多,是个国外的产品,并且能够说在JAVA报表领域应用是至关的普遍。windows
我当初刚刚接触这个报表的时候仍是至关的喜欢的,最主要的是它的可视化工具,真的是让我欲罢不能,居然能够经过简单画图的方式来设计JAVA报表。提及画图就是能够经过可视化的工具,让咱们可视化的设计报表模板,而且它支持输出的文件格式很普遍,包括EXCEL、WORD、PDF、HTML、XML、CSV等等。api
看起来是否是很强大,一次设计,屡次复用。固然强大得的东西,每每都有两面性,这不就被我遇到了,折磨了我至关长的时间,后文会详细描述的。数组
前面我说,JasperReport或者叫它ireport或jasperstudio,其实这是不许确的。二弟ireport、三弟jasperstudio实际上是jasper的辅助视觉设计工具,你不用它也能设计jasper报表,多写点XML白。5.5以前这个工具叫ireport,5.5以后随着三弟jasperstudio的出生,ireport就被彻底替代了,其实这两个工具基本上是同样的,一奶同胞。缓存
具体的工做流程:tomcat
①首先Jasper会获取须要输出的格式信息的xml文件,而后从xml文件中编译出.jasper类型的文件,而后这个jasper文件能够在咱们的应用程序中被加载生成最终的报表。有没有很熟悉的感受,是的,这一点和java很像,都须要编译一下。less
下图,就是ireport的操做界面,jasperstudio相似,就不贴了,你们能够自行百度下。
上图每种类型的band简单介绍一下。
(1)Title band:title段只在整个报表的第一页的最上面部分显示,除了第一页之外,无论报表中共有多少个页面也不会再出现Title band中的内容。
(2)pageHeader Band:顾名思义,pageHeader 段中的内容将会在整个报表中的每个页面中都会出现,显示在位置在页面的上部,若是是报表的第一页,pageHeader 中的内容将显示在Title Band下面,除了第一页之外的其余全部页面中pageHeader中的内容将在显示在页面的最上端。
(3)pageFooter Band:显示在所在页面的最下端。
(4)lastPageFooter Band:显示在最后一页的最下端。
(5)Detail Band:报表内容段,在这个Band 中设计报表中须要重复出现的内容,Detail 段中的内容每页都会出现。
(6)columnHeader Band:针对Detail Band的表头段,通常状况下在这个段中画报表的表头。
(7)columnFooter Band:针对Detail Band的表尾段。
(8)Summary Band:表格的合计段,出如今整个报表的最后一页中的Detail band 的后面,通常用来统计报表中某一个或某几个字段的合计值。
上面就是可视化的工具的所有,其实怎么用很简单,上手摸索下就会了,既然是踩坑实录,这个天然不是重点,不说了。
这是我总结的步骤,可能描述的不是很准确,你们凑合下
①设计模板,生成JRXML文件,↑↑上面的可视化工具设计你所须要的模板样式
②编译模板,JRXML编译成Jasper文件,就像java中的.java和.class文件同样,程序中运行的须要是*.jasper的二进制文件。
其实这一步能够直接用ireport编译生成.jasper,固然也能够在运行时经过jasper程序编译。可是建议若是在程序中编译的话,jasper版本最好和ireport或者jasperstudio的版本一致。
③执行报表(数据填充到报表)
一、 加载模板生成Jasperreport对象
二、利用JasperFillManager,生成JasperPrint对象
④最后利用JRXlsxExporter导出类,将报表导出或者展现
既然咱们已经利用可视化工具生成了.jasper或者.jrxml文件了,天然是须要让程序加载它。
加载的代码,返回jasperport对象
if (urlPath.endsWith(".jrxml")) { //compile jrxml to jasper try { InputStream is = url.openStream(); jasperReport = JasperCompileManager.compileReport(is); } catch (IOException e) { throw new BaseException("Load jasper error", e); } catch (JRException e) { throw new BaseException("The jrxml template transform to jasper file error", e); } catch (Throwable e) { log.error(e); throw new BaseException(e.getMessage()); } } else if (urlPath.endsWith(".jasper")) { try { InputStream is = url.openStream(); jasperReport = (JasperReport) JRLoader.loadObject(is); } catch (IOException e) { throw new BaseException("Load jasper error", e); } catch (JRException e) { throw new BaseException("The jrxml template file error", e); } catch (Throwable e) { log.error(e); throw new BaseException(e.getMessage()); } } else { throw new BaseException("Invalid file!"); }
这里我采用javabean的方式获取
JRDataSource dataSource = null; if (fieldValues != null && fieldValues.size() > 0) { dataSource = new JRBeanCollectionDataSource(fieldValues); } else { dataSource = new JREmptyDataSource(); }
fieldValues 为数据库中获取的pojo集合。
获得jasperprint对象
Map<String, Object> parameterValue = new HashMap<String, Object>(); jasperPrint = JasperFillManager.fillReport(jasperReport, parameterValue, dataSource);
这个也是须要配置参数最多的一个地方
baos = new ByteArrayOutputStream(); exporter = new JRXlsxExporter(); exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint); exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);
exporter.exportReport();
完成,数据已经写入输出流中了,怎么输出本身决定,是否是比其余方式代码简介不少。
确实在代码书写中JasperReport有着没法比拟的优点,各类api已经封装好。可是多是偏偏作的太多,问题也很多。
若是你使用上面的代码导出EXCEL的话,你会发现Excel的背景是白色,没了Excel一个个的小格子,这是由于jasper默认背景为白色,这样在导出其余格式时也好作到兼容,固然当咱们导出EXCEL并不须要。只须要加上下面两行就能够解决。
//去除两行以前的空白 exporter.setParameter(JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS,Boolean.TRUE); exporter.setParameter(JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_COLUMNS,Boolean.TRUE); //设置Excel表格的背景颜色为默认的白色 exporter.setParameter(JRXlsExporterParameter.IS_WHITE_PAGE_BACKGROUND,Boolean.FALSE);
若是你一个Sheet数据不少,可能会遇到表头屡次打印的状况,这种状况下,你须要加上高度设置。
Field pageHeight = JRBaseReport.class.getDeclaredField( "pageHeight"); pageHeight.setAccessible(true); pageHeight.setInt(jasperReport, Integer.MAX_VALUE);
有时候咱们导出的Excel报表,须要使用Excel的函数计算,若是全都是文本格式,天然计算不了,这种状况下,咱们须要使用
//自动选择格式 exporter.setParameter(JRXlsExporterParameter.IS_DETECT_CELL_TYPE, Boolean.TRUE);
切记,在报表设计时,Field字段选择正确的类型。
我上面那个简单的例子,只是一个文件中包含一个Sheet页,假如咱们的需求是一个文件导出多个Sheet怎么办,别急,这个Japser早已为咱们想到了。
只须要将上文中导出步骤换成下面这个样子
baos = new ByteArrayOutputStream(); exporter = new JRXlsxExporter(); exporter.setParameter(JRExporterParameter.JASPER_PRINT_LIST, listJasperPrint); exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos); //设置为true,便可在一个excel中,每一个单独的jasper对象放入到一个sheet页中 exporter.setParameter(JRXlsExporterParameter.IS_ONE_PAGE_PER_SHEET,Boolean.TRUE); //自定义sheet名称 exporter.setParameter(JRXlsExporterParameter.SHEET_NAMES, sheetNames);
JRExporterParameter.JASPER_PRINT_LIST,传入一个listJasperPrint的集合,每一个JasperPrint即一个Sheet页。
sheetNames 为自定义的数组类型,如:String[] sheetNames = {"自定义1","自定义2","自定义3"};如不须要也能够不配置此项。
其实这个问题也困扰了我好久,后来在大佬的帮助下才想起来问题所在,由于它抛出的根本不是个Exception,而是Error。我看到网上也有同窗问这个问题,因此贴出来。
能够用throwable捕获,就能够获得错误信息,报错:java.lang.InternalError: Can't connect to X11 window server using ':0.0' as
解决方法:修改tomcat/bin/catalina.sh 加JAVA_OPTS="$JAVA_OPTS -Djava.awt.headless=true"
报错内容:Font '微软雅黑' is not available to the JVM. See the Javadoc for more details.
net.sf.jasperreports.engine.util.JRFontNotFoundException: Font '微软雅黑' is not available to the JVM. See the Javadoc for more details.
解决方法:
一、把须要用到的字体(能够直接拷贝windows系统的C:\WINDOWS\Fonts 下的相关字体)拷贝当前项目的classpath下,通常为classes目录下
二、在classpath里添加 jasperreports.properties 属性文件
文件内容为:
net.sf.jasperreports.awt.ignore.missing.font=true
这里须要说一下,EXCEL 03和07版的区别,03版我记得好像是只支持65532行吧,而07版以后就大的多了,具体数字我忘了,反正不是一个数量级的。
JRXlsxExporter支持导出xlsx文件,
JRXlsExporter则是xls的文件,很好辨认,导出的工具和excel的格式同样。
而后是内存溢出和内存泄露问题,这个我相信玩JAVA的朋友基本上都遇到过。
关于内存溢出最一般的解决办法即是增大容器的内存,增长tomcat的内存大小,方法你们能够百度,有不少,不重复造轮子了。
这里提醒下,若是你使用的是tomcat的话,windows安装版,解压缩版和Linux版的配置方式都是不一样的,须要注意下。
这里我须要介绍的是JasperReport的方式,其实JasperReport是对大数据有解决方案的,在很早期的版本便推出了,JRFileVirtualizer的仿真器。
这个东西是作啥用的呢,其实它会根据你设置的参数,将数据写到硬盘的临时文件上,这样解决了填充报表时内存占用过大溢出的问题。
目前JasperReport有3个仿真器,都是用来解决这个问题的。
分别是:
①JRFileVirtualizer
②JRSwapFileVirtualizer
③JRGzipVirtualizer
这三个仿真器又有什么区别呢?
首先是推出最先的JRFileVirtualizer,我在测试时,当导出30W左右的数据,就会报内存溢出,后来加上这个后就能够正常导出了。这个仿真器会把每个对象生成一个临时文件存放在硬盘上解决内存占用的问题,可是由于产生的临时文件较多,无形中增长了文件建立和删除的内存消耗,因此并非很推荐。
//写多个文件 JRFileVirtualizer virtualizer = new JRFileVirtualizer(2, catchPath); Map<String, Object> parameterValue = new HashMap<String, Object>(); parameterValue.put(JRParameter.REPORT_VIRTUALIZER, virtualizer);
virtualizer.setReadOnly(true);
catchPath为文件缓存路径,必须真实存在,不然会报错。
而后是JRSwapFileVirtualizer,这个是为了解决JRFileVirtualizer的问题而推出的。这个仿真器,只会建立一个临时文件,每一个对象会占这个文件的一部分,因此就减小的文件建立和删除的内存消耗,其实这个也不是特别推荐。
//写单个文件 RSwapFile arquivoSwap = new JRSwapFile(catchPath, 4096, 25); JRAbstractLRUVirtualizer virtualizer = new JRSwapFileVirtualizer(2, arquivoSwap, true); Map<String, Object> parameterValue = new HashMap<String, Object>(); parameterValue.put(JRParameter.REPORT_VIRTUALIZER, virtualizer);
virtualizer.setReadOnly(true);
最后是JRGzipVirtualizer这个,看到Gzip,不知道你是否有联系到压缩这个词汇。没错,这个仿真器就是使用一种特殊的压缩算法,能够将内存占用压缩到二十分之一仍是十分之一来着,总之很神奇。
JRAbstractLRUVirtualizer virtualizer = new JRGzipVirtualizer(2); Map<String, Object> parameterValue = new HashMap<String, Object>(); parameterValue.put(JRParameter.REPORT_VIRTUALIZER, virtualizer); jasperPrint = JasperFillManager.fillReport(jasperReport, parameterValue, dataSource);
说了这么多,总之就是三种仿真器解决内存溢出问题,我也看了不少博客里面写利用JRFileVirtualizer,解决内存大数据问题。而后我在这里想说,我最最最不推荐使用JRFileVirtualizer仿真器,由于它不只建立文件消耗大,还有个很严重的BUG,内存泄露!!!还有JRSwapFileVirtualizer也有这个问题。
另外,须要说明的是不使用仿真器,也会有内存泄露的问题,当你导出报表后,dump出堆栈信息,会发现net.sf.jasperreports.engine.fill.JRTemplatePrintText类的实例特别多,没法回收,没法回收!!!而且最新版的japserreport 6.x依旧存在这个问题,在jasper的社区和Stack Overflow存在不少这样的问题,而没有解决方案。
这里推荐JRGzipVirtualizer仿真器,虽然依旧存在泄露问题,可是由于独特的压缩算法,已经将内存泄露问题控制在很小的范围里了,算是一种缓解的方案吧,大概泄露的内存占用缓解了九成以上。
总的来讲,我如今已经放弃这种方案了,写出来也是为了后来的兄弟少走弯路。撸了一个POI的工具类,接下来准备把全部的报表改为POI导出的方式,话说POI的大数据方案仍是挺不错的。
开发路上的坑,写的不是太好还请见谅。转载还请注明出处:小卖铺的老爷爷 http://www.cnblogs.com/laoyeye/p/7707149.html 。