【发布时间】: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