JasperReports - programatically creating a report
last modified July 13, 2020
In this tutorial, we show how to programatically create a report with JasperReports.
We create a PDF report from a CARS table. We use Derby database
in our application.
A report is a document containing information organized in a narrative, graphic, or tabular form, prepared on ad hoc, periodic, recurring, regular, or as required basis. JasperReports is an open-source reporting library. It loads data from a data source and creates a report from it. The report is a file in a PDF, HTML, RTF, XLS, ODT, CSV, or XML format.
JasperReports uses a template to define a document structure. The template is defined either in an XML file or created with the programming API. In this tutorial we use the latter option.
-- SQL for the CARS table
CREATE TABLE CARS(ID BIGINT NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY
(START WITH 1, INCREMENT BY 1), NAME VARCHAR(30), PRICE INT);
INSERT INTO CARS(Name, Price) VALUES('Audi', 52642);
INSERT INTO CARS(Name, Price) VALUES('Mercedes', 57127);
INSERT INTO CARS(Name, Price) VALUES('Skoda', 9000);
INSERT INTO CARS(Name, Price) VALUES('Volvo', 29000);
INSERT INTO CARS(Name, Price) VALUES('Bentley', 350000);
INSERT INTO CARS(Name, Price) VALUES('Citroen', 21000);
INSERT INTO CARS(Name, Price) VALUES('Hummer', 41400);
INSERT INTO CARS(Name, Price) VALUES('Volkswagen', 21600);
In the code example, we use this table.
Creating testdb database in Derby
Derby can be managed using the command line tools or from the Services tab of the NetBeans IDE. You can find out more about Derby in Apache Derby tutorial.
$ export DERBY_HOME=$JAVA_HOME/db
We set the DERBY_HOME directory. Derby comes with JDK, so
we do not need to install it separately.
$ export DERBY_OPTS=-Dderby.system.home=/home/janbodnar/.derby
We set the derby system directory. The database and the derby log is created in this directory.
$ $DERBY_HOME/bin/ij
We start the ij system tool.
ij> CONNECT 'jdbc:derby:testdb;create=true';
Using the CONNECT command, we create the testdb
database.
ij> run 'cars.sql';
With the run command, we issue the SQL statements in the cars.sql
file.
ij> SELECT * FROM CARS; ID |NAME |PRICE --------------------------------------------------------------- 1 |Audi |52642 2 |Mercedes |57127 3 |Skoda |9000 4 |Volvo |29000 5 |Bentley |350000 6 |Citroen |21000 7 |Hummer |41400 8 |Volkswagen |21600
This is the created CARS table.
ij> exit;
We exit the ij tool.
$ $DERBY_HOME/bin/startNetworkServer &
We start the Derby network server.
The application
The following application connects to the Derby server, loads
data from the CARS table and creates a PDF file
from the data with JasperReports.
$ tree
.
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── zetcode
│ │ └── main
│ │ ├── CommandLineRunner.java
│ │ ├── JasperProgrammatic.java
│ │ └── ReportBuilder.java
│ └── resources
└── test
└── java
This is the project structure.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zetcode</groupId>
<artifactId>JasperProgrammatic3</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>6.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbyclient</artifactId>
<version>10.13.1.1</version>
</dependency>
</dependencies>
</project>
In the Maven pom.xml file, we have the jasperreports and
derbyclient dependencies.
package com.zetcode.main;
public class CommandLineRunner {
public static void main(String[] args) throws Exception {
JasperProgrammatic app = new JasperProgrammatic();
app.start();
}
}
The CommandLineRunner sets up the application and
calls its start method.
package com.zetcode.main;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.design.JRDesignBand;
import net.sf.jasperreports.engine.design.JRDesignExpression;
import net.sf.jasperreports.engine.design.JRDesignField;
import net.sf.jasperreports.engine.design.JRDesignParameter;
import net.sf.jasperreports.engine.design.JRDesignQuery;
import net.sf.jasperreports.engine.design.JRDesignSection;
import net.sf.jasperreports.engine.design.JRDesignStaticText;
import net.sf.jasperreports.engine.design.JRDesignStyle;
import net.sf.jasperreports.engine.design.JRDesignTextField;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.type.HorizontalTextAlignEnum;
public class ReportBuilder {
public JasperDesign build() throws JRException {
JasperDesign jasDes = new JasperDesign();
jasDes.setName("myreport");
jasDes.setPageWidth(595);
jasDes.setPageHeight(842);
jasDes.setLeftMargin(20);
jasDes.setRightMargin(20);
jasDes.setTopMargin(20);
jasDes.setBottomMargin(20);
jasDes.setColumnWidth(555);
// Style
JRDesignStyle mystyle = new JRDesignStyle();
mystyle.setName("mystyle");
mystyle.setDefault(true);
mystyle.setFontName("DejaVu Sans");
mystyle.setFontSize(22f);
mystyle.setPdfFontName("Helvetica");
mystyle.setPdfEncoding("UTF-8");
jasDes.addStyle(mystyle);
// Fields
JRDesignField field1 = new JRDesignField();
field1.setName("id");
field1.setValueClass(String.class);
jasDes.addField(field1);
JRDesignField field2 = new JRDesignField();
field2.setName("name");
field2.setValueClass(String.class);
jasDes.addField(field2);
JRDesignField field3 = new JRDesignField();
field3.setName("price");
field3.setValueClass(String.class);
jasDes.addField(field3);
// Parameter
JRDesignParameter par = new JRDesignParameter();
par.setName("CarPrice");
par.setValueClass(Integer.class);
jasDes.addParameter(par);
// Query
JRDesignQuery query = new JRDesignQuery();
query.setText("SELECT * FROM Cars WHERE Price > $P{CarPrice}");
jasDes.setQuery(query);
// Title
JRDesignBand titleBand = new JRDesignBand();
titleBand.setHeight(50);
JRDesignStaticText titleText = new JRDesignStaticText();
titleText.setText("Expensive cars");
titleText.setX(0);
titleText.setY(10);
titleText.setWidth(515);
titleText.setHeight(30);
titleText.setHorizontalTextAlign(HorizontalTextAlignEnum.CENTER);
titleText.setFontSize(22f);
titleBand.addElement(titleText);
jasDes.setTitle(titleBand);
// Detail
JRDesignBand detailBand = new JRDesignBand();
detailBand.setHeight(60);
JRDesignTextField tf1 = new JRDesignTextField();
tf1.setBlankWhenNull(true);
tf1.setX(0);
tf1.setY(10);
tf1.setWidth(60);
tf1.setHeight(30);
tf1.setHorizontalTextAlign(HorizontalTextAlignEnum.CENTER);
tf1.setStyle(mystyle);
tf1.setExpression(new JRDesignExpression("$F{id}"));
detailBand.addElement(tf1);
JRDesignTextField tf2 = new JRDesignTextField();
tf2.setBlankWhenNull(true);
tf2.setX(80);
tf2.setY(10);
tf2.setWidth(120);
tf2.setHeight(30);
tf2.setHorizontalTextAlign(HorizontalTextAlignEnum.LEFT);
tf2.setStyle(mystyle);
tf2.setExpression(new JRDesignExpression("$F{name}"));
detailBand.addElement(tf2);
JRDesignTextField tf3 = new JRDesignTextField();
tf3.setBlankWhenNull(true);
tf3.setX(200);
tf3.setY(10);
tf3.setWidth(100);
tf3.setHeight(30);
tf3.setHorizontalTextAlign(HorizontalTextAlignEnum.RIGHT);
tf3.setStyle(mystyle);
tf3.setExpression(new JRDesignExpression("$F{price}"));
detailBand.addElement(tf3);
((JRDesignSection) jasDes.getDetailSection()).addBand(detailBand);
return jasDes;
}
}
In the ReportBuilder class we programatically create a Jasper report.
JasperDesign jasDes = new JasperDesign();
jasDes.setName("myreport");
jasDes.setPageWidth(595);
jasDes.setPageHeight(842);
jasDes.setLeftMargin(20);
jasDes.setRightMargin(20);
jasDes.setTopMargin(20);
jasDes.setBottomMargin(20);
jasDes.setColumnWidth(555);
JasperDesign is instrumental in creating the report with the
programming API. With its setter methods, we define the report name and its
basic settings.
// Style
JRDesignStyle mystyle = new JRDesignStyle();
mystyle.setName("mystyle");
mystyle.setDefault(true);
mystyle.setFontName("DejaVu Sans");
mystyle.setFontSize(22f);
mystyle.setPdfFontName("Helvetica");
mystyle.setPdfEncoding("UTF-8");
jasDes.addStyle(mystyle);
JRDesignStyle is used to define a custom style. Using a style
avoids code repetition.
// Fields
JRDesignField field1 = new JRDesignField();
field1.setName("id");
field1.setValueClass(String.class);
jasDes.addField(field1);
JRDesignField field2 = new JRDesignField();
field2.setName("name");
field2.setValueClass(String.class);
jasDes.addField(field2);
JRDesignField field3 = new JRDesignField();
field3.setName("price");
field3.setValueClass(String.class);
jasDes.addField(field3);
We have three fields that correspond to the three columns of the
CARS table. Report fields are elements, which represent
mapping of data between datasource and report template.
// Parameter
JRDesignParameter par = new JRDesignParameter();
par.setName("CarPrice");
par.setValueClass(Integer.class);
jasDes.addParameter(par);
JRDesignParameter defines a dynamic parameter passed to
the report-filling operation of the report engine.
// Query
JRDesignQuery query = new JRDesignQuery();
query.setText("SELECT * FROM Cars WHERE Price > $P{CarPrice}");
jasDes.setQuery(query);
JRDesignQuery defines the SQL query to fetch the data
from the database. The $P{CarPrice} placeholder is filled
with the value of the parameter that is passed to the report engine.
// Title
JRDesignBand titleBand = new JRDesignBand();
titleBand.setHeight(50);
JRDesignStaticText titleText = new JRDesignStaticText();
titleText.setText("Expensive cars");
titleText.setX(0);
titleText.setY(10);
titleText.setWidth(515);
titleText.setHeight(30);
titleText.setHorizontalTextAlign(HorizontalTextAlignEnum.CENTER);
titleText.setFontSize(22f);
titleBand.addElement(titleText);
jasDes.setTitle(titleBand);
Here we create a report title. A title is an instance of the JRDesignStaticText.
A report template consists of several parts, including title, column header, detail,
and summary. Each part is placed into a horizontal section called band.
// Detail
JRDesignBand detailBand = new JRDesignBand();
detailBand.setHeight(60);
JRDesignTextField tf1 = new JRDesignTextField();
tf1.setBlankWhenNull(true);
tf1.setX(0);
tf1.setY(10);
tf1.setWidth(60);
tf1.setHeight(30);
tf1.setHorizontalTextAlign(HorizontalTextAlignEnum.CENTER);
tf1.setStyle(mystyle);
tf1.setExpression(new JRDesignExpression("$F{id}"));
detailBand.addElement(tf1);
...
Detail is a band where report data is placed. Each row in a table is
represented by one line in the detail band. The detail band consists
of three JRDesignTextFields, which produce dynamic data
from the given expressions. The $F{id} expression gives
the ID of the current table row.
package com.zetcode.main;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.design.JasperDesign;
public class JasperProgrammatic {
private Connection con;
public void start() throws JRException, SQLException {
try {
String url = "jdbc:derby://localhost:1527/testdb";
String user = "app";
String password = "app";
DriverManager.registerDriver(new org.apache.derby.jdbc.ClientDriver());
con = DriverManager.getConnection(url, user, password);
JasperDesign jdes = new ReportBuilder().build();
JasperReport report = JasperCompileManager.compileReport(jdes);
HashMap params = new HashMap();
params.put("CarPrice", 30000);
JasperPrint jprint = JasperFillManager.fillReport(report, params, con);
JasperExportManager.exportReportToPdfFile(jprint,
"src/main/resources/expensivecars.pdf");
} catch (SQLException ex) {
Logger.getLogger(JasperProgrammatic.class.getName()).log(Level.SEVERE, null, ex);
} finally {
if (con != null) {
con.close();
}
}
}
}
In the JasperProgrammatic class, we build, compile, and export the report.
JasperDesign jdes = new ReportBuilder().build();
Using the ReportBuilder class to create a JasperDesign,
which is a report template created by programming API.
JasperReport report = JasperCompileManager.compileReport(jdes);
With the JasperCompileManager, we compile the template into
an intermediary JasperReport object.
HashMap params = new HashMap();
params.put("CarPrice", 30000);
Our map of parameters contains one parameter: the CarPrice, which is used to filter the data. Only expensive cars are shown in the report.
JasperPrint jprint = JasperFillManager.fillReport(report, params, con);
The next step is to fill the compiled JasperReport object
with data. The operation results in a JasperPrint object,
which can be viewed, printed, or exported to other formats.
JasperExportManager.exportReportToPdfFile(jprint,
"src/main/resources/expensivecars.pdf");
We use the JasperExportManager to export
the JasperPrint object into a PDF file. The generated
PDF file is written into the src/main/resources/ directory.
In this tutorial, we have created a PDF file report with the programming API of the JasperReports library.