用一个程序生成另一个程序_还有另一个报告生成器?

用一个程序生成另一个程序

如果您具有业务应用程序开发的经验,那么很可能会遇到要求该应用程序具有灵活的报告机制的需求。 我工作的公司主要专注于开发业务解决方案,而报告是必不可少的,实际上,它必须包含我们开发的所有企业系统的方面。 为了在我们的系统中实现灵活的报告,我们开发了自己的开源报告生成器-YARG (又一次获得了另一个报告生成器)(以Apache 2.0许可分发)。 现在,YARG是CUBA平台报告的核心-CUBA 平台本身就是我们开发的所有系统的基础。

为什么需要开发一个新的

首先,让我指出我们不是车轮发明家。 只要这些解决方案适合我们,我们就一直在寻找与之集成的解决方案。 不幸的是,在这种情况下,我们找不到符合我们确定的以下要求的任何开源工具:

  • 以模板格式生成报告和/或将输出转换为PDF
  • 避免使用外部工具来创建报告模板(Microsoft Office或Libreoffice应该足够了)
  • 支持各种格式的模板: DOC,ODT,XLS,DOCX,XLSX,HTML
  • 能够将复杂的XLSXLSX模板与图表,公式等配合使用。
  • 能够使用HTML布局和插入/嵌入图像
  • 拆分出数据层(报告结构和数据获取)和表示层(报告模板)
  • 启用各种数据获取方法,例如SQL,JPQL或Groovy脚本
  • 与IoC框架( SpringGuice )集成的能力
  • 将该工具用作独立应用程序的功能,以便能够在Java生态系统之外使用它(例如,使用PHP生成报告)
  • 以透明XML格式存储报告结构

