last modified July 13, 2020
In this tutorial, we show how to use JasperReports with Spring Boot framework. We createa web application.
JasperReports is a Java open source reporting library. It can create reports invarious 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 createapplications that work with relational databases and JDBC. It takes care of manytedious 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 Java application framework for developing Javaenterprise applications. It also helps integrate various enterprise components.Spring Boot makes it easy to create Spring-powered, production-grade applicationsand 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 inembedded and client/server modes.
The CARS table
We use the following table:
cars.sql
-- SQL for the CARS tableCREATE 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/ijij version 10.11ij> 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 yourselfwith Derby.
$ $DERBY_HOME/bin/NetworkServerControl start &
Derby server is started with NetworkServerControl
tool.
Application
The following Spring Boot application loads data from a database tableand produces a PDF report from it with JasperReports library. The applicationruns with embedded Tomcat server.
$ tree.├── pom.xml└── src ├── main │ ├── java │ │ └── com │ │ └── zetcode │ │ ├── Application.java │ │ ├── bean │ │ │ └── Car.java │ │ ├── conf │ │ │ ├── AppConfig.java │ │ │ └── MvcConf.java │ │ ├── controller │ │ │ └── MyController.java │ │ └── service │ │ ├── CarService.java │ │ └── ICarService.java │ └── resources │ ├── application.yml │ ├── report2.jrxml │ └── static │ └── index.html └── test └── java
This is the project structure.
pom.xml
<?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>JasperSpringBootWeb</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</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</groupId> <artifactId>spring-context-support</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </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></project>
The Maven pom.xml
file contains dependencies for JasperReports library,Derby driver, and Spring Boot.
report2.xml
<?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. It is located in the src/main/resources
directory.The template contains only the detail band. Inside a detail band, each element is repeated forevery 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 ofthe 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 thevariable with the $F{}
syntax.
com/zetcode/Car.java
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.
application.yml
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 configurationfile. It contains the Derby datasource.
com/zetcode/AppConfig.java
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;@Configurationpublic class AppConfig { @Bean @Primary @ConfigurationProperties(prefix = "datasource") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); }}
The AppConfig
is a Java configuration class. It createsthe data source bean from the configuration file.
com/zetcode/MyController.java
package com.zetcode.controller;import com.zetcode.service.ICarService;import java.util.HashMap;import java.util.Map;import java.util.logging.Level;import java.util.logging.Logger;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.ApplicationContext;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView;@Controllerpublic class MyController { @Autowired private ApplicationContext appContext; @Autowired private ICarService carService; @RequestMapping(path = "/pdf", method = RequestMethod.GET) public ModelAndView report() { JasperReportsPdfView view = new JasperReportsPdfView(); view.setUrl("classpath:report2.jrxml"); view.setApplicationContext(appContext); Map<String, Object> params = new HashMap<>(); params.put("datasource", carService.findAll()); return new ModelAndView(view, params); }}
In the MyController
, we have two methods that react to tworequests.
@Autowiredprivate ICarService carService;
We inject CarService
object into the attribute. The serviceobject is used to retrieve data from the database.
@RequestMapping(path = "/pdf", method = RequestMethod.GET)public ModelAndView report() { JasperReportsPdfView view = new JasperReportsPdfView(); view.setUrl("classpath:report2.jrxml"); view.setApplicationContext(appContext); Map<String, Object> params = new HashMap<>(); params.put("datasource", carService.getCars()); return new ModelAndView(view, params);}
In the report
method, a report is generated and sentback to the client. The JasperReportsPdfView
is a Springclass that generates a PDF report from the provided template and data.
com/zetcode/ICarService.java
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 toget all cars from the data source.
com/zetcode/CarService.java
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;@Servicepublic 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 ofthe findAll
method. We retrieve all cars fromthe CARS
table with the help of the JdbcTemplate
.
@Autowiredprivate JdbcTemplate jtm;
JdbcTemplate
is injected.
String sql = "SELECT * FROM Cars";
This is SQL to be executed. We select all cars from the CARS
table.
List<Car> cars = jtm.query(sql, new BeanPropertyRowMapper(Car.class));
BeanPropertyRowMapper
converts a row into a new instance of thespecified mapped target class.
index.html
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Home Page</title> </head> <body> <a href="/pdf.html">Generate report</a> </body></html>
The index.html
file contains a link to generate the PDF report.
com/zetcode/Application.java
package com.zetcode;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.EnableAutoConfiguration;@SpringBootApplicationpublic 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. Theapplication used Spring Boot framework and was run in a web environment.