Spring Boot cmd JasperReports integration
last modified July 13, 2020
In this tutorial, we show how to use JasperReports with Spring Boot framework. The Spring Boot is run in the command line.
JasperReports is a Java open-source reporting library. It can create reports in various formats including PDF, HTML, XLS, or CSV. JasperReports creates page-oriented, ready-to-print documents in a simple and flexible manner.
JdbcTemplate is a Spring library that helps programmers create
applications that work with relational databases and JDBC. It takes care of many
tedious and error-prone low-level details such as handling transactions,
cleaning up resources, and correctly handling exceptions.
JdbcTemplate is shipped in Spring's spring-jdbc
module.
Spring is a popular Java application framework for developing Java enterprise applications. It also helps integrate various enterprise components. Spring Boot makes it easy to create Spring-powered, production-grade applications and services with minimum setup requirements.
Apache Derby is an open source relational database implemented entirely in Java. It has small footprint and is easy to deploy and install. It can be run in embedded and client/server modes.
The CARS table
In our applications, we use the following table:
-- 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);
The cars.sql
file creates the CARS
table.
$ $DERBY_HOME/bin/ij ij version 10.11 ij> CONNECT 'jdbc:derby:testdb'; ij> RUN 'cars.sql';
One option is to use the ij
tool to create the table from the SQL script.
Refer to Apache Derby tutorial to familiarize yourself
with Derby.
$ $DERBY_HOME/bin/NetworkServerControl start &
Derby server is started with NetworkServerControl
tool.
Application
The following Spring Boot application loads data from a database table and produces a PDF report from it with JasperReports library.
$ tree . ├── pom.xml └── src ├── main │ ├── java │ │ └── com │ │ └── zetcode │ │ ├── Application.java │ │ ├── bean │ │ │ └── Car.java │ │ ├── conf │ │ │ └── AppConfig.java │ │ ├── MyRunner.java │ │ ├── report │ │ │ └── ReportGenerator.java │ │ └── service │ │ ├── CarService.java │ │ └── ICarService.java │ └── resources │ ├── application.yml │ └── report2.xml └── 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>JasperSpringBootCmd</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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.2.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.apache.derby</groupId> <artifactId>derbyclient</artifactId> <version>10.13.1.1</version> </dependency> <dependency> <groupId>net.sf.jasperreports</groupId> <artifactId>jasperreports</artifactId> <version>6.4.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <name>JasperSpringBootCmd</name> </project>
The Maven pom.xml
file contains these dependencies:
derbyclient
, jasperreports
, and spring-boot-starter-jdbc
.
The jasperreports
dependency is the JasperReports library;
the spring-boot-starter-jdbc
contains the JdbcTemplate library.
<?xml version = "1.0" encoding = "UTF-8"?> <!DOCTYPE jasperReport PUBLIC "//JasperReports//DTD Report Design//EN" "http://jasperreports.sourceforge.net/dtds/jasperreport.dtd"> <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="report2" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20"> <field name="Id" class="java.lang.Long"> <fieldDescription><![CDATA[id]]></fieldDescription> </field> <field name="Name" class="java.lang.String"> <fieldDescription><![CDATA[name]]></fieldDescription> </field> <field name="Price" class="java.lang.Integer"> <fieldDescription><![CDATA[price]]></fieldDescription> </field> <detail> <band height="15"> <textField> <reportElement x="0" y="0" width="50" height="15" /> <textElement textAlignment="Right" verticalAlignment="Middle"/> <textFieldExpression class="java.lang.Long"> <![CDATA[$F{Id}]]> </textFieldExpression> </textField> <textField> <reportElement x="150" y="0" width="100" height="15" /> <textElement textAlignment="Left" verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"> <![CDATA[$F{Name}]]> </textFieldExpression> </textField> <textField> <reportElement x="200" y="0" width="100" height="15"/> <textElement textAlignment="Right" verticalAlignment="Middle"/> <textFieldExpression class="java.lang.Integer"> <![CDATA[$F{Price}]]> </textFieldExpression> </textField> </band> </detail> </jasperReport>
This is the report template file. The template contains only the detail band. Inside a detail band, each element is repeated for every record provided by the data source.
<field name="Id" class="java.lang.Long"> <fieldDescription><![CDATA[id]]></fieldDescription> </field> <field name="Name" class="java.lang.String"> <fieldDescription><![CDATA[name]]></fieldDescription> </field> <field name="Price" class="java.lang.Integer"> <fieldDescription><![CDATA[price]]></fieldDescription> </field>
We have three fields in the report. The fields are mapped to the elements of the data source beans.
<textField> <reportElement x="0" y="0" width="50" height="15" /> <textElement textAlignment="Right" verticalAlignment="Middle"/> <textFieldExpression class="java.lang.Long"> <![CDATA[$F{Id}]]> </textFieldExpression> </textField>
A text field is an element that is filled with dynamic data.
We place a value from a field inside the text field. We refer to the
variable with the $F{}
syntax.
package com.zetcode.bean; public class Car { private Long id; private String name; private int price; public Car() {} public Car(Long id, String name, int price) { this.id = id; this.name = name; this.price = price; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } @Override public String toString() { return "Car{" + "id=" + id + ", name=" + name + ", price=" + price + '}'; } }
This is Car
bean class. It contains item ID, name, and price.
datasource: url: jdbc:derby://localhost:1527/testdb username: app password: app driverClassName: org.apache.derby.jdbc.ClientDriver
The application.yml
is the main Spring Boot configuration
file. It contains the Derby datasource settings.
package com.zetcode.conf; import javax.sql.DataSource; import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; @Configuration public class AppConfig { @Bean @Primary @ConfigurationProperties(prefix = "datasource") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } }
The AppConfig
is a Java configuration class. It creates
the data source bean from the configuration file.
package com.zetcode.report; import com.zetcode.bean.Car; import java.util.HashMap; import java.util.List; 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.data.JRBeanCollectionDataSource; public class ReportGenerator { public void generatePdfReport(List<Car> cars) throws JRException { String report = "src/main/resources/report2.xml"; JasperReport jreport = JasperCompileManager.compileReport(report); JRBeanCollectionDataSource ds = new JRBeanCollectionDataSource(cars); HashMap params = new HashMap(); JasperPrint jprint = JasperFillManager.fillReport(jreport, params, ds); JasperExportManager.exportReportToPdfFile(jprint, "src/main/resources/report2.pdf"); } }
The ReportGenerator
creates a PDF report from the supplied data.
JasperReport jreport = JasperCompileManager.compileReport(report);
With the JasperCompileManager.compileReport
method we compile the
XML report template into the intermediary JasperReport
.
JRBeanCollectionDataSource ds = new JRBeanCollectionDataSource(cars);
From the supplied list of car objects, we create a JRBeanCollectionDataSource
.
The attributes of the beans are going to be mapped to the fields of the compiled report object.
JasperPrint jprint = JasperFillManager.fillReport(jreport, params, ds);
The compiled Jasper object is filled with data with the JasperFillManager.fillReport
method. A JasperPrint
object is produced.
JasperExportManager.exportReportToPdfFile(jprint, "src/main/resources/report2.pdf");
The JasperExportManager.exportReportToPdfFile
method transforms
the JasperPrint
object into a PDF file.
package com.zetcode.service; import com.zetcode.bean.Car; import java.util.List; public interface ICarService { public List<Car> findAll(); }
ICarService
provides a contract method to
get all cars from the data source.
package com.zetcode.service; import com.zetcode.bean.Car; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; @Service public class CarService implements ICarService { @Autowired private JdbcTemplate jtm; @Override public List<Car> findAll() { String sql = "SELECT * FROM Cars"; List<Car> cars = jtm.query(sql, new BeanPropertyRowMapper(Car.class)); return cars; } }
CarService
contains the implementation of the
findAll
method. We retrieve all cars from the CARS
table with the help of the JdbcTemplate
.
package com.zetcode; import com.zetcode.bean.Car; import com.zetcode.report.ReportGenerator; import com.zetcode.service.ICarService; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; @Component public class MyRunner implements CommandLineRunner { private static final Logger LOG = Logger.getLogger(MyRunner.class.getName()); @Autowired private ICarService carService; @Override public void run(String... args) throws Exception { List<Car> cars = carService.findAll(); ReportGenerator rg = new ReportGenerator(); rg.generatePdfReport(cars); LOG.log(Level.INFO, "Generating PDF report"); } }
MyRunner
is a command line runner for the Spring Boot application.
@Autowired private ICarService carService;
We inject the service object.
List<Car> cars = carService.findAll();
We fetch all the cars using the service object.
ReportGenerator rg = new ReportGenerator(); rg.generatePdfReport(cars);
ReportGenerator
is used to create the PDF report.
The report contains the retrieved cars.
package com.zetcode; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
The Application
sets up the Spring Boot application.
In this tutorial, we have created a PDF report with JasperReports. The application used Spring Boot framework and was run in the command line.