1. Overview
1.概述
JasperReports is an open source reporting library that enables users to create pixel-perfect reports that can be printed or exported in many formats including PDF, HTML, and XLS.
JasperReports是一个开源的报告库,使用户能够创建像素完美的报告,可以打印或以多种格式导出,包括PDF、HTML和XLS。
In this article, we’ll explore its key features and classes, and implement examples to showcase its capabilities.
在这篇文章中,我们将探讨它的主要特征和类,并实施例子来展示它的能力。
2. Maven Dependency
2.Maven的依赖性
First, we need to add the jasperreports dependency to our pom.xml:
首先,我们需要将jasperreports依赖性添加到我们的pom.xml。
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>6.4.0</version>
</dependency>
The latest version of this artifact can be found here.
该工件的最新版本可以在这里找到。
3. Report Templates
3.报告模板
Report designs are defined in JRXML files. These are ordinary XML files with a particular structure that JasperReports engine can interpret.
报告设计是在JRXML文件中定义的。这些是普通的XML文件,具有JasperReports引擎可以解释的特定结构。
Let’s now have a look at only the relevant structure of the JRXML files – to understand better the Java part of the report generation process, which is our primary focus.
现在让我们只看一下JRXML文件的相关结构–以更好地理解报告生成过程的Java部分,这是我们的主要焦点。
Let’s create a simple report to show employee information:
让我们创建一个简单的报告来显示雇员信息。
<jasperReport ... >
<field name="FIRST_NAME" class="java.lang.String"/>
<field name="LAST_NAME" class="java.lang.String"/>
<field name="SALARY" class="java.lang.Double"/>
<field name="ID" class="java.lang.Integer"/>
<detail>
<band height="51" splitType="Stretch">
<textField>
<reportElement x="0" y="0" width="100" height="20"/>
<textElement/>
<textFieldExpression class="java.lang.String">
<![CDATA[$F{FIRST_NAME}]]></textFieldExpression>
</textField>
<textField>
<reportElement x="100" y="0" width="100" height="20"/>
<textElement/>
<textFieldExpression class="java.lang.String">
<![CDATA[$F{LAST_NAME}]]></textFieldExpression>
</textField>
<textField>
<reportElement x="200" y="0" width="100" height="20"/>
<textElement/>
<textFieldExpression class="java.lang.String">
<![CDATA[$F{SALARY}]]></textFieldExpression>
</textField>
</band>
</detail>
</jasperReport>
3.1. Compiling Reports
3.1.编译报告
JRXML files need to be compiled so the report engine can fill them with data.
JRXML文件需要被编译,以便报告引擎能够用数据填充它们。
Let’s perform this operation with the help of the JasperCompilerManager class:
让我们在JasperCompilerManager类的帮助下执行这一操作。
InputStream employeeReportStream
= getClass().getResourceAsStream("/employeeReport.jrxml");
JasperReport jasperReport
= JasperCompileManager.compileReport(employeeReportStream);
To avoid compiling it every time, we can save it to a file:
为了避免每次都编译,我们可以把它保存到一个文件中。
JRSaver.saveObject(jasperReport, "employeeReport.jasper");
4. Populating Reports
4.填充报告
The most common way to fill compiled reports is with records from a database. This requires the report to contain a SQL query the engine will execute to obtain the data.
填充编译报告最常见的方式是使用数据库中的记录。这需要报告包含一个SQL查询,引擎将执行该查询以获得数据。
First, let’s modify our report to add a SQL query:
首先,让我们修改我们的报告,添加一个SQL查询。
<jasperReport ... >
<queryString>
<![CDATA[SELECT * FROM EMPLOYEE]]>
</queryString>
...
</jasperReport>
Now, let’s create a simple data source:
现在,让我们创建一个简单的数据源。
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:employee-schema.sql")
.build();
}
Now, we can fill the report:
现在,我们可以填写报告了。
JasperPrint jasperPrint = JasperFillManager.fillReport(
jasperReport, null, dataSource.getConnection());
Note that we are passing null to the second argument since our report doesn’t receive any parameters yet.
注意,我们将null传给第二个参数,因为我们的报告还没有收到任何参数。
4.1. Parameters
4.1.参数[/strong]
Parameters are useful for passing data to the report engine that it can not find in its data source or when data changes depending on different runtime conditions.
参数对于向报告引擎传递它在数据源中找不到的数据,或者当数据根据不同的运行时间条件发生变化时,参数是有用的。
We can also change portions or even the entire SQL query with parameters received in the report filling operation.
我们还可以用报告填充操作中收到的参数改变部分甚至整个SQL查询。
First, let’s modify the report to receive three parameters:
首先,让我们修改报告以接收三个参数。
<jasperReport ... >
<parameter name="title" class="java.lang.String" />
<parameter name="minSalary" class="java.lang.Double" />
<parameter name="condition" class="java.lang.String">
<defaultValueExpression>
<![CDATA["1 = 1"]]></defaultValueExpression>
</parameter>
// ...
</jasperreport>
Now, let’s add a title section to show the title parameter:
现在,让我们添加一个标题部分来显示title参数。
<jasperreport ... >
// ...
<title>
<band height="20" splitType="Stretch">
<textField>
<reportElement x="238" y="0" width="100" height="20"/>
<textElement/>
<textFieldExpression class="java.lang.String">
<![CDATA[$P{title}]]></textFieldExpression>
</textField>
</band>
</title>
...
</jasperreport/>
Next, let’s alter the query to use the minSalary and condition parameters:
接下来,让我们改变查询,使用minSalary和condition参数。
SELECT * FROM EMPLOYEE
WHERE SALARY >= $P{minSalary} AND $P!{condition}
Note the different syntax when using the condition parameter. This tells the engine that the parameter should not be used as a standard PreparedStatement parameter, but as if the value of that parameter would have been written originally in the SQL query.
注意使用condition参数时的不同语法。这告诉引擎,该参数不应作为标准的PreparedStatement参数使用,而是像该参数的值原本就写在SQL查询中一样。
Finally, let’s prepare the parameters and fill the report:
最后,让我们准备好参数并填写报告。
Map<String, Object> parameters = new HashMap<>();
parameters.put("title", "Employee Report");
parameters.put("minSalary", 15000.0);
parameters.put("condition", " LAST_NAME ='Smith' ORDER BY FIRST_NAME");
JasperPrint jasperPrint
= JasperFillManager.fillReport(..., parameters, ...);
Note that the keys of parameters correspond to parameter names in the report. If the engine detects a parameter is missing, it will obtain the value from defaultValueExpression of the parameter if any.
注意,parameters的键对应于报告中的参数名称。如果引擎检测到一个参数丢失,它将从参数的defaultValueExpression中获取值(如果有的话)。
5. Exporting
5.出口
To export a report, first, we instantiate an object of an exporter class that matches the file format we need.
要导出一份报告,首先,我们要实例化一个符合我们所需文件格式的导出器类的对象。
Then, we set our previous filled report as input and define where to output the resulting file.
然后,我们将之前填好的报告设置为输入,并定义输出结果文件的位置。
Optionally, we can set corresponding report and export configuration objects to customize the exporting process.
另外,我们可以设置相应的报告和导出配置对象来定制导出过程。
5.1. PDF
5.1.PDF
JRPdfExporter exporter = new JRPdfExporter();
exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
exporter.setExporterOutput(
new SimpleOutputStreamExporterOutput("employeeReport.pdf"));
SimplePdfReportConfiguration reportConfig
= new SimplePdfReportConfiguration();
reportConfig.setSizePageToContent(true);
reportConfig.setForceLineBreakPolicy(false);
SimplePdfExporterConfiguration exportConfig
= new SimplePdfExporterConfiguration();
exportConfig.setMetadataAuthor("baeldung");
exportConfig.setEncrypted(true);
exportConfig.setAllowedPermissionsHint("PRINTING");
exporter.setConfiguration(reportConfig);
exporter.setConfiguration(exportConfig);
exporter.exportReport();
5.2. XLS
5.2.XLS
JRXlsxExporter exporter = new JRXlsxExporter();
// Set input and output ...
SimpleXlsxReportConfiguration reportConfig
= new SimpleXlsxReportConfiguration();
reportConfig.setSheetNames(new String[] { "Employee Data" });
exporter.setConfiguration(reportConfig);
exporter.exportReport();
5.3. CSV
5.3.CSV[/strong]
JRCsvExporter exporter = new JRCsvExporter();
// Set input ...
exporter.setExporterOutput(
new SimpleWriterExporterOutput("employeeReport.csv"));
exporter.exportReport();
5.4. HTML
5.4.HTML
HtmlExporter exporter = new HtmlExporter();
// Set input ...
exporter.setExporterOutput(
new SimpleHtmlExporterOutput("employeeReport.html"));
exporter.exportReport();
6. Subreports
6.分报告
Subreports are nothing more than a standard report embedded in another report.
子报告只不过是嵌入另一个报告的标准报告。
First, let’s create a report to show the emails of an employee:
首先,让我们创建一个报告来显示一个雇员的电子邮件。
<jasperReport ... >
<parameter name="idEmployee" class="java.lang.Integer" />
<queryString>
<![CDATA[SELECT * FROM EMAIL WHERE ID_EMPLOYEE = $P{idEmployee}]]>
</queryString>
<field name="ADDRESS" class="java.lang.String"/>
<detail>
<band height="20" splitType="Stretch">
<textField>
<reportElement x="0" y="0" width="156" height="20"/>
<textElement/>
<textFieldExpression class="java.lang.String">
<![CDATA[$F{ADDRESS}]]></textFieldExpression>
</textField>
</band>
</detail>
</jasperReport>
Now, let’s modify our employee report to include the previous one:
现在,让我们修改我们的雇员报告,以包括之前的报告。
<detail>
<band ... >
<subreport>
<reportElement x="0" y="20" width="300" height="27"/>
<subreportParameter name="idEmployee">
<subreportParameterExpression>
<![CDATA[$F{ID}]]></subreportParameterExpression>
</subreportParameter>
<connectionExpression>
<![CDATA[$P{REPORT_CONNECTION}]]></connectionExpression>
<subreportExpression class="java.lang.String">
<![CDATA["employeeEmailReport.jasper"]]></subreportExpression>
</subreport>
</band>
</detail>
Note that we are referencing the subreport by the name of the compiled file and passing it the idEmployee and current report connection as parameters.
注意,我们是通过编译文件的名称来引用子报告,并将idEmployee和当前报告连接作为参数传递给它。
Next, let’s compile both reports:
接下来,让我们来编译这两份报告。
InputStream employeeReportStream
= getClass().getResourceAsStream("/employeeReport.jrxml");
JasperReport jasperReport
= JasperCompileManager.compileReport(employeeReportStream);
JRSaver.saveObject(jasperReport, "employeeReport.jasper");
InputStream emailReportStream
= getClass().getResourceAsStream("/employeeEmailReport.jrxml");
JRSaver.saveObject(
JasperCompileManager.compileReport(emailReportStream),
"employeeEmailReport.jasper");
Our code for filling and exporting the report doesn’t require modifications.
我们填写和导出报告的代码不需要修改。
7. Conclusion
7.结论
In this article, we had a brief look at the core features of the JasperReports library.
在这篇文章中,我们简单看了一下JasperReports库的核心功能。
We were able to compile and populate reports with records from a database; we passed parameters to change the data shown in the report according to different runtime conditions, embedded subreports and exported them to the most common formats.
我们能够用数据库中的记录来编译和填充报告;我们通过参数来根据不同的运行条件改变报告中显示的数据,嵌入子报告并将它们导出为最常见的格式。
Complete source code for this article can be found over on GitHub.
本文的完整源代码可以在GitHub上找到over。