【问题标题】:JasperReport - Concatenating multiple report in the same page prints a white pageJasperReport - 在同一页面中连接多个报告会打印一个白页
【发布时间】:2021-10-21 18:48:35
【问题描述】:

自从我尝试使用 Jasper 以编程方式构建具有相同报告的多个表以来,这一直很糟糕,因此我决定再次使用 DynamicJasper 库。 (尽管有时发现它不太清楚,但通常非常方便)。

无论如何,我认为我需要的是在同一个报告(或页面)中连接多个表格报告。

我使用的主要“数据源”是一个列表列表,每个列表都是一个不同的“表格”来填充。这些标头也发生了类似的机制。 (稍后我会在下面展示所有内容)

据我从 DynamicJasper 中看到,它以一种相当简单和直接的方式通过声明某种 DynamicReportBuilder 以及有关报告的一些一般信息(标题、宽度、样式、ecc..),然后是addConcatenatedReport 应该可以满足我的需求。

还写到每个子报表都必须由一个“字符串”标识,该字符串将成为数据源(也就是填充数据)的钩子,该数据源必须最近在参数映射中指定。

到目前为止一切正常,但打印整个结果总是在白页中!

见:http://dynamicjasper.com/2010/10/08/how-to-add-concatenated-subreports/

我将从现在开始发布我是如何解决这个问题的,以上面的例子作为指导。

从最后一件事开始:

this.dynamicReport = new Generator().withTitle(this.title).withHeaders(this.headerData).prepare();
    Map generatedParams = this.buildParams();
    this.jasperReport = DynamicJasperHelper.generateJasperReport(this.dynamicReport, new ClassicLayoutManager(), generatedParams);
    this.jasperPrint = JasperFillManager.fillReport(this.jasperReport, generatedParams);

我创建了Generator 类,它只负责生成报告结构(以及连接的报告)。

Generator 中有两个主要功能:

public DynamicReport prepare() throws Exception {
    Style rowStyle = new Style();
    rowStyle.setBorder(Border.NO_BORDER());
    rowStyle.setBackgroundColor(Color.LIGHT_GRAY);
    rowStyle.setTransparency(ar.com.fdvs.dj.domain.constants.Transparency.OPAQUE);

    DynamicReportBuilder reportBuilder = new DynamicReportBuilder()
            .setTitleStyle(new Style())
            .setTitle(this.title)
            .setDetailHeight(15)
            .setLeftMargin(20)
            .setRightMargin(20)
            .setTopMargin(20)
            .setBottomMargin(20)
            .setPrintBackgroundOnOddRows(true)
            .setOddRowBackgroundStyle(rowStyle);

    for (HeaderData headerData : headerData) {
        reportBuilder.addConcatenatedReport(
                this.createSubreportForEntry(headerData),
                new ClassicLayoutManager(),
                headerData.getDataSourceName(), // <-------- see?
                DJConstants.DATA_SOURCE_ORIGIN_PARAMETER,
                DJConstants.DATA_SOURCE_TYPE_COLLECTION,
                false
        );
    }

    reportBuilder.setUseFullPageWidth(true);

    return reportBuilder.build();
}


private DynamicReport createSubreportForEntry(HeaderData headerData) throws Exception {
    FastReportBuilder reportBuilder = new FastReportBuilder();

    for (HeaderColumn headerColumn : headerData.getHeaderColumns()) {
        reportBuilder.addColumn(headerColumn.getColumnName(), headerColumn.getColumnCode(), String.class.getName(), headerColumn.getWidth());
    }

    return reportBuilder
            .setTitle(headerData.getBoxName())
            .setMargins(5, 5, 20, 20)
            .setUseFullPageWidth(true)
            .build();
}

正如我所说,这些是为应该打印的内容提供形状,我什至突出显示了数据源,以便您知道它在哪里。 (我猜应该没问题)

现在,HeaderData 是什么?

public class HeaderData {
    private String boxName;
    private String dataSourceName;
    private List<HeaderColumn> headerColumns;
}

public class HeaderColumn {
    private String columnCode; // Hook for the datasource
    private String columnName; // what should be shown to the user
    private int width;
    private int height;
    private Style style;
    private Style headerStyle;
}

我必须为标题创建一个动态结构,因为每个表都有不同的列!

最后,生成这些参数的函数(包含那些填充集合):

private Map buildParams() {
    Map params = new HashMap<>();
    this.reportRows.forEach(tuple2 -> {
        if (tuple2._1 != null && tuple2._2 != null) {
            params.put(tuple2._1.toString(), tuple2._2);
        }
    });
    return params;
}

这是结果:

[
  key: DataSourceName1, value: List[Class1(prop1=1, prop2=2), Class1(...), Class1(...), ...],
  key: DataSourceName2, value: List[Class2(...), Class2(...), Class2(...), ...],
  key: DataSourceName3, value: List[Class3(...), Class3(...), Class3(...), ...],
]

如您所见,每个“值”都是不同类对象的列表。这是因为(再次)我没有为每个表设置相同的标题!

我猜每个“属性”(prop1,prop2,ecc..)都与“columnCode”链接在一起(如上所示,在createSubreportForEntry中)

Ofc,这些类中的属性反映了HeaderColumn.columnCode

啊!在-最后-我还想发布我是如何打印的:

    JRPdfExporter exporter = new JRPdfExporter();

    File outputFile = new File(path);
    File parentFile = new File(path).getParentFile();

    if (parentFile != null) {
        parentFile.mkdirs();
    }

    FileOutputStream fos = new FileOutputStream(outputFile);

    SimpleExporterInput simpleExporterInput = new SimpleExporterInput(jasperPrint);
    OutputStreamExporterOutput simpleOutputStreamExporterOutput = new SimpleOutputStreamExporterOutput(fos);

    exporter.setExporterInput(simpleExporterInput);
    exporter.setExporterOutput(simpleOutputStreamExporterOutput);

    exporter.exportReport();

我不确定使用纯 JasperReport 库是否有更好的方法,或者我是否可以使用混合方法,例如:DynamicJasper 用于生成报告结构(上面著名的Generator 类),纯 JasperReport填充它。

注意:正如我在开头所说,“程序化”一词意味着使用 JRXML 超出了范围(是的,也许会更容易)

编辑:

通过调试net.sf.jasperreports.engine.fill.JRVerticalFiller#fillReport,我看到它进入了“无数据”的“if”分支,所以我猜使用映射来传递集合不是正确的方式(?)

我使用的jasper版本:6.11.0

【问题讨论】:

    标签: java jasper-reports dynamic-jasper


    【解决方案1】:

    似乎以前几乎没有人尝试过使用这个库,所以我最近遇到了 Apache 的 PDFBox,它以更简单的方式完成了这项工作(对于那些不知道这个库的人 -> https://pdfbox.apache.org/index.html)。

    我进一步发现 -> https://github.com/vandeseer/easytable 以更简单的方式创建更漂亮的表格(也有很好的文档记录!)。

    我向任何正在寻找通过代码在 PDF 中生成表格的动态方法的人推荐这两个。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多