写在最前面

翻了翻博客,因为太忙,已经好久没认真总结过了。

正好趁着今天老婆出门团建的机会,记录下最近这段时间遇到的大坑-JasperReport。

六月份的时候写过一篇利用poi文件导入导出的小Demo,JAVA实用案例之文件导入导出(POI方式)

虽然简单,但是企业应用的原理基本上也就是这样,只不过是封装的更好些,不像我之前写的那样每个Cell都需要定义,其实poi的方式也是我目前最推崇的方式之一了。主要原因是jxl不支持xlsx,JasperReport坑又太大,哎。下面进入正题,来介绍下今天的猪脚JasperReport或者叫它ireport亦或jasperstudio,当然后面两个是它的可视化工具。

JasperReport是个什么东西?

这货其实在国内用户也不少,是个国外的产品,而且可以说在JAVA报表领域应用是相当的广泛。

我当初刚刚接触这个报表的时候还是相当的喜欢的,最主要的是它的可视化工具,真的是让我欲罢不能,竟然可以通过简单画图的方式来设计JAVA报表。说起画图就是可以通过可视化的工具,让我们可视化的设计报表模板,并且它支持输出的文件格式很广泛,包括EXCEL、WORD、PDF、HTML、XML、CSV等等。

看起来是不是很强大,一次设计,多次复用。当然强大得的东西,往往都有两面性,这不就被我遇到了,折磨了我相当长的时间,后文会详细描述的。

JasperReport的大胸弟

前面我说,JasperReport或者叫它ireport或jasperstudio,其实这是不准确的。二弟ireport、三弟jasperstudio其实是jasper的辅助视觉设计工具,你不用它也能设计jasper报表,多写点XML白。5.5之前这个工具叫ireport,5.5之后随着三弟jasperstudio的出生,ireport就被完全替代了,其实这两个工具基本上是一样的,一奶同胞。

具体的工作流程:

①首先Jasper会获取需要输出的格式信息的xml文件,然后从xml文件中编译出.jasper类型的文件,然后这个jasper文件可以在我们的应用程序中被加载生成最终的报表。有没有很熟悉的感觉,是的,这一点和java很像,都需要编译一下。

下图,就是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的版本一致。

③执行报表(数据填充到报表)

  1、 加载模板生成Jasperreport对象

  2、利用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);

最后我们利用JRXlsxExporter导出报表

这个也是需要配置参数最多的一个地方

baos = new ByteArrayOutputStream();
exporter = new JRXlsxExporter();
exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);
exporter.exportReport();

完成,数据已经写入输出流中了,怎么输出自己决定,是不是比其他方式代码简介很多。

确实在代码书写中JasperReport有着无法比拟的优势,各种api已经封装好。但是可能是恰恰做的太多,问题也不少。

JasperReport的问题

1、两行前的空白

如果你使用上面的代码导出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);

2、数据量很大,title多次写入

如果你一个Sheet数据很多,可能会遇到表头多次打印的情况,这种情况下,你需要加上高度设置。

Field pageHeight = JRBaseReport.class.getDeclaredField(
"pageHeight");
pageHeight.setAccessible(true);
pageHeight.setInt(jasperReport, Integer.MAX_VALUE);

3、Cell的类型的问题

有时候我们导出的Excel报表,需要使用Excel的函数计算,如果全都是文本格式,自然计算不了,这种情况下,我们需要使用

 //自动选择格式
exporter.setParameter(JRXlsExporterParameter.IS_DETECT_CELL_TYPE, Boolean.TRUE);

切记,在报表设计时,Field字段选择正确的类型。

4、多Sheet的问题

我上面那个简单的例子,只是一个文件中包含一个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"};如不需要也可以不配置此项。

5、Linux下启动不报错,但是无法导出报表

其实这个问题也困扰了我很久,后来在大佬的帮助下才想起来问题所在,因为它抛出的根本不是个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"

6、Linux下字体缺失问题

报错内容: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.

解决方法: 
1、把需要用到的字体(可以直接拷贝windows系统的C:\WINDOWS\Fonts 下的相关字体)拷贝当前项目的classpath下,一般为classes目录下 
2、在classpath里添加 jasperreports.properties 属性文件
文件内容为: 
net.sf.jasperreports.awt.ignore.missing.font=true

7、大数据内存溢出和内存泄露问题!!

这里需要说一下,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 

