PDF报表打印 -- Jasper Report

一. PDF报表打印概述


1 概述


在企业级应用开发中,报表生成、报表打印下载是其重要的一个环节。在之前的课程中我们已经学习了报表中比较重要的一种:Excel报表。其实除了Excel报表之外,PDF报表也有广泛的应用场景,必须用户详细资料,用户简历等。

2 常见PDF报表的制作方式


目前世面上比较流行的制作PDF报表的工具如下:

  1. iText PDF:iText是著名的开放项目,是用于生成PDF文档的一个java类库。通过iText不仅可以生成PDF或rtf的文档,而且可以将XML、Html文件转化为PDF文件。
  2. Openoffice:openoffice是开源软件且能在windows和linux平台下运行,可以灵活的将word或者Excel转化为PDF文档。
  3. Jasper Report:是一个强大、灵活的报表生成工具,能够展示丰富的页面内容,并将之转换成PDF.

3 JasperReport框架的介绍


在这里插入图片描述
JasperReport是一个强大、灵活的报表生成工具,能够展示丰富的页面内容,并将之转换成PDF,HTML,或者XML格式。该库完全由Java写成,可以用于在各种Java应用程序,包括J2EE,Web应用程序中生成动态内容。只需要将JasperReport引入工程中即可完成PDF报表的编译、显示、输出等工作。

  • 在开源的JAVA报表工具中,JASPER Report发展是比较好的,比一些商业的报表引擎做得还好,如支持了十字交叉报表、统计报表、图形报表,支持多种报表格式的输出,如PDF、RTF、XML、CSV、XHTML、TEXT、DOCX以及OpenOffice。
  • 数据源支持更多,常用 JDBC SQL查询、XML文件、CSV文件 、HQL(Hibernate查询),HBase,JAVA集合等。还允许你义自己的数据源,通过JASPER文件及数据源,JASPER就能生成最终用户想要的文档格式。

二. JasperReport的开发步骤


1 JasperReport生命周期


通常我们提到PDF报表的时候,浮现在脑海中的是最终的PDF文档文件。在JasperReports中,这只是报表生命周期的最后阶段。通过JasperReports生成PDF报表一共要经过三个阶段,我们称之为 JasperReport的生命周期,这三个阶段为:设计(Design)阶段、执行(Execution)阶段以及输出(Export)阶段,如下图所示:

在这里插入图片描述

  1. 设计阶段(Design):所谓的报表设计就是创建一些模板,模板包含了报表的布局与设计,包括执行计算的复杂公式、可选的从数据源获取数据的查询语句、以及其它的一些信息。模板设计完成之后,我们将模板保存为JRXML文件(JR代表JasperReports),其实就是一个XML文件。
  2. 执行阶段(Execution):使用以JRXML文件编译为可执行的二进制文件(即.Jasper文件)结合数据进行执行,填充报表数据。
  3. 输出阶段(Export):数据填充结束,可以指定输出为多种形式的报表。

2 JasperReport原理简述


在这里插入图片描述

  1. JRXML:报表填充模板,本质是一个XML。
    JasperReport已经封装了一个dtd,只要按照规定的格式写这个xml文件,那么jasperReport就可以将其解析最终生成报表,但是jasperReport所解析的不是我们常见的.xml文件,而是.jrxml文件,其实跟xml是一样的,只是后缀不一样。
  2. Jasper:由JRXML模板编译生成的二进制文件,用于代码填充数据。
    解析完成后JasperReport就开始编译.jrxml文件,将其编译成.jasper文件,因为JasperReport只可以对.jasper文件进行填充数据和转换,这步操作就跟我们java中将java文件编译成class文件是一样的。
  3. Jrprint:当用数据填充完Jasper后生成的文件,用于输出报表。
    这一步才是JasperReport的核心所在,它会根据你在xml里面写好的查询语句来查询指定是数据库,也可以控制在后台编写查询语句,参数,数据库。在报表填充完后,会再生成一个.jrprint格式的文件(读取jasper文件进行填充,然后生成一个jrprint文件)。
  4. Exporter:决定要输出的报表为何种格式,报表输出的管理类。
  5. Jasperreport可以输出多种格式的报表文件,常见的有Html,PDF,xls等。

3 开发流程概述

  • 制作报表模板
  • 模板编译
  • 构造数据
  • 填充模板数据

三. 模板工具Jaspersoft Studio


1 概述


Jaspersoft Studio是JasperReports库和JasperReports服务器的基于Eclipse的报告设计器; 它可以作为Eclipse插件或作为独立的应用程序使用。Jaspersoft Studio允许您创建包含图表,图像,子报表,交叉表等的复杂布局。您可以通过JDBC,TableModels,JavaBeans,XML,Hibernate,大数据(如Hive),CSV,XML / A以及自定义来源等各种来源访问数据,然后将报告发布为PDF,RTF, XML,XLS,CSV,HTML,XHTML,文本,DOCX或OpenOffice。

