My first days at AMIS I examined JasperReports (v. 0.6.3), an open source report-generating library. This tool is entirely written in Java and uses XML report templates to generate reports you can display on the screen, send to a printer, or save as a PDF document.
In order to fill a report with data, the report design (template) must be compiled first.
This compilation is performed by the compileReport() method exposed by the net.sf.jasperreports.engine.JasperCompileManager class.
Through compilation, the report design is loaded into a report design object that is then serialized and stored on disk (net.sf.jasperreports.engine.JasperReport). This serialized object is then used when the application wants to fill the specified report design with data. In fact, the compilation of a report design implies the compilation of all Java expressions defined in the XML file representing the report design. Various verifications are made at compilation time, to check the report design consistency. The result is a ready to fill report design that will be then used to generate documents on different sets of data.
In order to fill a report design, one can use the fillReport() method exposed by the net.sf.jasperreports.engine.JasperFillManager class. This method takes as parameters:
- the report design object, or a file representing the specified report design object, in a serialized form
- a map of reportparameters
- a JDBC connection to the database from where to retrieve the data to fill the report
The result is an object that represents the ready to print document (net.sf.jasperreports.engine.JasperPrint) and can be stored onto the disk, in a serialized form, for later use, or can be delivered to the printer, to the screen or can be transformed into a PDF, HTML, XLS, CSV or XML document.
I’ve only tried the PDF transformation. The following code illustrates this:
package nl.amis.jasper.test; import java.sql.Connection; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; import net.sf.jasperreports.engine.JRException; import net.sf.jasperreports.engine.xml.JRXmlLoader; import net.sf.jasperreports.engine.JasperCompileManager; import net.sf.jasperreports.engine.JasperFillManager; import net.sf.jasperreports.engine.JasperExportManager; import net.sf.jasperreports.engine.JasperPrint; import net.sf.jasperreports.engine.JasperReport; import net.sf.jasperreports.engine.design.JasperDesign; import net.sf.jasperreports.view.JasperViewer; import nl.amis.database.Database; public class EmpDeptReport { public static void main(String[] args) { // First, load JasperDesign from XML and compile it into JasperReport try { JasperDesign jasperDesign = JRXmlLoader.load("EmpDeptReport.xml"); JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign); // Second, create a map of parameters to pass to the report. Map parameters = new HashMap(); parameters.put("Title", "EmpDept JasperReport"); // Third, get a database connection Connection conn = Database.getConnection(); // Fourth, create JasperPrint using fillReport() method JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, conn); // You can use JasperPrint to create PDF JasperExportManager.exportReportToPdfFile(jasperPrint, "EmpDeptReport.pdf"); // Or to view report in the JasperViewer JasperViewer.viewReport(jasperPrint); } catch (JRException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
To create a XML report template I’ve used OpenReports Designer (v. 1.10).
This is a tool that combines a visual report designer, an XML report definition editor, and report viewer into one interface to provide a complete integrated report development environment.
The XML file EmpDeptReport.xml – which can be downloaded below – is a template for a report which retrieves data from Oracle’s Emp and Dept tables.
In the following I’ll explain the structure of this template. This structure is declared in a DTD file supplied with the JasperReports engine.
Every JasperReports XML template starts with with the following structure:
< ?xml version="1.0" encoding="UTF-8"?> < !DOCTYPE jasperReport PUBLIC "-//JasperReports//DTD Report Design//EN" "http://jasperreports.sourceforge.net/dtds/jasperreport.dtd"> < jasperReport name="EmpDeptReport" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="30" bottomMargin="30"> < /jasperReport>
Parameters are object references that are passed-in to the report filling operations (see EmpDeptReport class above).
Declaring a parameter in a report design is very simple and it requires specifying only its name and its class:
< parameter name=”Title” class=”java.lang.String”>
< /parameter>
When using a JDBC data source, one could pass a Connection object to the report filling operations (see also EmpDeptReport class) and specify the query in the report definition itself:
< queryString> < ![CDATA[select e.empno , e.ename , e.job , e.mgr , to_char(e.hiredate, 'dd-mm-yyyy') hiredate , e.sal , e.comm , e.deptno , d.dname , d.loc from emp e , dept d where e.deptno = d.deptno order by e.deptno]]> < /queryString>
Report fields represent the only way to map data from the data source into the report generating routines.
We can define the following field in our report design:
< field name="ENAME" class="java.lang.String"> < /field>
Expressions are a powerful feature of JasperReports. They can be used for declaring report variables that perform various calculations, for data grouping on the report, to specify report text fields content or to further customize the appearance of objects on the report.
Basically, all report expressions are Java expressions that can reference report fields and report variables.
In an XML report design there are several elements that define expressions: < variableExpression> , < initialValueExpression> , < groupExpression> , < printWhenExpression> , < imageExpression> and < textFieldExpression> .
In order to use a report field reference in an expression, the name of the field must be put between $F{ and } character sequences.
A Report variable is a special objects build on top of an expression. Variables can be used to simplify the report design by declaring only once an expression that is heavily used throughout the report design or to perform various calculations on the corresponding expressions.
Variables can perform built-in types of calculations on their corresponding expression values like: count, sum, average, lowest, highest, variance, etc.
A variable that performs the sum of the SAL field per department should be declared like this:
< variable name="SalSumDept" class="java.math.BigDecimal" resetType="Group" resetGroup="DeptGroup" calculation="Sum"> < variableExpression> < ![CDATA[$F{SAL}]]> < /variableExpression> < /variable>
As you can see a group DeptGroup is introduced.
Groups represent a flexible way to organize data on a report. When filling a report, the JasperReports engine test all the defined group expressions to see whether a group rupture has occurred and if so it introduces the corresponding < groupFooter> and < groupHeader> sections on the report:
< group name="DeptGroup"> < groupExpression> < ![CDATA[$F{DEPTNO}]]> < /groupExpression> < groupHeader> < /groupHeader> < groupFooter> < /groupFooter> < /group>
By the the way, I didn’t succeed in creating groupHeaders and groupFooters with OpenReports Designer (v. 1.10), so I did some copy-paste from another template.
The template’s remainder divides into six report sections:
- title
- pageHeader
- columnHeader
- detail
- columnFooter
- pageFooter
- summary
Each report section, called a band, is given a height. Each band can include multiple staticText and textField elements, which are given a position, size, and value. Report parameters, fields, and variables are referenced using P${name}, F${name}, and V${name}, respectively.
For example, the following lines in the page footer section create a staticText and a textField containing the current page number. The page number’s value is set to the variable PAGE_NUMBER, defined internally by JasperReports and available to all reports:
< pageFooter> < band height="15"> < staticText> < reportElement positionType="Float" x="0" y="0" width="40" height="15"/> < textElement/> < text> < ![CDATA[Page:]]> < /text> < /staticText> < textField> < reportElement positionType="Float" x="40" y="0" width="100" height="15"/> < textElement/> < textFieldExpression="java.lang.Integer"> < ![CDATA[$V{PAGE_NUMBER}]] > < /textFieldExpression> < /textField> < /band> < /pageFooter>
Resources:
‘Reports made easy with JasperReports’ by Erik Swenson:
http://www.javaworld.com/javaworld/jw-09-2002/jw-0920-opensourceprofile.html
Find the JasperReports homepage at:
http://jasperreports.sourceforge.net
OpenReports Project:
http://opensourcesoft.net
Report design tools for Eclipse:
http://sourceforge.net/projects/jeez (this plugin doesn’t seem to work with Eclipse 3.0.1)
Downloads:
EmpDeptReport.java
Database.java
EmpDeptReport.xml