JasperReport报表导出踩坑实录的更多相关文章

  1. JAVA实用案例之文件导出(JasperReport踩坑实录)

    写在最前面 想想来新公司也快五个月了,恍惚一瞬间. 翻了翻博客,因为太忙,也有将近五个多月没认真总结过了. 正好趁着今天老婆出门团建的机会,记录下最近这段时间遇到的大坑-JasperReport. 六 ...

  2. 后端路由项目由 gulp 改为 webpack 的踩坑实录

    前言 公司有个后端路由的项目是用 gulp 作为前端自动化构建工具,最近学习了一下 webpack,深感其强大,一狠心将其改成了 webpack 构建,以下是踩坑实录. gulp 先来说说原来的架构. ...

  3. ffmpeg 踩坑实录 添加实时水印(二)

    一.背景介绍 最近领导要求做一个视频录制的相关项目.其中,需要对视频文件进行添加 实时时间水印.于是,我想到了使用之前的ffmpeg来做. 二.ffmpeg实际操作 首先把需要添加水印的视频文件,上传 ...

  4. HashMap踩坑实录——谁动了我的奶酪

    说到HashMap,hashCode 和 equals ,想必绝大多数人都不会陌生,然而你真的了解这它们的机制么?本文将通过一个简单的Demo还原我自己前不久在 HashMap 上导致的线上问题,看看 ...

  5. (最新)VS2015安装以及卸载过程——踩坑实录

    前言 Visual Studio (简称VS)是微软公司旗下最重要的软件集成开发工具产品.是目前最流行的 Windows 平台应用程序开发环境,也是无数人学习编程的入门软件之一.Visual Stud ...

  6. [Cyan之旅]使用NPOI实现Excel的导入导出,踩坑若干.

    Cyan是博主[Soar360]自2014年以来开始编写整理的工具组件,用于解决现实工作中常用且与业务逻辑无关的问题. 什么是NPOI? NPOI 是 POI 项目的 .NET 版本.POI是一个开源 ...

  7. ffmpeg 踩坑实录 安装与视频切片(一)

    这段时间一直在做一个关于视频处理的项目.其中有一块需要切片相关功能.于是采用了ffmpeg来完成相关需求. 第一,ffmpeg的安装. 首先下载官方包,我这里用的是ffmpeg-release-64b ...

  8. windows安装rabbitmq踩坑实录

    最近学习springcloud消息总线需要用到rabbitmq,然后安装的时候踩了一些坑,记录如下: 首先安装rabbitmq之前需要先安装erlang,因为rabbitmq服务端使用erlang写的 ...

  9. Ubuntu14.04安装PowerDNS踩坑实录

    公司要使用PowerDNS,作为内网域名解析的工具.让我和另一组的同事学一下如何配置及调优.所以先找了两台服务器试着安装一下.这一装就是一个礼拜,经历了大大小小的坑,记下来以后可能需要参考.安装过程如 ...

随机推荐

  1. 【译】从数学公式入手,详细了解 Animation 的 Interpolators

    我们在做动画的时候,总是避免不了会使用到 Interpolator(插值器)这个东西,比如 LinearInterpolator 等.这样做的好处是,能够让动画的变化速度符合现实世界中的物理规律,看上 ...

  2. html2canvas 截屏 兼容手机端

    <template> <div> <!--<input type="button" id="btnsavaImg" valu ...

  3. Android常见问题——找不到HttpClient和okHttp的包

    今天再用Android Studio进行网络编程的时候遇到了一个问题,就是怎么也找不到HttpClient的包,上网搜了一下也没什么结果,但最后偶然解决问题,下面总结了一下方法: 首先打开File-& ...

  4. OK335xS knob driver hacking

    /************************************************************************* * OK335xS knob driver hac ...

  5. linux下vi命令(转)

    进入vi的命令 vi filename :打开或新建文件,并将光标置于第一行首 vi +n filename :打开文件,并将光标置于第n行首 vi + filename :打开文件,并将光标置于最后 ...

  6. BZOJ2154 Crash的数字表格 【莫比乌斯反演】

    BZOJ2154 Crash的数字表格 Description 今天的数学课上,Crash小朋友学习了最小公倍数(Least Common Multiple).对于两个正整数a和b,LCM(a, b) ...

  7. SQL之 UNION ALL 和UNION

    有时候复杂的逻辑处理可以交给SQL来处理,自认为是比java处理要快点. 举个例子:如何统计每个品牌的的偏好用户数? 当时我做的处理是在java中处理这些品牌,若是品牌相同,就加一,但是这种方法很慢, ...

  8. 读取JSON文件并 排序,分组,

    读取.json文件 public string GetFileJson(string filepath) { string json = string.Empty; using (FileStream ...

  9. windows下gvim中文乱码解决方案

    网罗了一些网上的解决windows下gvim中文乱码的解决方案,都试了一遍,可惜都不能完全解决我的所有问题,最后我综合一下网上的两种方案,得到了最后完全解决我的中文乱码问题的方案,配置很简单,就是把下 ...

  10. LOJ #3049. 「十二省联考 2019」字符串问题

    LOJ #3049. 「十二省联考 2019」字符串问题 https://loj.ac/problem/3049 题意:给你\(na\)个\(A\)类串,\(nb\)个\(B\)类串,\(m\)组支配 ...