Jaspersoft Studio 是一个可视化的报表设计工具,使用该软件可以方便地对报表进行可视化的设计,设计结果为格式.jrxml 的 XML 文件,并且可以把.jrxml 文件编译成.jasper 格式文件方便 JasperReport 报表引擎解析、显示。

2 安装配置


到JasperReport官网下载 https://community.jaspersoft.com/community-download

在这里插入图片描述
下载 Library Jar包(传统导入jar包工程需下载)和模板设计器Jaspersoft studio。并安装Jaspersoft studio,安装的过程比较简单,一直下一步直至安装成功即可。

3 面板介绍


在这里插入图片描述

  • Report editing area (主编辑区域)中,您直观地通过拖动,定位,对齐和通过 Designer palette(设计器调色板)对报表元素调整大小。JasperSoft Studio 有一个多标签编辑器,Design,Source 和 Preview:
    1. Design tab:当你打开一个报告文件,它允许您以图形方式创建报表选中
    2. Source tab: 包含用于报表的 JRXML 源代码。
    3. Preview tab: 允许在选择数据源和输出格式后,运行报表预览。
  • Repository Explorer view:包含 JasperServer 生成的连接和可用的数据适配器列表
  • Project Explorer view:包含 JasperReports 的工程项目清单
  • Outline view:在大纲视图中显示了一个树的形式的方式报告的完整结构。
  • Properties view:通常是任何基于 Eclipse 的产品/插件的基础之一。它通常被填充与实际所选元素的属性的信息。这就是这样,当你从主设计区域(即:一个文本字段)选择一个报表元素或从大纲,视图显示了它的信息。其中一些属性可以是只读的,但大部分都是可编辑的,对其进行修改,通常会通知更改绘制的元素(如:元素的宽度或高度)。
  • Problems view:显示的问题和错误,例如可以阻断报告的正确的编译。
  • Report state summary 提供了有关在报表编译/填充/执行统计用户有用的信息。错误会显示在这里。

4 基本使用


4.1 模板制作


(1)打开Jaspersoft Studio ,新建一个project。 步骤: File -> New -> Project-> JasperReports Project。

在这里插入图片描述

(2)新建一个Jasper Report模板,在 Stidio的左下方Project Explorer 找到刚才新建的Project (我这里新建的是JasperProject)。步骤:项目右键 -> New -> Jasper Report
在这里插入图片描述
在这里插入图片描述
(3)选择 Blank A4 (A4纸大小的模板),然后 Next 命名为DemoReport1.jrxml,点击Finish。

在这里插入图片描述
如图所示,报表模板被垂直的分层,每一个部分都是一个Band,每一个Band的特点不同:

在这里插入图片描述

  • Title(标题):只在整个报表的第一页的最上端显示。只在第一页显示,其他页面均不显示。
  • Page Header(页头):在整个报表中每一页都会显示。在第一页中,出现的位置在 Title Band的下面。在除了第一页的其他页面中Page Header 的内容均在页面的最上端显示。
  • Page Footer(页脚):在整个报表中每一页都会显示。显示在页面的最下端。一般用来显示页码。
  • Detail 1(详细):报表内容,每一页都会显示。
  • Column Header(列头):Detail中打印的是一张表的话,这Column Header就是表中列的列头。
  • Column Footer(列脚):Detail中打印的是一张表的话,这Column Footer就是表中列的列脚。
  • Summary(统计):表格的合计段,出现在整个报表的最后一页中,在Detail 1 Band后面。主要是用来做报表的合计显示。

4.2 编译模板


在右侧Palette里选择static text文本框,里面输入“Jasper Test”
在这里插入图片描述

我们可以右键单机模板文件 -> compile Report 对模板进行编译,生成.jasper文件。也可以用java代码生成。
右键生成:
在这里插入图片描述
代码生成:

(1)新建工程引入坐标
<dependencies>
        <dependency>
            <groupId>net.sf.jasperreports</groupId>
            <artifactId>jasperreports</artifactId>
            <version>6.5.0</version>
        </dependency>
        <dependency>
            <groupId>org.olap4j</groupId>
            <artifactId>olap4j</artifactId>
            <version>1.2.0</version>
        </dependency>
        <dependency>
            <groupId>com.lowagie</groupId>
            <artifactId>itext</artifactId>
            <version>2.1.7</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>4.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
            <version>4.0.1</version>
        </dependency>
    </dependencies>
(2)代码实现
package com.wsw;

import net.sf.jasperreports.engine.JREmptyDataSource;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.view.JasperViewer;

import java.util.HashMap;

public class JasperTest {
    public static void main(String[] args) {
        //createJasper();
        //createJrprint();
        showPdf();
    }

