# Spring Boot CMD JasperReports 集成

> 原文： [http://zetcode.com/articles/jasperspringbootcmd/](http://zetcode.com/articles/jasperspringbootcmd/)

在本教程中，我们展示如何在 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`

```java
-- 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`表。

```java
$ $DERBY_HOME/bin/ij
ij version 10.11
ij> CONNECT 'jdbc:derby:testdb';
ij> RUN 'cars.sql';

```

一种选择是使用`ij`工具从 SQL 脚本创建表。 请参考 [Apache Derby 教程](/db/apachederbytutorial/)以熟悉 Derby。

```java
$ $DERBY_HOME/bin/NetworkServerControl start &

```

使用`NetworkServerControl`工具启动 Derby 服务器。

## 应用

以下 Spring Boot 应用从数据库表加载数据，并使用 JasperReports 库从中生成 PDF 报告。

```java
$ 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`

```java
<?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`

```java
<?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>

```

这是报告模板文件。 模板仅包含明细带。 在详细信息区域内，将对数据源提供的每个记录重复每个元素。

```java
<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 的元素。

```java
<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`

```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`

```java
datasource:
  url: jdbc:derby://localhost:1527/testdb
  username: app
  password: app
  driverClassName: org.apache.derby.jdbc.ClientDriver

```

`application.yml`是主要的 Spring Boot 配置文件。 它包含 Derby 数据源设置。

`AppConfig.java`

```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`

```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 报告。

```java
JasperReport jreport = JasperCompileManager.compileReport(report);

```

使用`JasperCompileManager.compileReport()`方法，我们将 XML 报告模板编译为中介`JasperReport`。

```java
JRBeanCollectionDataSource ds = new JRBeanCollectionDataSource(cars);

```

从提供的汽车对象列表中，我们创建一个`JRBeanCollectionDataSource`。 Bean 的属性将被映射到已编译报表对象的字段。

```java
JasperPrint jprint = JasperFillManager.fillReport(jreport, params, ds);

```

已编译的 Jasper 对象使用`JasperFillManager.fillReport()`方法填充了数据。 产生一个`JasperPrint`对象。

```java
JasperExportManager.exportReportToPdfFile(jprint,
        "src/main/resources/report2.pdf");

```

`JasperExportManager.exportReportToPdfFile()`方法将`JasperPrint`对象转换为 PDF 文件。

`ICarService.java`

```java
package com.zetcode.service;

import com.zetcode.bean.Car;
import java.util.List;

public interface ICarService {

    public List<Car> findAll();
}

```

`ICarService`提供了一种从数据源获取所有汽车的契约方法。

`CarService.java`

```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`

```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 应用的命令行运行程序。

```java
@Autowired
private ICarService carService;

```

我们注入服务对象。

```java
List<Car> cars = carService.findAll();

```

我们使用服务对象获取所有汽车。

```java
ReportGenerator rg = new ReportGenerator();
rg.generatePdfReport(cars);

```

`ReportGenerator`用于创建 PDF 报告。 该报告包含检索到的汽车。

`Application.java`

```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 框架，并在命令行中运行。 您可能也对这些相关教程感兴趣： [Spring Boot JasperReports Web 集成](/articles/jasperspringbootweb/)，[使用 JasperReports API 创建报告](/articles/jasperprog/)，[使用 JasperReports 从 CSV 创建报告](/articles/jaspercsv/)和 [Java 教程](/lang/java/)。