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

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

如果您具有业务应用程序开发的经验,那么很可能会遇到要求该应用程序具有灵活的报告机制的需求。 我工作的公司主要专注于开发业务解决方案,而报告是必不可少的,实际上,它必须包含我们开发的所有企业系统的方面。 为了在我们的系统中实现灵活的报告,我们开发了自己的开源报告生成器-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 shop

select 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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值