    //1.将pdf模板编译为Jasper文件
    public static void createJasper(){
        try{
            String path = "C:\\Users\\21134\\Desktop\\DemoReport1.jrxml";
            JasperCompileManager.compileReportToFile(path);
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    //2.将Jasper文件和数据进行填充,获取Jrprint
    public static void createJrprint(){
        try{
            String path = "C:\\Users\\21134\\Desktop\\DemoReport1.jasper";
            //通过空参数和空数据源进行填充
            JasperFillManager.fillReportToFile(path,new HashMap(),new JREmptyDataSource());
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    //3.预览
    public static void showPdf(){
        try{
            String path = "C:\\Users\\21134\\Desktop\\DemoReport1.jrprint";
            JasperViewer.viewReport(path,false);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}
(3)实现结果

文件生成位置:

在这里插入图片描述
最终展示效果:
在这里插入图片描述

4.3 整合SpringBoot工程


(1)新建SpringBoot工程引入坐标
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.5.RELEASE</version>
    <relativePath/>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>net.sf.jasperreports</groupId>
        <artifactId>jasperreports</artifactId>
        <version>6.5.0</version>
    </dependency>
    <dependency>
        <groupId>org.olap4j</groupId>
        <artifactId>olap4j</artifactId>
        <version>1.2.0</version>
    </dependency>
    <dependency>
        <groupId>com.lowagie</groupId>
        <artifactId>itext</artifactId>
        <version>2.1.7</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>4.0.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>4.0.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml-schemas</artifactId>
        <version>4.0.1</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
</dependencies>
(2)引入配置文件
server:
    port: 8181
spring:
    application:
        name: jasper-demo #指定服务名
    datasource:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/ihrm?useUnicode=true&characterEncoding=utf8
        username: root
        password: root
(3)创建启动类
@SpringBootApplication(scanBasePackages = "com.xxx")
public class JasperApplication {
	public static void main(String[] args) {
		SpringApplication.run(JasperApplication.class, args);
	}
}
(4)导入生成的.jasper文件
(5)创建测试controller
@RestController
public class JasperController {
    @GetMapping("/testJasper")
    public void createHtml(HttpServletResponse response, HttpServletRequest request)throws Exception{
        //引入jasper文件。由JRXML模板编译生成的二进制文件,用于代码填充数据
        Resource resource = new ClassPathResource("templates/test01.jasper");
        //加载jasper文件创建inputStream
        FileInputStream isRef = new FileInputStream(resource.getFile());
        ServletOutputStream sosRef = response.getOutputStream();
        try {
            //创建JasperPrint对象
            JasperPrint jasperPrint = JasperFillManager.fillReport(isRef, new HashMap<>(),new JREmptyDataSource());
            //写入pdf数据
            JasperExportManager.exportReportToPdfStream(jasperPrint,sosRef);
        } finally {
            sosRef.flush();
            sosRef.close();
        }
    }
}

4.4 中文处理


(1)设计阶段需要指定中文样式

在这里插入图片描述
(2)通过手动指定中文字体的形式解决中文不现实

  • 添加properties文件:
net.sf.jasperreports.extension.registry.factory.simple.font.families=net.sf.jasperreports.engine.fonts.SimpleFontExtensionsRegistryFactory
net.sf.jasperreports.extension.simple.font.families.lobstertwo=stsong/fonts.xml
  • 指定中文配置文件fonts.xml
<?xml version="1.0" encoding="UTF-8"?>
<fontFamilies>
    <!--<fontFamily name="Lobster Two">-->
    <!--<normal>lobstertwo/LobsterTwo-Regular.otf</normal>-->
    <!--<bold>lobstertwo/LobsterTwo-Bold.otf</bold>-->
    <!--<italic>lobstertwo/LobsterTwo-Italic.otf</italic>-->
    <!--<boldItalic>lobstertwo/LobsterTwo-BoldItalic.otf</boldItalic>-->
    <!--<pdfEncoding>Identity-H</pdfEncoding>-->
    <!--<pdfEmbedded>true</pdfEmbedded>-->
    <!--<!–-->
    <!--<exportFonts>-->
    <!--<export key="net.sf.jasperreports.html">'Lobster Two', 'Times New Roman', Times, serif</export>-->
    <!--</exportFonts>-->
    <!--–>-->
    <!--</fontFamily>-->
    <fontFamily name="华文宋体">
        <normal>stsong/stsong.TTF</normal>
        <bold>stsong/stsong.TTF</bold>
        <italic>stsong/stsong.TTF</italic>
        <boldItalic>stsong/stsong.TTF</boldItalic>
        <pdfEncoding>Identity-H</pdfEncoding>
        <pdfEmbedded>true</pdfEmbedded>
        <exportFonts>
            <export key="net.sf.jasperreports.html">'华文宋体', Arial, Helvetica, sans-serif</export>
            <export key="net.sf.jasperreports.xhtml">'华文宋体', Arial, Helvetica, sans-serif</export>
        </exportFonts>
        <!--
        <locales>
            <locale>en_US</locale>
            <locale>de_DE</locale>
        </locales>
        -->
    </fontFamily>
</fontFamilies>

windows可以从C:\Windows\Fonts下寻找想要的字库。

5 数据填充


/**
 * 填充数据构造JasperPrint
 * 			is: 文件输入流
 * 		parameters: 参数
 * 		dataSource: 数据源 
 */
public static JasperPrint fillReport(InputStream inputStream, Map<String, Object> parameters, JRDataSource dataSource) throws JRException {
    return getDefaultInstance().fill(inputStream, parameters, dataSource);
}

通过这段代码我们可以看出JasperReport对报表模板中的数据填充有很多种,但最主要的有以下两种:

  • Parameters(参数)填充
  • DataSource(数据源)填充

5.1 参数Map填充数据


Parameter通常是用来在打印的时候从程序里传值到报表里。也就是说parameters通常是起参数传递的作用。他们可以被用在一些特定的场合(比如应用中SQL查询的条件), 如report中任何一个需要从外部传入的变量等(如一个Image对象所包括的char或报表title的字符串)。parameters也需要在创建的时候定义它的数据类型,其数据类型是标准的java的Object。

5.1.1 模板制作
(1) 创建模板, 删除不需要的Band

新建一个jrxml文件,删除不需要的band。如下图所示:

在这里插入图片描述

(2) 设置模板的静态信息

如下图所示:
在这里插入图片描述

(3) 创建Parameters

首先,在左下角找到Parameters点击右键,选择Create Parameter
在这里插入图片描述在右下角的Properties中设置参数信息:
在这里插入图片描述
直接将设置好的参数拖拽到页面上即可,如下图所示:
在这里插入图片描述
模板制作完成后可以点击,预览按钮查看模板样式:
在这里插入图片描述
若是对于样式不满意,还可以去右下角对样式进行设计,修改
在这里插入图片描述

(4) 编译模板生成jasper文件

在这里插入图片描述

(5) 将Jasper文件放到Java工程里

在这里插入图片描述

(6) 编写Java代码

注意:设置参数时,参数的key必须大于模板中parameter参数的name一致。

package com.wsw.controller;

import net.sf.jasperreports.engine.JREmptyDataSource;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Map;

@RestController
public class JasperController02 {
    /**
     * 基于Parameters以Map的形式填充数据
     * @param response
     * @param request
     * @throws Exception
     */
    @GetMapping("/testJasper2")
    public void createHtml(HttpServletResponse response, HttpServletRequest request)throws Exception{
        //1.引入jasper文件。由JRXML模板编译生成的二进制文件,用于代码填充数据
        Resource resource = new ClassPathResource("templates/testParam.jasper");
        //2.加载jasper文件创建inputStream
        FileInputStream isRef = new FileInputStream(resource.getFile());
        ServletOutputStream sosRef = response.getOutputStream();
        try {
            Map parameters = new HashMap();
            //设置参数 参数的key必须大于模板中parameter参数的name一致
            parameters.put("username", "张三");
            parameters.put("mobile", "14747596654");
            parameters.put("company", "阿里巴巴");
            parameters.put("dept", "开发部");

            JasperPrint jasperPrint = JasperFillManager.fillReport(isRef, parameters,new JREmptyDataSource());
            //3.将JasperPrint已PDF的形式输出
            JasperExportManager.exportReportToPdfStream(jasperPrint,sosRef);
        } finally {
            sosRef.flush();
            sosRef.close();
        }
    }

}
(6) 重启项目
(7) 调用接口

填写的参数都被打印出来了,如下图所示:
在这里插入图片描述

5.2 数据源填充数据


5.2.1 JDBC 数据源
5.2.1.1 无参数的JDBC数据源连接

使用JDBC数据源填充数据,使用JasperSoft Studio 先要配置一个数据库连接。
填写数据源的类型,选择“DataBase JDBC Connection”
(1) 新建建一个JDBC Connection的模板,testConn.jrxml
(2) 选择左上角的Repository
在这里插入图片描述
(3) 右键点击Data Adapters 选择Created Data Adapter

在这里插入图片描述
(4) 选择 Database JDBC Connection
在这里插入图片描述
(5) 配置数据库连接的信息

在这里插入图片描述
(6) 添加数据库连接的驱动
点击Driver Classpath

在这里插入图片描述
点击Add,选择数据库驱动的jar包, 这里提供一个下载jar包的网址:http://central.maven.org/maven2/mysql/mysql-connector-java/ 。我下载的版本是:mysql-connector-java-5.1.9.jar
在这里插入图片描述
添加完jar包后,点击test按钮,连接成功如下图所示 :

在这里插入图片描述最后,点击Finish。创建成功!
在这里插入图片描述

(7) 编辑模板 – 设置Fields

去左下角的OutLine里,在模板上点击右键选择Datatest and Query
在这里插入图片描述
选择我们刚刚设置好的的数据库:

在这里插入图片描述
选择我们想要显示数据的表,并在右侧编写查询sql

在这里插入图片描述
点击Read Fields,就会生成相应的字段信息

在这里插入图片描述
删除多余的字段,只留下需要展示的字段:
在这里插入图片描述
点击OK,查看OutLine里的Fields,里面已经有我们设置好的字段信息了:

在这里插入图片描述
(8) 编辑模板 – 设置页面样式
直接将需要使用的字段拖拽到Detail里,这时会出现对应的静态文本框,因为我们是要生成一个列表,需要将这些静态框删除,然后设计表格样式,如下图所示:
在这里插入图片描述
去properties中设置每一行数据的高度,高度与你设置的每一个元素的高度相同:
在这里插入图片描述
保存后,点击preview查看样式:

在这里插入图片描述
(8) 编译模板,将生成的Jasper文件拖入项目的resourse目录下
(9) 编写java代码

package com.wsw.controller;

import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.HashMap;
import java.util.Map;

@RestController
public class JasperController03 {
    /**
     * 基于JDBC数据源的形式填充数据
     * @param response
     * @param request
     * @throws Exception
     */
    @GetMapping("/testJasper3")
    public void createHtml(HttpServletResponse response, HttpServletRequest request)throws Exception{
        //1.引入jasper文件。由JRXML模板编译生成的二进制文件,用于代码填充数据
        Resource resource = new ClassPathResource("templates/testConn01.jasper");
        //2.加载jasper文件创建inputStream
        FileInputStream isRef = new FileInputStream(resource.getFile());
        ServletOutputStream sosRef = response.getOutputStream();
        try {
            Map parameters = new HashMap();

            //获取数据库连接
            Connection conn = getConnection();

            JasperPrint jasperPrint = JasperFillManager.fillReport(isRef, parameters, conn);
            //3.将JasperPrint已PDF的形式输出
            JasperExportManager.exportReportToPdfStream(jasperPrint,sosRef);
        } finally {
            sosRef.flush();
            sosRef.close();
        }
    }

    public Connection getConnection() throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/ihrm", "root", "root");
        return connection;
    }

}

(9) 调用接口

结果如下图所示:
在这里插入图片描述

5.2.1.2 有参数的JDBC数据源连接

(1) 创建Parameters
回到我们的模板,添加一个Paramerters
在这里插入图片描述
设置参数信息:
在这里插入图片描述
(2) 修改查询语句
回到OutLine,右键单击testConn,选择Datatest and Query

在这里插入图片描述
修改sql, 这里的参数要使用 $P{参数名} 的形式:

在这里插入图片描述
点击OK后,进入preview页面。填入参数后,点击启动按钮:

在这里插入图片描述
预览一下,OK:
在这里插入图片描述
(3) 重新编译一下jrxml文件,将生成的jasper文件放入工程里

(4) 修改Java代码

package com.wsw.controller;

import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.HashMap;
import java.util.Map;

@RestController
public class JasperController03 {
    /**
     * 基于JDBC数据源的形式填充数据
     * @param response
     * @param request
     * @throws Exception
     */
    @GetMapping("/testJasper3")
    public void createHtml(HttpServletResponse response, HttpServletRequest request)throws Exception{
        //1.引入jasper文件。由JRXML模板编译生成的二进制文件,用于代码填充数据
        Resource resource = new ClassPathResource("templates/testConn.jasper");
        //2.加载jasper文件创建inputStream
        FileInputStream isRef = new FileInputStream(resource.getFile());
        ServletOutputStream sosRef = response.getOutputStream();
        try {
            Map parameters = new HashMap();

            parameters.put("cid", "1");

            //获取数据库连接
            Connection conn = getConnection();

            JasperPrint jasperPrint = JasperFillManager.fillReport(isRef, parameters, conn);
            //3.将JasperPrint已PDF的形式输出
            JasperExportManager.exportReportToPdfStream(jasperPrint,sosRef);
        } finally {
            sosRef.flush();
            sosRef.close();
        }
    }
	/**
	 * 获取数据库连接
	 * @return
	 * @throws Exception
	 */
    public Connection getConnection() throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/ihrm", "root", "root");
        return connection;
    }

}

(5) 调用接口,如下图所示

注意:我在编写代码时遇到过jasper文件读取不到的问题,解决方法时将Jasper文件改个名字即可,怀疑时缓存问题。

在这里插入图片描述

5.2.2 JavaBean 数据源

使用JDBC数据源的形式,将数据库的连接交给了Jasper管理。这种方式可能不够好,这时可以使用JavaBean作为数据源的方式

(1) 新建模板testBean

(2) 手动创建Fields
找到OutLine,右键Fields选择Create Field

在这里插入图片描述
设置Field的名称,因为是通过反射实现的,所以该名称要与JavaBean中的一致:
在这里插入图片描述

(3) 设置模板如下图所示

在这里插入图片描述

(4) preview一下确定样式

由于没有传递数据,故此时都为null。
在这里插入图片描述

(5) 编译模板,将jasper文件放入工程

(6) 编写Java代码

步骤:

  1. 获取到对象的list集合
  2. 通过list结合创建JavaBean的数据源对象

① 创建一个JavaBean

package com.wsw.domain;

public class User {
    private String id;
    private String username;
    private String mobile;
    private String company;
    private String dept;

    public User() {
    }

    public User(String id, String username, String mobile, String company, String dept) {
        this.id = id;
        this.username = username;
        this.mobile = mobile;
        this.company = company;
        this.dept = dept;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    public String getCompany() {
        return company;
    }

    public void setCompany(String company) {
        this.company = company;
    }

    public String getDept() {
        return dept;
    }

    public void setDept(String dept) {
        this.dept = dept;
    }
}

② 编写接口

package com.wsw.controller;

import com.wsw.domain.User;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
public class JasperController04 {
    /**
     * 基于JavaBean的形式填充数据
     * @param response
     * @param request
     * @throws Exception
     */
    @GetMapping("/testJasper4")
    public void createHtml(HttpServletResponse response, HttpServletRequest request)throws Exception{
        //1.引入jasper文件。由JRXML模板编译生成的二进制文件,用于代码填充数据
        Resource resource = new ClassPathResource("templates/testBean01.jasper");
        //2.加载jasper文件创建inputStream
        FileInputStream isRef = new FileInputStream(resource.getFile());
        ServletOutputStream sosRef = response.getOutputStream();
        try {
            Map parameters = new HashMap();

            //构造JavaBean的数据源
            //1. 获取到对象的list集合
            List<User> users = getUserList();
            //2. 通过list结合创建JavaBean的数据源对象
            JRBeanCollectionDataSource jrBeanCollectionDataSource = new JRBeanCollectionDataSource(users);

            JasperPrint jasperPrint = JasperFillManager.fillReport(isRef, parameters, jrBeanCollectionDataSource);
            //3.将JasperPrint已PDF的形式输出
            JasperExportManager.exportReportToPdfStream(jasperPrint,sosRef);
        } finally {
            sosRef.flush();
            sosRef.close();
        }
    }

    /**
     * 设置模拟数据
     * @return
     */
    public List<User> getUserList() {
        List<User> userList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            User user = new User(i + "", "wsw" + i ,"1470000000" + i, "中国石油" , "开发部");
            userList.add(user);
        }
        return userList;
    }

}

注意:这里有一个坑,就是在手动设置Field的时候description字段不要填写描述,否则反射机制会出现问题,可能寻找对应字段时会出现对应字段匹配错误的问题!

(7) 重启项目
(8) 调用接口

结果如下:

在这里插入图片描述
6 分组报表


6.1 概述


两种情况会使用分组报表:

  • 美观和好看的显示
  • 当数据库分为两层表时,经常需要批量打印子表的数据。打印室,常常需要按照附表的外键或关联值进行自动分组,即每一条父表记录所属的字表打印到一组报表中,每组报表都单独计数及计算页数。

在应用中,可以通过选择需要打印的父表记录,将父表的id传入,有报表进行自动分组。

6.2 分组功能的实现


(1) 新建模板

新建一个testGroup.jrxml模板
在这里插入图片描述

创建Field
在这里插入图片描述
设置页面基本样式:
在这里插入图片描述

(2) 设置分组

找到 Outline 的模板名称,点击右键选择 Create Group

在这里插入图片描述
选择分组的依据,这里我选择的时company 公司分组:
在这里插入图片描述
点击next,会出现两个选项,就按照默认就好(这两个选项就是分组的头和尾):

在这里插入图片描述
点击Finsih,页面变成如下样式:

在这里插入图片描述
由于我们以公司分组,故要将公司的company的Field拖入Group Header中显示,出现下图情况直接点击Finish。

在这里插入图片描述
成功后如下图所示:
在这里插入图片描述
双击Group Header里的company字段可以修改打印的语句,格式与java代码类似,最后点击Finish:

在这里插入图片描述
最后一步,对模板的样式进行处理:
在这里插入图片描述

(3) 点击preview,预览模板
在这里插入图片描述

(4) 编译模板,将生成的jasper文件导入项目中
(5) 编写java代码

package com.wsw.controller;

import com.wsw.domain.User;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
public class JasperController05 {
    /**
     * 分组报表
     * @param response
     * @param request
     * @throws Exception
     */
    @GetMapping("/testJasper5")
    public void createHtml(HttpServletResponse response, HttpServletRequest request)throws Exception{
        //1.引入jasper文件。由JRXML模板编译生成的二进制文件,用于代码填充数据
        Resource resource = new ClassPathResource("templates/testGroup.jasper");
        //2.加载jasper文件创建inputStream
        FileInputStream isRef = new FileInputStream(resource.getFile());
        ServletOutputStream sosRef = response.getOutputStream();
        try {
            Map parameters = new HashMap();

            //构造JavaBean的数据源
            //1. 获取到对象的list集合
            List<User> users = getUserList();
            //2. 通过list结合创建JavaBean的数据源对象
            JRBeanCollectionDataSource jrBeanCollectionDataSource = new JRBeanCollectionDataSource(users);

            JasperPrint jasperPrint = JasperFillManager.fillReport(isRef, parameters, jrBeanCollectionDataSource);
            //3.将JasperPrint已PDF的形式输出
            JasperExportManager.exportReportToPdfStream(jasperPrint,sosRef);
        } finally {
            sosRef.flush();
            sosRef.close();
        }
    }

    /**
     * 设置模拟数据
     * @return
     */
    public List<User> getUserList() {
        List<User> userList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            User user = new User(i + "", "wsw" + i ,"1470000000" + i, "中国石油" , "开发部");
            userList.add(user);
        }
        for (int i = 0; i < 6; i++) {
            User user = new User(i + "", "木头人" + i ,"1590000000" + i, "中国工商银行" , "开发部");
            userList.add(user);
        }
        return userList;
    }

}

(6) 调用接口

结果如下:
在这里插入图片描述

6.3 分组统计汇总

(1)创建Variable

找到Outline 选中 Variable 右键,选择Create Variable:
在这里插入图片描述
填写Variable 和参数类型,参数类型选择Integer就行:

在这里插入图片描述
点击Calculation, 选择Count:

在这里插入图片描述

点击Expression右侧, 填写表达式:

在这里插入图片描述
填写完成后点击Finish:
在这里插入图片描述

在Reset type 里选择 Group,根据分组重置Count函数的值:

在这里插入图片描述
(2)将Variable拖入Group Footer里
在这里插入图片描述
(3)双击这条Variable, 设置显示信息
在这里插入图片描述
设置完成后,点击Finish。并修改模板样式。如下图所示:
在这里插入图片描述
(3)设置页码

找到Outline里的Page Footer,右键 选择Add Band:
在这里插入图片描述

Band 被加回页面上:
在这里插入图片描述
将 Outline 里 Variables 下的PAGE_NUMBER 直接拖入 Page Footer。这就是当前页码:
在这里插入图片描述

(4)Preview 查看样式
(5)重新编译并导入项目
(6)重启项目,调用接口

结果如下:

在这里插入图片描述

7 Chart 图表

统计每个公司的员工数,以饼状图的形式显示


7.1 模板设置


(1) 删除Band 只保留 Title 和 Summary
在这里插入图片描述

(2) 创建Fields
在这里插入图片描述

(3) 创建chart图标

第一步:palette面板找到chart图标, 拖拽到band中
在这里插入图片描述

第二步:选择需要的图表类型,点击next
在这里插入图片描述

第三步:设置图标参数

在这里插入图片描述

第四步:点击Finish

(5) 设置模板页面样式

在这里插入图片描述
(6) 点击饼状图,在右下角设置饼状图属性

在这里插入图片描述
对标题进行设置:

![5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2NjYyNDc4,size_16,color_FFFFFF,t_70)
(7) 编译模板,导入项目

7.2 代码实现


(1) 编写存放表格数据的实体类

package com.wsw.domain;

public class UserCount {
    private String company;
    private Long count;

    public UserCount(String company, Long count) {
        this.company = company;
        this.count = count;
    }

    public UserCount() {
    }

    public String getCompany() {
        return company;
    }

    public void setCompany(String company) {
        this.company = company;
    }

    public Long getCount() {
        return count;
    }

    public void setCount(Long count) {
        this.count = count;
    }
}

(2) 接口代码

package com.wsw.controller;

import com.wsw.domain.User;
import com.wsw.domain.UserCount;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
public class JasperController06 {
    /**
     * Chart报表
     * @param response
     * @param request
     * @throws Exception
     */
    @GetMapping("/testJasper6")
    public void createHtml(HttpServletResponse response, HttpServletRequest request)throws Exception{
        //1.引入jasper文件。由JRXML模板编译生成的二进制文件,用于代码填充数据
        Resource resource = new ClassPathResource("templates/testChart.jasper");
        //2.加载jasper文件创建inputStream
        FileInputStream isRef = new FileInputStream(resource.getFile());
        ServletOutputStream sosRef = response.getOutputStream();
        try {
            Map parameters = new HashMap();

            //构造JavaBean的数据源
            //1. 获取到对象的list集合
            List<UserCount> users = getUserCountList();
            //2. 通过list结合创建JavaBean的数据源对象
            JRBeanCollectionDataSource jrBeanCollectionDataSource = new JRBeanCollectionDataSource(users);

            JasperPrint jasperPrint = JasperFillManager.fillReport(isRef, parameters, jrBeanCollectionDataSource);
            //3.将JasperPrint已PDF的形式输出
            JasperExportManager.exportReportToPdfStream(jasperPrint,sosRef);
        } finally {
            sosRef.flush();
            sosRef.close();
        }
    }

    /**
     * 设置模拟数据
     * @return
     */
    public List<UserCount> getUserCountList() {
        List<UserCount> userCounts = new ArrayList<>();

        UserCount userCount01 = new UserCount("阿里巴巴", 1000L);
        UserCount userCount02 = new UserCount("百度", 900L);
        UserCount userCount03 = new UserCount("腾讯", 1200L);

        userCounts.add(userCount01);
        userCounts.add(userCount02);
        userCounts.add(userCount03);

        return userCounts;
    }

}

7.3 实现结果

在这里插入图片描述

8 父子报表


8.1 概述


复杂报表或数据内容比较多的时候,可以使用子报表解决。

8.2 制作夫报表


首先制作父报表,就是调用子报表的一个基本报表。主报表的作用有如下两种:

  • 父报表中需要显示数据,使用子报表弥补studio设计的不足
  • 父报表不需要显示任何数据, 只是作为子报表的载体。适用于复杂报表的设计

8.3 制作子报表


第一步:创建父报表parent.jrxml
在这里插入图片描述
第二步:添加子报表

点击组件面板上的"Subreport"按钮,拖动到报表工作区上。

在这里插入图片描述
这时会出现如下弹框:
在这里插入图片描述
点击 Select a report file,选择WorkSpace这一项:
在这里插入图片描述
点击Browse,选择之前制作的图形报表testChart.jrxml:
在这里插入图片描述
一直点击OK,最后Finish:
在这里插入图片描述
第三步:修改testChart,只保留图表部分

在这里插入图片描述
第四步:在父报表中添加一个Parameter,存放子报表图形中所需的数据
在这里插入图片描述
第五步:单击子报表,选择Subreport
在这里插入图片描述
第六步:清空Connection Expression,点击Data Source Expression

在这里插入图片描述
第七步:点击加号
在这里插入图片描述
第八步:点击‘…‘
在这里插入图片描述第九步:选择JRBeanCollectionDataSource
在这里插入图片描述
第十步:复制下来该方法
在这里插入图片描述
第十一步:填写表达式
在这里插入图片描述

第十二步:在父报表中添加一个参数subPath,用来保存子报表的路径

在这里插入图片描述
第十三步:填写子报表的表达式

在这里插入图片描述
第十四步:编译父子报表,并导入项目

8.4 编写Java代码


package com.wsw.controller;

import com.wsw.domain.UserCount;
import net.sf.jasperreports.engine.JREmptyDataSource;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
public class JasperController07 {
    /**
     * 父子报表
     * @param response
     * @param request
     * @throws Exception
     */
    @GetMapping("/testJasper7")
    public void createHtml(HttpServletResponse response, HttpServletRequest request)throws Exception{
        //1.引入jasper文件。由JRXML模板编译生成的二进制文件,用于代码填充数据
        Resource resource = new ClassPathResource("templates/parent.jasper");
        //2.加载jasper文件创建inputStream
        FileInputStream isRef = new FileInputStream(resource.getFile());
        ServletOutputStream sosRef = response.getOutputStream();
        try {
            Map parameters = new HashMap();
            Resource subResource = new ClassPathResource("templates/testChart.jasper");
            //参数 子报表的路径 子报表的数据
            parameters.put("subPath", subResource.getFile().getPath());
            parameters.put("subList", getUserCountList());

            JasperPrint jasperPrint = JasperFillManager.fillReport(isRef, parameters, new JREmptyDataSource());
            //3.将JasperPrint已PDF的形式输出
            JasperExportManager.exportReportToPdfStream(jasperPrint,sosRef);
        } finally {
            sosRef.flush();
            sosRef.close();
        }
    }

    /**
     * 设置模拟数据
     * @return
     */
    public List<UserCount> getUserCountList() {
        List<UserCount> userCounts = new ArrayList<>();

        UserCount userCount01 = new UserCount("阿里巴巴", 1000L);
        UserCount userCount02 = new UserCount("百度", 900L);
        UserCount userCount03 = new UserCount("腾讯", 1200L);

        userCounts.add(userCount01);
        userCounts.add(userCount02);
        userCounts.add(userCount03);

        return userCounts;
    }

}

8.5 调用接口


结果如下:
在这里插入图片描述

8.6 样式修改


我们可以明显的看到子报表位置太靠右,原因如下:

父报表
在这里插入图片描述
子报表
在这里插入图片描述
两个报表都有很多空格,两个相加图形就很靠右了。解决方法:调整子报表图形的位置

在这里插入图片描述
重新编译子报表,导入项目。重启工程,结果如下:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_36662478/article/details/88700119