我们可以找到的最接近的工具是JasperReports ,但是有一些阻止程序使我们无法使用它:

  • 免费版本无法生成DOC报告(有一个提供此功能的商业库)
  • XLS报告非常有限,无法使用图表,公式和单元格格式
  • 要创建报告,必须具有一定的技能和知识,以及如何使用非常特定的工具(例如iReports
  • 数据层和表示层之间没有明确的分隔

当然,我们研究了许多其他不同的工具,但是我们发现的所有其他库都集中在某种特定格式上。 我们希望有一个万能的报表功能-一种用于所有报表的工具。

考虑到以上列出的所有观点和想法,我们决定开发另一种定制的报告生成工具。

什么是内幕

当我们开始YARG时,找到用于XLS集成的库( POI-HSSFJXLS等)不是问题。 我们决定选择Apache POI作为最受欢迎和受支持的库。

DOC集成的情况则完全相反。 在开源市场上只有很少的选择( POI-HWPFCOMUNO Runtime )。 POI-HWPF库在许多方面都非常有限,我们认为它不是合适的选择。 我们必须在COMUNO运行时之间进行选择这实际上是用于OpenOffice服务器端集成的API。

因此,经过深入调查,我们决定选择UNO Runtime ,主要是因为成功将其用于以完全不同的语言(例如Python,Ruby,C#等)编码的系统的人们的积极反馈。

尽管POI-HSSF的使用非常简单(图表除外),但我们在集成UNO Runtime时面临许多挑战:

  1. 没有明确的API可用于表格
  2. 每次生成报告时,OpenOffice都会启动。 最初,我们使用bootstrapconnector来管理OpenOffice进程,但是后来很明显,在很多情况下,它不会在生成报告后终止该进程。 因此,我们不得不重新实现OpenOffice启动和关闭的逻辑(感谢jodconverter开发人员,他们在此问题上指出了许多好主意)
  3. 另外, UNO Runtime (和OpenOffice Server本身)在线程安全方面也存在严重问题,如果发生内部错误,这可能导致服务器冻结或终止自身。 为了克服这个问题,我们必须实现一种机制,以便在服务器发生故障时重新启动报告,这显然会对性能造成不利影响

后来,当DOCX4J库变得非常成熟和流行时,我们支持XLSX / DOCX。 DOCX4J库的主要优点是,它提供了对文档结构的必要的低级访问(基本上,您使用XML进行操作)。 使用DOCX4J的另一个好处是,它不需要OpenOffice服务器集成即可生成DOCX报告。

另外,还可以使用带有Freemarker标记的文档作为报告模板。 我们通常使用它生成非常自定义的HTML报表,然后将结果转换为PDF

最后,YARG基础结构是以可扩展的方式开发的,因此有经验的用户可以自己实现与任何其他模板类型的集成。

你好世界报告

让我们认识一下YARG。 报告生成器的主要思想是将数据层和表示层分开。 数据层使脚本编制或直接SQL查询能够获取所需的信息,而表示层则代表所获取数据的标记。

YARG的所有报告均由所谓的“乐队”组成是将数据和表示层链接在一起的东西。 因此,每个乐队都知道从何处获取数据以及将数据放置在模板中的位置。

例如,我们想将所有员工打印到Excel电子表格中。 我们将需要创建“ Staff”乐队并定义一个SQL查询以获取员工列表:

select name, surname, position from staff

Java代码

ReportBuilder reportBuilder = new ReportBuilder();
ReportTemplateBuilder reportTemplateBuilder = new ReportTemplateBuilder().documentPath("/home/haulmont/templates/staff.xls").documentName("staff.xls").outputType(ReportOutputType.xls).readFileFromPath();
reportBuilder.template(reportTemplateBuilder.build());
BandBuilder bandBuilder = new BandBuilder();
ReportBand staff= bandBuilder.name("Staff").query("Staff", "select name, surname, position from staff", "sql").build();
reportBuilder.band(staff);
Report report = reportBuilder.build();Reporting reporting = new Reporting();
reporting.setFormatterFactory(new DefaultFormatterFactory());
reporting.setLoaderFactory(new DefaultLoaderFactory().setSqlDataLoader(new SqlDataLoader(datasource)));ReportOutputDocument reportOutputDocument = reporting.runReport(new RunParams(report), new FileOutputStream("/home/haulmont/reports/staff.xls"));

剩下的唯一事情就是创建XLS模板:

1个

开始了! 只需运行该程序即可享受结果!

没有Java的进阶范例

假设我们有一个书店网络。 需要生成一个XLS报告,其中显示了已售书的列表,并参考了售书的书店。 此外,我们没有Java开发人员,只有拥有XMLSQL基本技能的系统管理员。

首先,我们需要为报告创建XLS模板:

2

如您所见,我们定义了两个命名区域(对应于乐队):商店(蓝色)和书籍实例(白色)。

现在,我们必须从数据库中获取所需的数据:

select shop.id as "id", shop.name as "name", shop.address as "address" 
from store shopselect book.author as "author", book.name as "name", book.price as "price",  count(*) as "count" 
from book book where book.store_id = ${Shop.id} 
group by book.author, book.name, book.price

最后,我们使用XML声明报告的波段结构:

<?xml version="1.0" encoding="UTF-8"?>
<report name="report"><templates><template code="DEFAULT" documentName="bookstore.xls" documentPath="./test/sample/bookstore/bookstore.xls" outputType="xls" outputNamePattern="bookstore.xls"/></templates><rootBand name="Root" orientation="H"><bands><band name="Header" orientation="H"/><band name="Shop" orientation="H"><bands><band name="Book" orientation="H"><queries><query name="Book" type="sql"><script>select book.author as "author", book.name as "name", book.price as "price",  count(*) as "count" from book  where book.store_id = ${Shop.id} group by book.author, book.name, book.price</script></query></queries></band></bands><queries><query name="Shop" type="sql"><script>select shop.id as "id", shop.name as "name", shop.address as "address" from store shop</script></query></queries></band></bands><queries/></rootBand>
</report>

让我们启动报告并查看结果(下面的“ 独立”部分描述了如何运行报告):

3

该用例表明,您可以引用父带:book.store_id = $ {Shop.id}。 这使我们能够过滤每个特定书店出售的书籍。

一个更高级的例子

现在,我们创建一个发票报告。 我们将创建DOCX文档,然后将其转换为不可变形式– PDF文档。 为了说明如何加载数据的另一种方式,我们将使用groovy脚本,而不是直接SQL查询:

<?xml version="1.0" encoding="UTF-8"?>
<report name="report"><templates><template code="DEFAULT" documentName="invoice.docx" documentPath="./test/sample/invoice/invoice.docx" outputType="pdf" outputNamePattern="invoice.pdf"/></templates><formats><format name="Main.date" format="dd/MM/yyyy"/><format name="Main.signature" format="${html}"/></formats><rootBand name="Root" orientation="H"><bands><band name="Main" orientation="H"><queries><query name="Main" type="groovy"><script>return [['invoiceNumber':99987,'client' : 'Google Inc.','date' : new Date(),'addLine1': '1600 Amphitheatre Pkwy','addLine2': 'Mountain View, USA','addLine3':'CA 94043','signature':<![CDATA['<html><body><b><font color="red">Mr. Yarg</font></b></body></html>']]>]]</script></query></queries></band><band name="Items" orientation="H"><queries><query name="Main" type="groovy"><script>return [['name':'Java Concurrency in practice', 'price' : 15000],['name':'Clear code', 'price' : 13000],['name':'Scala in action', 'price' : 12000]]</script></query></queries></band></bands><queries/></rootBand>
</report>

您可能已经注意到,Groovy脚本返回List <Map <String,Object >>对象。 因此,每个项目都表示为一个键(参数名称)和值(参数值)。

4

最后,我们将需要创建一个DOCX模板:

要将底部表格链接到书籍列表,我们使用## band = Items标记。

生成报告后,我们得到以下输出:

5

IoC框架集成

如前所述,要求之一是提供集成到IoC框架( SpringGuice )的能力。 我们将YARG用作CUBA平台(我们用于企业应用程序开发的高级Java框架)中强大的报告引擎的一部分。 CUBA采用Spring作为IoC机制,让我们看一下YARG如何集成到平台中:

<bean id="reporting_lib_Scripting" class="com.haulmont.reports.libintegration.ReportingScriptingImpl"/>
<bean id="reporting_lib_GroovyDataLoader" class="com.haulmont.yarg.loaders.impl.GroovyDataLoader"><constructor-arg ref="reporting_lib_Scripting"/>
</bean>
<bean id="reporting_lib_SqlDataLoader" class="com.haulmont.yarg.loaders.impl.SqlDataLoader"><constructor-arg ref="dataSource"/>
</bean>
<bean id="reporting_lib_JpqlDataLoader" class="com.haulmont.reports.libintegration.JpqlDataDataLoader"/>
<bean id="reporting_lib_OfficeIntegration"class="com.haulmont.reports.libintegration.CubaOfficeIntegration"><constructor-arg value="${cuba.reporting.openoffice.path?:/}"/><constructor-arg><list><value>8100</value><value>8101</value><value>8102</value><value>8103</value></list></constructor-arg><property name="displayDeviceAvailable"><value>${cuba.reporting.displayDeviceAvailable?:false}</value></property><property name="timeoutInSeconds"><value>${cuba.reporting.openoffice.docFormatterTimeout?:20}</value></property>
</bean>
<bean id="reporting_lib_FormatterFactory"class="com.haulmont.yarg.formatters.factory.DefaultFormatterFactory"><property name="officeIntegration" ref="reporting_lib_OfficeIntegration"/>
</bean>
<bean id="reporting_lib_LoaderFactory" class="com.haulmont.yarg.loaders.factory.DefaultLoaderFactory"><property name="dataLoaders"><map><entry key="sql" value-ref="reporting_lib_SqlDataLoader"/><entry key="groovy" value-ref="reporting_lib_GroovyDataLoader"/><entry key="jpql" value-ref="reporting_lib_JpqlDataLoader"/></map></property>
</bean>
<bean id="reporting_lib_Reporting" class="com.haulmont.yarg.reporting.Reporting"><property name="formatterFactory" ref="reporting_lib_FormatterFactory"/><property name="loaderFactory" ref="reporting_lib_LoaderFactory"/>
</bean>

为了将YARG集成到Spring Framework中,应注册以下bean:

  1. reporting_lib_Reporting –提供对核心报告生成功能的访问。 report_lib_FormatterFactory –将输出管理为不同的格式(DOCX,XSLX,DOC等)
  2. reporting_lib_LoaderFactory –提供数据加载功能(包含与不同源相对应的多个Bean)
  3. reporting_lib_OfficeIntegration –将报表生成器与OpenOffice服务器集成(生成DOC和ODT报表所需)

如您所见,YARG可以轻松地嵌入到您的应用程序中。

独立使用

YARG的另一个重要功能是可以用作独立应用程序。 从技术上讲,如果已安装JRE,则可以从命令提示符下运行报告生成器。 例如,如果您有服务器端PHP应用程序,并且想在应用程序中启用报告,则只需创建一个XLS模板,以XML声明报告结构,然后从命令提示符下启动YARG:

yarg -rp ~/report.xml -op ~/result.xls “-Pparam1=20/04/2014”

CUBA平台提供的更多功能

YARG已深度集成到CUBA平台中,并充当该平台中实现的强大报告机制的核心引擎。

首先,您可以使用CUBA Studio一键式嵌入报告( 此处提供只读演示版):

6

CUBA为报表管理提供了方便的用户界面:

  • 报告浏览器,带有导入/导出和运行报告的选项。 7
  • 报告编辑器允许您创建任何复杂性的报告(定义带,输入参数,管理模板,使用Groovy,SQL和JPQL选择数据): 8
  • CUBA引入了报告向导功能。 借助向导,即使对编程的了解有限,任何用户都可以快速创建报告: 9

总结这篇文章,让我跳过通常无聊的深层思考(特别是因为可以在此处找到所有信息),并提出了一些我最喜欢的报告:

10

11

因此,如果您有兴趣,请点击链接并了解更多信息! 请注意,YARG是完全免费的,可以在GitHub上使用 。

翻译自: https://www.javacodegeeks.com/2015/09/yet-another-report-generator.html

用一个程序生成另一个程序

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

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

相关文章

CocosCreator1.x实现水流动的效果

CocosCreator1.x实现水流动的效果Cocos Creator版本&#xff1a;1.10.2 运行结果&#xff1a;(H5和原生都支持) 场景: 脚本&#xff1a; HelloWorld.js&#xff1a; let shader require(shader);cc.Class({extends: cc.Component,properties: {water: cc.Node,waterNorm…

python爬虫xpath教程_使用 Xpath 进行爬虫开发

使用 Xpath 进行爬虫开发 Xpath( XML Path Language, XML路径语言)&#xff0c;是一种在 XML 数据中查找信息的语言&#xff0c;现在&#xff0c;我们也可以使用它在 HTML 中查找需要的信息。 既然谈到 Xpath 是一门语言&#xff0c;当然它就会有自己的一些特定的语法。我们这里…

用C语言写烟花,给心中的那个人看!

点击蓝字关注我们前言程序员不懂浪漫? 大错特错&#xff01;今天就让你们看看什么是程序员的浪漫&#xff01;你向窗外看烟花&#xff0c;我在窗边看你&#xff0c;这时&#xff0c;你比烟花好看的多&#xff0c;你的眼眸倒映满天的烟火&#xff0c;我的瞳孔倒映你温柔的脸庞…

手把手教你做一个线程池--C语言版

点击蓝字关注我们1、线程池原理我们使用线程的时候就去创建一个线程&#xff0c;这样实现起来非常简便&#xff0c;但是就会有一个问题&#xff1a;如果并发的线程数量很多&#xff0c;并且每个线程都是执行一个时间很短的任务就结束了&#xff0c;这样频繁创建线程就会大大降低…

oracle 48小时内_缺血性脑梗死后48小时内使用阿替普酶能够降低脑损伤程度

一项刊登在影响因子7.6杂志Neurology上题为“Effect of IV alteplase on the ischemic brain lesion at 24–48 hours after ischemic stroke”的研究报告中&#xff0c;来自爱丁堡大学的科学家们发现&#xff0c;alteplase与病变可视性的短期进展降低相关。在荟萃分析中&#…

MySQL夺命16问,你能坚持到第几问?

点击蓝字关注我们1、数据库三大范式是什么&#xff1f;第一范式&#xff1a;每个列都不可以再拆分。第二范式&#xff1a;在第一范式的基础上&#xff0c;非主键列完全依赖于主键&#xff0c;而不能是依赖于主键的一部分。第三范式&#xff1a;在第二范式的基础上&#xff0c;非…

美图手机投射功能在哪_在Java 8中进行投射(还有其他功能?)

美图手机投射功能在哪将实例转换为设计不良的类型。 尽管如此&#xff0c;在某些情况下没有其他选择。 从第一天开始&#xff0c;执行此功能就已成为Java的一部分。 我认为Java 8提出了对这种古老技术稍加改进的需求。 静态铸造 Java中最常见的转换方法如下&#xff1a; 静态…

js箭头函数和普通函数区别

js箭头函数和普通函数区别实验环境&#xff1a;nodejs v12.16.1 箭头函数不能作为构造函数&#xff0c;而普通函数可以 箭头函数没有原型&#xff0c;而普通函数有 箭头函数return可以省略语句块。(如果>右边不是语句块&#xff0c;则代表return右边的表达式或对象) 箭…

git 更新_[技术分享T.191212]GitLab使用方法及git命令常见问题(不断更新)

该文章用于记录一些GitLab的使用指南&#xff0c;以及在实际版本控制过程中遇到的问题及解决方法&#xff0c;会尽量及时的更新~GitLab简介&#xff1a;GitLab和GitHub很相似都属于仓库管理系统的开源项目&#xff0c;使用Git作为代码管理工具&#xff0c;并在此基础上搭建起来…

记一次开发实战-对提供接口的C/C++进行二次开发

点击蓝字关注我们一、需求描述我有一个USB5538的库和头文件&#xff0c;并通过头文件提供了接口&#xff0c;我想把它更改一下&#xff0c;编译成python可调用的模块。二、创建工程及其目录1、创建空项目2、创建目录三、创建文件1、复制文件并添加2、添加新文件并写入四、环境配…

C++是如何实现多态的

C是如何实现多态的结论&#xff1a;C通过虚函数来实现多态的&#xff0c;根本原因是派生类和基类的虚函数表的不同。 构成多态的必要条件有如下3点&#xff1a; 存在继承关系基类存在虚函数&#xff0c;且派生类有相同原型的函数遮蔽它存在基类类型的指针指向派生类对象&…

C语言实现通讯录附详细代码(动态+静态)

点击蓝字关注我们一、通讯录简介实现一个通讯录&#xff1b;通讯录可以用来存储1000个人的信息&#xff0c;每个人的信息包括&#xff1a;姓名、性别、年龄、电话、住址提供方法&#xff1a;添加联系人信息删除指定联系人信息查找指定联系人信息修改指定联系人信息显示所有联系…

Lua协程Coroutine是什么

Lua协程Coroutine是什么协程和线程不同&#xff1a; 同一时刻&#xff0c;一个多线程程序可以用多个线程同时执行&#xff1b;而协程只能有一个在执行多线程是抢占式的&#xff1b;而协程是非抢占式的&#xff0c;只有协程显示被挂起&#xff0c;才会被挂起 协程和线程的相同…

C++程序的内存分区模型-栈区堆区

点击蓝字关注我们1、栈区&#xff1a;由编译器自动分配释放&#xff0c;存放函数的参数值&#xff0c;局部变量等&#xff08;由编译器管理其“生死”&#xff09;注意事项&#xff1a;不要返回局部变量的地址&#xff0c;栈区开辟的数据由编译器自动释放栈区代码演示&#xff…

CocosStudio的节点如何使用自定义shader

CocosStudio的节点如何使用自定义shader问题&#xff1a;我想对CocosStudio 的 某个UI 里的 某个图片&#xff08;如下图所示的Image类型&#xff09;使用自定义shader。但是&#xff0c;我把 对传统的cc.Sprite应用自定义shader的方式 应用于它时&#xff0c;并不生效&#xf…

excel随机抽取_简单随机抽样及其进阶分层随机抽样方法展示

一、分享简单随机抽样的几种方法1、抽样分析工具抽样2、INDIRECTRANDBETWEEN函数抽样3、RAND排序抽样4、SAS抽样二、分层抽样方法1、Python分层抽样2、SAS分层抽样3、EXCEL函数及功能分层抽样简单随机抽样的几种方法方法一抽样分析工具抽样如果你的EXCEL尚未安装数据分析&#…

为什么存在动态内存分配,动态内存函数(malloc函数,free函数,calloc函数,realloc函数)...

点击蓝字关注我们1.当前我们知道的内存的使用方法2.为什么存在动态内存分配如上我们已学的开辟空间的方式有两个特点&#xff1a;空间开辟的大小是固定的必须指定数组的长度所以就产生了空间开大了浪费开小了不够用的问题&#xff0c;所以使用动态内存分配3.动态内存函数&#…

C++ vector类的模拟实现

点击蓝字关注我们1.前言vector和string虽然底层都是通过顺序表来实现的&#xff0c;但是他们利用顺序表的方式不同&#xff0c;string是指定好了类型&#xff0c;通过使用顺序表来存储并对数据进行操作&#xff0c;而vector是利用了C中的泛型模板&#xff0c;可以存储任何类型的…

visual studio源文件的编译顺序是依据什么?

问题&#xff1a;visual studio源文件的编译顺序是依据什么&#xff1f; 结论&#xff1a;依据 .vcxproj 文件里 指定了ClCompile的ItemGroup &#xff0c;如下图所示&#xff0c;就是这么简单粗暴。

功能齐全的屏幕截图C++实现详解

点击蓝字关注我们1、概述要使用屏幕截图&#xff0c;其实很容易&#xff0c;装一款聊天软件或者办公软件就可以了&#xff0c;比如QQ、企业微信、钉钉、飞书等。但要开发出类似这些软件的屏幕截图模块&#xff0c;则没那么容易。其实实现屏幕截图的技术并不复杂&#xff0c;主要…