0. 示例代码
示例代码地址
1. 报表介绍
1.1 为什么要使用报表?
在企业级应用开发中,报表生成、报表打印下载是其重要的一个环节。除了
Excel
报表之外,
目前世面上比较流行的制作PDF
报表的工具如下:
名称 | 介绍 |
---|---|
Jasper Report | 是一个强大、灵活的报表生成工具,能够展示丰富的页面内容,并将之转换成PDF |
Openoffice | openoffice是开源软件且能在windows和linux平台下运行,可以灵活的将word或者Excel转化为PDF文档。 |
iText PDF | iText是著名的开放项目,是用于生成PDF文档的一个java类库。通过iText不仅可以生成PDF或rtf的文档,而且可以将XML、Html文件转化为PDF文件。 |
2. JasperReport
2.1 框架介绍
- 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就能生成最终用户想要的文档格式。
2.2 相关文件介绍
JRXML
:报表填充模板,本质是一个XML. JasperReport已经封装了一个dtd,只要按照规定的格式写这个xml文件,那么jasperReport就可以将其解析最终生成报表,但是jasperReport所解析的不是我们常见的.xml文件,而是.jrxml文件,其实跟xml是一样的,只是后缀不一样。Jasper
:**由JRXML模板编译生成的二进制文件,用于代码填充数据。**解析完成后JasperReport就开始编译.jrxml文件,将其编译成.jasper文件,因为JasperReport只可以对.jasper文件进行填充数据和转换,这步操作就跟我们java中将java文件编译成class文件是一样的Jrprint
:**当用数据填充完Jasper后生成的文件,用于输出报表。**这一步才是JasperReport的核心所在- 它会根据你在xml里面写好的查询语句来查询指定是数据库
- 也可以控制在后台编写查询语句,参数,数据库。在报表填充完后,会再生成一个.jrprint格式的文件(读取jasper文件进行填充,然后生成一个jrprint文件)
Exporter
:决定要输出的报表为何种格式,报表输出的管理类。
2.3 开发流程概述
2.4 模板工具Jaspersoft Studio
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.4.1 Jaspersoft Studio CE下载
我下载的是js-studiocomm_6.20.5_windows_x86_64.exe
下载完成后无脑安装就行了
2.4.2 面板介绍
左侧切换outline
视图,调整视图的位置
-
Report editing area(主编辑区域) 通过拖动,定位,对齐和通过 Designer palette(设计器调色板)对报表元素调整大小
-
Editor Area
- Design tab: 当你打开一个报告文件,它允许您以图形方式创建报表选中
- Source tab: 包含用于报表的 JRXML 源代码。
- Preview tab: 允许在选择数据源和输出格式后,运行报表预览。
-
Repository Explorer view 包含 JasperServer 生成的连接和可用的数据适配器列表
-
Outline view 在大纲视图中显示了一个树的形式的方式报告的完整结构
-
Properties view 控件属性设置
-
Design tab 以图形方式创建报表中的控件
-
Report Editor Area介绍
Title
(标题)😗*只在整个报表的第一页的最上端显示。**只在第一页显示,其他页面均不显示Page Header
(页头):在整个报表中每一页都会显示。- 在第一页中,出现的位置在 Title Band的下面。
- 在除了第一页的其他页面中Page Header 的内容均在页面的最上端显示。
Page Footer
(页脚): **在整个报表中每一页都会显示。**显示在页面的最下端。一般用来显示页码。Detail1
(详细) : 报表内容,每一页都会显示。Column Header
(列头): Detail中打印的是一张表的话,这Column Header就是表中列的列头。Column Footer
(列脚) :Detail中打印的是一张表的话,这Column Footer就是表中列的列脚。Summary
(统计): 表格的合计段,出现在整个报表的最后一页中,在Detail 1 Band后面。主要是用来做报表的合计显示。
2.4.3 Paramter,Field和Detail基本组件介绍
2.4.3.1 Paramters
- Paramters是一张报表中全局的属性,初始自带了一些属性,也可以自定义属性。大家可以理解为存放一个报表的表头数据
- Paramter的属性可以是任何类型,String,Long,Double,List等等
- Paramter可以用在报表的任何区域,一般用在报表的
Title
,Page Header
,Page Footer
区域
-
Paramters的创建:在左侧的Outline框,在Paramters上右键 Create Paramter 就可以创建一个新的Paramter,在右侧可以设置名称和类型。使用时直接拖拽到相应的区域即可。如下图所示
-
在Java程序中可以通过给对应的Paramter赋值,在打印时就可以输出你想要的结果。代码如下所示
//给Paramter赋值 HashMap<String, Object> parameters = new HashMap<String, Object>(); parameters.put("name", "小明");//这里的key要和报表中的Paramter的name对应 parameters.put("age", "18"); //中间代码省略 //核心代码,把Paramters传入JasperReport提供的方法,并返回JasperPrint 对象 JasperPrint jasperPrint = JasperFillManager.fillReport(jasperStream, parameters, dataSource);
2.4.3.2 Fields
- Fields是报表中数据集合中的字段属性,只能自定义Field字段。大家可以理解为一个报表的明细列表数据
- Field的属性可以是任何类型,String,Long,Double,List等等
- Field只能用在报表的
Detail
区域
-
Fields的创建:在左侧的Outline框,在Fields上右键 Create Field 就可以创建一个新的Field,在右侧可以设置名称和类型。使用时直接拖拽到相应的区域即可。如下图所示
-
在Java程序中可以通过集合给集合中的每一条数据的Field字段赋值,在打印时就可以输出你想要的结果。代码如下所示
//给Field赋值 List<HashMap> list = new ArrayList<>(); for (int i = 0; i < 100; i++) { HashMap<String, String> item = new HashMap<String, String>(); item.put("Field1", "Field1-" + i); item.put("Field2", "Field2-" + i); item.put("Field3", "Field3-" + i); item.put("Field4", "Field4-" + i); item.put("Field5", "Field5-" + i); list.add(item); } //中间代码省略 //核心代码,用包含Field字段的集合创建一个JRDataSource,传入JasperReport提供的方法,并返回JasperPrint 对象 JRDataSource dataSource = new JRBeanCollectionDataSource(list); JasperPrint jasperPrint = JasperFillManager.fillReport(jasperStream, parameters, dataSource);
2.4.3.3 Detail
- Detail是打印Field字段的区域,一个报表可以有多个Detail,在Detail上右键可以通过Add Detail Band来增加新的Detail区
- Detail会把传递进来的list的数据,循环打印出来,有多条就会打印多行,一页打印不下就会从下一页继续打印
- 如果通过Detail来打印表格,Detail的高度最好和要打印的Field高度一样,这样每行就不会有缝隙,打印出来和表格一样的效果
- 如果存在多个detail,他们是交替打印
2.4.4 动态组件常用的属性的用法
-
所有动态的组件都是通过Expression表达式来绑定要打印的数据,比如Paramter,Field,Image,Table组件等等。
-
所有组件都有一块
Print When属性
,**其中有一个Print When Expression表达式,可以在返回true的情况下打印,在false的情况下不打印。**这个表达式可以依赖其他Paramter,Field,可以通过它实现一些特殊的打印需求- 表达式例子:
new Boolean($F{showtitle1})
,new Boolean(true)
- 表达式参考
- 表达式例子:
2.5 springBoot 整合JasperReport基础案例(固定报表)
2.5.1 引入依赖
创建一个springBoot项目
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>site.zhourui</groupId>
<artifactId>jasper-report-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>jasper-report-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Jasper所需jar -->
<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>
<!-- 根据情况添加数据库驱动 -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.4.1</version>
</plugin>
</plugins>
</build>
</project>
2.5.2 模板制作
-
创建
jasper
文件:File
->New
->Jasper Report
我选择的空白A4
-
制作模版
-
点击
Compile Repot
生成Jasper
文件 -
找到编译后的.jasper文件
编译完成后在下方控制台会提示文件生成地址
-
找到文件将文件复制到springboot的templates目录下改名为demo.jasper
2.5.3 创建测试Controller
package site.zhourui.jasperreportdemo.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.RequestMapping;
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;
/**
* @author zr
* @date 2023/7/20 14:52
*/
@RestController
@RequestMapping("/jasper")
public class demoController {
/**
* JasperReport的简单使用
*/
@GetMapping("/test1")
public void createHtml(HttpServletResponse response, HttpServletRequest request) throws Exception {
Resource resource = new ClassPathResource("templates/demo.jasper");
FileInputStream is = new FileInputStream(resource.getFile());
ServletOutputStream os = response.getOutputStream();
try {
/**
* 创建JasperPrint对象
* 数据填充
* is:inputstream params:参数填充 DataSource:数据源填充
*/
JasperPrint jasperPrint = JasperFillManager.fillReport(is, new HashMap<>(), new JREmptyDataSource());
// 写入pdf数据
JasperExportManager.exportReportToPdfStream(jasperPrint, os);
} finally {
os.flush();
os.close();
}
}
}
访问http://localhost:8080/jasper/test1
2.5.4 JasperReports 不显示中文问题及解决方案
2.5.4.1 问题展示
-
新增了一个带中文Static Text
-
再次生成Jasper文件demo2.Jasper放入templates目录下
-
测试访问http://localhost:8080/jasper/test1
新增的Text英文展示出来了,但是中文没有展示出来
2.5.4.2 问题原因
jasperreports的jar包源码中不包含中文字体库。
2.5.4.3 解决方案(添加中文字体库)
-
在JasperReport Studio工具的Window-> Preferences -> font 中add一个微软雅黑的字体
我下载字体的位置
-
此时就可以选择我们添加的字体了(注意这里有两个微软雅黑要选我们自定义的那个)
-
然后我们就可以保存文件重新编译一次然后放入templates目录下改名为demo.jasper
-
在Jaspersoft Studio 打包字体文件Font.jar包
-
Jaspersoft Studio中打包Font.jar,步骤如下: Window -> Preferences -> Jaspersoft Studio -> Fonts->Export
-
-
将导出的font.jar导入项目依赖
-
通过maven引入
-
maven打包
注意:你的文件路径可能和我的不一样
mvn install:install-file -Dfile=C:\Users\Administrator\JaspersoftWorkspace\MyReports\font\font.jar -DgroupId=site.zhourui.report -DartifactId=font -Dversion=1.0.0 -Dpackaging=jar
-
maven 引入依赖
<dependency> <groupId>site.zhourui.report</groupId> <artifactId>font</artifactId> <version>1.0.0</version> </dependency>
-
也可以推送到maven远程仓库这个看你自己
-
-
通过Add as Library引入
-
只要保证 fonts.jar 在项目的 classpath 中即可!我放到在
resources
下面 -
然后点击鼠标右键
-
选择Classes
-
设置名称和适用范围等
-
-
-
访问测试http://localhost:8080/jasper/test2
2.5.5 Java-map(parameter)的方式传入参数
-
新增两个参数
year
,name
-
创建模板使用我们创建的参数
-
模板
如果是内容中文记住更换字体
生成Jasper文件demo3.Jasper放入templates目录下
-
新建测试方法
之前传的是一个空的HashMap
现在传入对应的值
/** * JasperReport携带参数 * @param response * @throws Exception */ @RequestMapping("/test3") public void test3(HttpServletResponse response) throws Exception{ Resource resource = new ClassPathResource("templates/demo3.jasper"); FileInputStream is = new FileInputStream(resource.getFile()); ServletOutputStream os = response.getOutputStream(); Map<String, Object> parameters = new HashMap<String, Object>(); parameters.put("year", "2023"); parameters.put("name", "测试"); try { /** * 创建JasperPrint对象 * 数据填充 * is:inputstream params:参数填充 DataSource:数据源填充 */ JasperPrint jasperPrint = JasperFillManager.fillReport(is, parameters, new JREmptyDataSource()); // 写入pdf数据 JasperExportManager.exportReportToPdfStream(jasperPrint, os); } finally { os.flush(); os.close(); } }
-
访问测试
测试链接http://localhost:8080/jasper/test3
2.5.6 Java-List(Failed)的方式传入参数,并打印多页表单
-
制作模板
4个属性
如果有中文注意选择字体
-
生成Jasper文件demo3.Jasper放入templates目录下
-
新建测试方法
/** * JasperReport携带参数 ,打印多页表单 * @param response * @throws Exception */ @RequestMapping("/test4") public void test4(HttpServletResponse response) throws Exception{ Resource resource = new ClassPathResource("templates/demo4.jasper"); FileInputStream is = new FileInputStream(resource.getFile()); ServletOutputStream os = response.getOutputStream(); Random random = new Random(); List<HashMap> list = new ArrayList<>(); for (int i = 0; i < 100; i++) { HashMap<String, String> item = new HashMap<String, String>(); item.put("Field_1", "员工-" + i); item.put("Field_2", "部门-" + i); item.put("Field_3", i%2==0?"男":"女"); item.put("Field_4", String.valueOf(random.nextInt(10000 - 8000) + 8000 + 1));//8000-10000 list.add(item); } JRDataSource dataSource = new JRBeanCollectionDataSource(list); try { /** * 创建JasperPrint对象 * 数据填充 * is:inputstream params:参数填充 DataSource:数据源填充 */ JasperPrint jasperPrint = JasperFillManager.fillReport(is, new HashMap<>(), dataSource); // 写入pdf数据 JasperExportManager.exportReportToPdfStream(jasperPrint, os); } finally { os.flush(); os.close(); } }
-
测试效果 访问http://localhost:8080/jasper/test4