在本教程中,我们展示如何在 Spring Boot 框架中使用 JasperReports。 Spring Boot 在命令行中运行。
JasperReports 是一个 Java 开源报告库。 它可以创建各种格式的报告,包括 PDF,HTML,XLS 或 CSV。 JasperReports 以一种简单而灵活的方式创建了面向页面的可打印文档。
JdbcTemplate 是一个 Spring 库,可以帮助程序员创建与关系数据库和 JDBC 一起使用的应用。 它会处理许多繁琐且容易出错的底层细节,例如处理事务,清理资源以及正确处理异常。 JdbcTemplate 在 Spring 的spring-jdbc
模块中提供。
Spring 是用于开发 Java 企业应用的流行 Java 应用框架。 它还有助于集成各种企业组件。 Spring Boot 使创建具有 Spring 动力的生产级应用和服务变得很容易,而对安装的要求却最低。
Apache Derby 是完全用 Java 实现的开源关系数据库。 它占地面积小,易于部署和安装。 它可以在嵌入式和客户端/服务器模式下运行。
CARS
表
在我们的应用中,我们使用下表:
cars.sql
-- 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);
cars.sql
文件创建CARS
表。
$ $DERBY_HOME/bin/ij
ij version 10.11
ij> CONNECT 'jdbc:derby:testdb';
ij> RUN 'cars.sql';
一种选择是使用ij
工具从 SQL 脚本创建表。
$ $DERBY_HOME/bin/NetworkServerControl start &
使用NetworkServerControl
工具启动 Derby 服务器。
应用
以下 Spring Boot 应用从数据库表加载数据,并使用 JasperReports 库从中生成 PDF 报告。
$ 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
这是项目结构。
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>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>
Maven pom.xml
文件包含以下依赖项:derbyclient
,jasperreports
和spring-boot-starter-jdbc
。 jasperreports
依赖项是 JasperReports 库; spring-boot-starter-jdbc
包含 JdbcTemplate 库。
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>
这是报告模板文件。 模板仅包含明细带。 在详细信息区域内,将对数据源提供的每个记录重复每个元素。
<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>
报告中有三个字段。 这些字段映射到数据源 bean 的元素。
<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>
文本字段是充满动态数据的元素。 我们将一个字段中的值放在文本字段中。 我们使用$F{}
语法引用该变量。
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 + '}';
}
}
这是Car
bean 类。 它包含商品 ID,名称和价格。
application.yml
datasource:
url: jdbc:derby://localhost:1527/testdb
username: app
password: app
driverClassName: org.apache.derby.jdbc.ClientDriver
application.yml
是主要的 Spring Boot 配置文件。 它包含 Derby 数据源设置。
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;
@Configuration
public class AppConfig {
@Bean
@Primary
@ConfigurationProperties(prefix = "datasource")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
}
AppConfig
是 Java 配置类。 它从配置文件创建数据源 bean。
ReportGenerator.java
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");
}
}
ReportGenerator
根据提供的数据创建 PDF 报告。
JasperReport jreport = JasperCompileManager.compileReport(report);
使用JasperCompileManager.compileReport()
方法,我们将 XML 报告模板编译为中介JasperReport
。
JRBeanCollectionDataSource ds = new JRBeanCollectionDataSource(cars);
从提供的汽车对象列表中,我们创建一个JRBeanCollectionDataSource
。 Bean 的属性将被映射到已编译报表对象的字段。
JasperPrint jprint = JasperFillManager.fillReport(jreport, params, ds);
已编译的 Jasper 对象使用JasperFillManager.fillReport()
方法填充了数据。 产生一个JasperPrint
对象。
JasperExportManager.exportReportToPdfFile(jprint,
"src/main/resources/report2.pdf");
JasperExportManager.exportReportToPdfFile()
方法将JasperPrint
对象转换为 PDF 文件。
ICarService.java
package com.zetcode.service;
import com.zetcode.bean.Car;
import java.util.List;
public interface ICarService {
public List<Car> findAll();
}
ICarService
提供了一种从数据源获取所有汽车的合同方法。
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;
@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
包含findAll()
方法的实现。 我们借助JdbcTemplate
从CARS
表中检索所有汽车。
MyRunner.java
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
是 Spring Boot 应用的命令行运行程序。
@Autowired
private ICarService carService;
我们注入服务对象。
List<Car> cars = carService.findAll();
我们使用服务对象获取所有汽车。
ReportGenerator rg = new ReportGenerator();
rg.generatePdfReport(cars);
ReportGenerator
用于创建 PDF 报告。 该报告包含检索到的汽车。
Application.java
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);
}
}
Application
设置 Spring Boot 应用。
在本教程中,我们使用 JasperReports 创建了 PDF 报告。 该应用使用了 Spring Boot 框架,并在命令行中运行。