JasperReports:棘手的部分

如果您使用Java进行编程的时间足够长,则有可能需要为业务用户生成报告。 就我而言,我已经看到几个项目使用JasperReports®库来生成PDF和其他文件格式的报告。 最近,我荣幸地观察了Mike和他的团队使用上述报告库及其面临的挑战。

简而言之JasperReports

简而言之,使用JasperReports(JR)生成报告涉及三个步骤:

  1. 加载已编译的报告(即,加载JasperReport对象)
  2. 通过用数据填充报告来运行报告(结果是JasperPrint对象)
  3. 将填充的报告导出到文件(例如,使用JRPdfExporter导出到PDF)

在Java代码中,看起来像这样。

JasperReport compiledReport = JasperCompileManager.compileReport("sample.jrxml");
Map<String, Object> parameters = ...;
java.sql.Connection connection = dataSource.getConnection();
try {JasperPrint filledReport = JasperFillManager.fillReport(compiledReport, parameters, connection);JasperExportManager.exportReportToPdf(filledReport, "report.pdf");
} finally {connection.close();
}

多亏了facade类,这看起来很简单。 但是外表可能是骗人的!

鉴于以上代码段(以及概述的三个步骤),您认为哪些部分需要最多的时间和内存? (听起来像面试问题)。

如果您回答(#2)填写数据,那是对的! 如果您回答了#3,那也是正确的,因为#3与#2成正比。

恕我直言 ,大多数在线教程仅显示简单的部分。 就JR而言 ,似乎缺少对较困难和棘手的部分的讨论。 在这里,与Mike的团队一起,我们遇到了两个困难:内存不足错误和长期运行的报告。 使这些困难特别令人难忘的是,它们仅在生产过程中出现(而不在开发过程中)。 我希望通过共享它们,将来可以避免它们。

内存不足错误

第一个挑战是报告内存不足。 在开发过程中,与实际操作数据相比,我们用于运行报告的测试数据将太小。 因此, 为此设计

在我们的例子中,所有报告都使用JRVirtualizer运行。 这样,当达到内存中的页面/对象最大数量时,它将刷新到磁盘/文件。

在此过程中,我们还了解到虚拟器需要清理。 否则,周围会有几个临时文件。 而且,只有在报告导出到文件 ,我们才能清理这些临时文件。

Map<String, Object> parameters = ...;
JRVirtualizer virtualizer = new JRFileVirtualizer(100);
try {parameters.put(JRParameter.REPORT_VIRTUALIZER, virtualizer);...... filledReport = JasperFillManager.fillReport(compiledReport, parameters, ...);// cannot cleanup virtualizer at this pointJasperExportManager.exportReportToPdf(filledReport, ...);
} finally {virtualizer.cleanup();
}

有关更多信息,请参见Virtualizer Sample – JasperReports 。

请注意,当我们在运行报表时遇到内存不足的错误时,JR 并不总是罪魁祸首。 有时,即使在使用JR之前,我们也会遇到内存不足错误。 我们看到了如何滥用JPA来加载报告的整个数据集( Query.getResultList()TypedQuery.getResultList() )。 同样,由于数据集仍然很小,因此在开发期间不会显示该错误。 但是,当数据集太大而无法容纳在内存中时,我们会遇到内存不足错误。 我们选择避免​​使用JPA生成报告。 我猜我们只需要等待JPA 2.2的Query.getResultStream()可用即可。 我希望JPA的Query.getResultList()返回Iterable 。 这样,就有可能一次映射一个实体,而不是整个结果集。

现在,避免加载整个数据集。 一次加载一个记录。 在此过程中,我们返回了良好的JDBC。 不错,JR很好地使用了ResultSet

长期运行的报告

第二个挑战是长期运行报告。 同样,在开发过程中可能不会发生这种情况。 充其量,将运行10秒钟左右的报告视为冗长。 但是,有了实际的运行数据,它可以运行大约5-10分钟。 当根据HTTP请求生成报告时,这尤其麻烦。 如果报告可以在超时时间段内(通常为60秒或最多5分钟)开始写入响应输出流,那么它很有可能被请求用户(通常是通过浏览器)接收。 但是,如果填写报告需要5分钟以上的时间,而导出到文件又需要8分钟,那么用户将只会看到超时的HTTP请求,并将其记录为错误。 听起来有点熟?

请记住,报告可能会运行几分钟。 因此, 为此设计

就我们而言,我们在单独的线程上启动报告。 对于通过HTTP请求触发的报告,我们将以一个页面进行响应,该页面包含指向所生成报告的链接。 这样可以避免超时问题。 当用户单击此链接而报告尚未完成时,他/她将看到仍在生成报告。 但完成的报告时,他/她就可以看到生成的报告文件。

ExecutorService executorService = ...;
... = executorService.submit(() -> {Map<String, Object> parameters = ...;try {...... filledReport = JasperFillManager.fillReport(compiledReport, parameters, ...);JasperExportManager.exportReportToPdf(filledReport, ...);} finally {...}
});

我们还必须添加停止/取消运行报告的功能。 好东西,JR有检查Thread.interrupted()代码。 因此,仅中断线程将使其停止。 当然,您需要编写一些测试来进行验证(期望JRFillInterruptedExceptionExportInterruptedException )。

在讨论过程中,我们重新发现了将“监听器”添加到报告生成中的方法(例如FillListenerJRExportProgressMonitor )并为用户提供一些进度信息。

我们还创建了实用程序测试类,以通过反复重复给定的数据来生成大量数据。 这对于帮助团队的其他成员开发专为处理长期运行和内存不足错误而设计的JR应用程序很有用。

进一步的设计考虑

要考虑的另一件事是填写报告时需要打开和关闭所需的资源。 这可以是JDBC连接,Hibernate会话,JPA EntityManager或文件输入流(例如CSV,XML)。 下图是我的设计注意事项的粗略草图。

1. Compiling- - - - - - - - - - - - - -\- - - -\                    \
2. Filling       > open-close         \- - - -/   resource           > swap to file/
3. Exporting                         /- - - - - - - - - - - - - -/

我们要隔离#2并定义装饰器,这些装饰器将打开资源,填充报告并在finally块中关闭打开的资源。 打开的资源可能取决于报表中的<queryString>元素(如果存在)。 在某些情况下,如果没有<queryString>元素,则可能无需打开资源。

<queryString language="hql"><![CDATA[ ... ]]>
</queryString>
...
<queryString language="csv"><![CDATA[ ... ]]>
</queryString>

此外,我们还希望将#2和#3组合为一种抽象。 这种单一的抽象使您可以更轻松地进行增强装饰,例如将创建的页面对象刷新为文件,并在导出过程中将其加载回。 如前所述,这就是JRVirtualizer所做的。 但是我们希望使用结合#2和#3的抽象对对象透明的设计。

致谢

目前为止就这样了。 再次感谢Mike和他的团队分享了他们的经验。 是的,他是将自己应用的收入捐赠给慈善机构的那个人 。 另外,还要感谢克莱尔(Claire)通过一次又一次重复给定数据进行测试的想法。 相关代码段可以在GitHub上找到 。

翻译自: https://www.javacodegeeks.com/2018/01/jasperreports-tricky-parts.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/348088.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

win mysql 2003错误_windows MySql 报1067错误 2003错误

1067错误原因是我把安装mysql的目录的名字改了。但是位于目录里面的my.ini配置文件没有修改&#xff0c;玛德我真傻逼。把my.ini的#Path to installation directory. All paths are usually resolved relative to this.basedir"D:/My_MySQL/"这下面一行的路径名改成目…

分布式系统开发注意点_分布式系统开发注意事项

分布式系统开发注意点开发分布式软件系统时&#xff0c;要考虑许多因素。 如果您甚至不知道第一句话中我在说什么&#xff0c;那么让我为您提供一些见解&#xff0c;示例以及有关分布式系统的实例。 总览 分布式系统是指多个物理硬件设备与单独的离散用户交互并通过这些硬件设…

电子电气架构——车载ECU刷写工具vFlash简介

电子电气架构——车载ECU刷写工具vFlash简介 我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 没有人关注你。也无需有人关注你。你必须承认自己的价值&a…

ldap java_使用LDAP保护Java EE6中的Web应用程序

ldap java在上一篇文章中&#xff0c;我们解释了如何在通过传输层安全性&#xff08;TLS&#xff09;/安全套接字层&#xff08;SSL&#xff09;传输数据时保护数据。 现在让我们尝试了解如何为使用LDAP服务器进行身份验证的基于JEE 6的Web应用程序应用安全机制。 目的&#x…

mysql 一致性hash_一致性hash算法在分表分库中的应用

一致性hash算法结构图 分表分库结构图 可进行循环冗余存储&#xff0c;顺时针存储到下一个物理节点(非虚拟节点)package com.haiziwang.platform.kmcsms.route.algorithm;import java.util.Collection;import java.util.SortedMap;import java.util.TreeMap;/*** 一致性Hash算法…

生产中的性能分析

生产中的性能分析 如果您在Java应用程序的性能方面遇到了一些严重问题&#xff0c;那么很可能您会知道线程分析的价值。 但是您知道应该使用哪个分析器吗&#xff1f; 探查器使用两种基本技术-采样和仪器。 采样分析器 采样探查器包括定期向JVM询问所有当前活动线程的当前执行…

mysql用com_MySQL 使用教程

关于 MySQLMySQL 是最流行的开源数据库。本文简明的讲解了 MySQL 如何下载安装到使用的整个过程。MySQL 支持多种特性&#xff1a;使用 C和 C编写&#xff0c;并使用了多种编译器进行测试&#xff0c;保证了源代码的可移植性。支持 AIX、FreeBSD、HP-UX、Linux、Mac OS、Novell…

c++ 一维数组长度_每天一点C / 一维数组和指针

哈喽&#xff0c;我是老吴&#xff0c;继续记录我的学习心得。每天一点系列是我对微习惯的践行。现在能做到每天一点 C&#xff0c;将来就会有更多的每天一点系列&#xff0c;没人规定嵌入式软件工程师就只能学习 C 语言和折腾 Linux&#xff0c;不要给自己设限。为什么是每天一…

mysql事务中怎么更改空值_MySQL事务

1.事务1.事务特性--ACIDAtomicity(原子性):要么全做,要么不做,不能只做一半(银行转账)Consistency(约束性):事务的前后,约束都能满足Isolation(依赖性):事务之间是独立的,互不影响的Durability(持久性):事务执行之后,事物的结果可以持久保存2.事务隔离级别:read uncommitted:可…

线程池实现填充短信_填充一个池需要多少个线程?

线程池实现填充短信在最近几个月中&#xff0c;我们一直看到很小但持续的操作失败&#xff0c;但有一个奇怪的异常– org.springframework.jdbc.CannotGetJdbcConnectionException –“无法获得JDBC连接&#xff1b; 嵌套异常是java.sql.SQLException&#xff1a;客户端尝试检出…

jsf标签_多个动态包含一个JSF标签

jsf标签每个JSF开发人员都知道ui&#xff1a;include和ui&#xff1a;param标签。 您可以包括一个facelet&#xff08;XHTML文件&#xff09;并传递一个对象&#xff0c;该对象将在包含的facelet中可用&#xff0c;如下所示&#xff1a; <ui:include src"/sections/co…

spring 长轮询_Spring集成文件轮询和测试

spring 长轮询我最近实施了一个小项目&#xff0c;在该项目中&#xff0c;我们必须轮询文件夹中的新文件&#xff0c;然后在文件内容上触发服务流。 Spring Integration非常适合此要求&#xff0c;因为它带有一个通道适配器 &#xff0c;该适配器可以扫描文件夹中的新文件&…

您将在下一个项目中使用JSF吗?

上周有一篇很棒的stackoverflow博客文章&#xff0c;主题是“ JavaScript框架的残酷生命周期” 。 这篇文章是关于Javascript UI框架&#xff08;angularjs&#xff0c;angular&#xff0c;jquery和react&#xff09;的流行和流行的速度。 这篇文章的关键指标是每月关于框架的问…

使用java自带的日志管理_java日志管理

1.相关概念日志统一框架(日志门面)&#xff1a;apache commons logging、slf4j日志实现框架(实现层)&#xff1a;JDK自带的logging(java.util.logging)、log4j、Java Util Logging、log4j2、logback.(1)JDK自带的logging(java.util.logging)用法&#xff1a;1 importjava.util.…

安卓4.4玩java_Android4.4运行过程中闪退java.lang.NoClassDefFoundError

上周五项目测试时发现一个奇怪的Bug&#xff0c;项目中依赖了一个第三方框架&#xff0c;但是在android4.0-4.4.4之间的系统中运行会直接闪退&#xff0c;抛出错误异常为java.lang.NoClassDefFoundError。第一次遇到这样的问题&#xff0c;google了好久找到了以下几个原因&…

update se_Java SE 7 Update 25 –发行说明进行了解释。

update se昨天是CPU日。 Oracle通过6月的Java重要补丁更新发布了Java SE更新25 。 在4月的最后一次重大更新之后&#xff0c;这是最后一次与Oracle其他所有Oracle产品都不适合的Oracle重要补丁更新计划。 从2013年10月开始 &#xff0c;Java安全修补程序将遵循四个年度安全发布…

java scavenge_请概述一下Java中都有哪些垃圾收集器

1、Serial(串行GC)收集器Serial收集器是一个新生代收集器&#xff0c;单线程执行&#xff0c;使用复制算法。它在进行垃圾收集时&#xff0c;必须暂停其他所有的工作线程(用户线程)。是Jvmclient模式下默认的新生代收集器。对于限定单个CPU的环境来说&#xff0c;Serial收集器由…

阿帕奇光束

Apache Beam是一个开放源代码统一模型&#xff0c;用于定义批处理和流数据并行处理管道。 使用一种开源的Beam SDK&#xff0c;您可以构建一个定义管道的程序。 然后&#xff0c;该管道由Beam支持的分布式处理后端之一执行&#xff0c;这些后端包括Apache Apex &#xff0c; Ap…

java音乐登陆界面_第四篇——Spring音乐登录界面设计及实现(C#)

Spring音乐播放器&#xff0c;我们小组设计其启动时有一个登录界面&#xff0c;用户初次可以注册&#xff0c;输入用户名和密码&#xff0c;点击注册即将输入信息保存到register文本文件中&#xff1b;如果已有用户名&#xff0c;输入用户名和密码&#xff0c;点击登录&#xf…

java中线性结构的例子_java数据结构--线性结构

一、数据结构数据结构由数据和结构两部分组成&#xff0c;就是将数据按照一定的结构组合起来&#xff0c;这样不同的组合方式有不同的效率&#xff0c;可根据需求选择不同的结构应用在相应在场景。数据结构大致分为两类&#xff1a;线性结构(如数组&#xff0c;链表&#xff0c…