iReport 5.6.0 + Jasper 6.8.0 报表生成
一、iReport和Jasper介绍
Jasper:
JasperReport是一个强大、灵活的报表生成工具,能够展示丰富的页面内容,并将之转换成PDF,HTML,或者XML格式。该库完全由Java写成,可以用于在各种Java应用程序,包括J2EE,Web应用程序中生成动态内容。
iReport:
iReport 是为JasperReports Library和JasperReports Server设计的报表可视化设计器
二、 iReport的使用
1. iReport下载
iReport可以到社区里下载:
https://sourceforge.net/projects/ireport/files/iReport/iReport-5.6.0/
推荐下载zip版本的
下载完成后,解压到本地,目录结构如图(其中jdk1.7是我自己解压进去的 原始zip包并不包含):
iReport 5.6.0 由于历史久远,最多支持jdk到1.7 ,如果你的本地jdk环境是1.8,打开会闪退; 所以需要自行准备jdk1.7 。
2. 配置JDK
用记事本打开etc目录下的ireport.conf,修改jdkhome为jdk1.7的根目录。
3. 配置数据源
然后输入本地数据库的url,数据库用户名,数据库密码, 输入完成后,点击Test
如果出现Connection test successful,说明数据库配置的没问题
注意: iReport 只提供了少量的JdbcDriver,比如Oracle驱动它就没有,需要自行导入, 导入步骤:
(a)将要导入的JdbcDriver复制到libs目录下,D:\iReport-5.6.0\ireport\libs
(b)工具-选项,按照如图所示步骤添加JdbcDriver的jar包
此时就可以看到添加数据源时,Oracle的驱动可以用了
4. 创建模板
(1)选择预设模板
因为是入门Demo,我们选择空白的A4即可,选择完后 点击"Open this Templete"
选择工作的workspace,填写完模板名,点击下一步-完成
(2)编辑模板
step1:选择数据源
点击OK后,可以看到我们左侧的Fileds里出现了刚添加sql的字段, 如果需要多表联表查询,查询出的字段也会出现在这里
step2:编辑样式
比如说我们要做一个简单的demo报表,就是加一个报表头,然后把数据库的数据展示出来,我们可以把不需要的编辑栏进行删除,右键"Delete Band" 删除
标题是静态文本,我们选择Static Text,拖到Title里
依次类推,把列名的静态文本加入到 “Column Header” 里
当然我们可以在列名和数据之间加一条线作为区分
Line的pen属性可以选择分割线的样式
step3:填充数据
我们现在需要把数据填充进去,此时拖着Fields里刚才配置的字段到指定位置即可,填写完后,点击Preview即可预览PDF。
(3)文本换行处理
有时我们会遇到,给定的区域太小,但是文本有特别多情况,这样如果文本超出了区域,超出的部分将被截取,不再显示,如:
我们需要它换行显示,则需要设置该文本的几项属性:
这样文本就会换行显示了:
三、Java集成Jasper
1.引入Pom依赖
新建工程,在pom中添加依赖:
<!-- jasper报表依赖 -->
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>6.8.0</version>
<exclusions>
<exclusion>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>2.1.7</version>
</dependency>
<dependency>
<groupId>cn.lesper</groupId>
<artifactId>iTextAsian</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.15</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
</dependency>
</dependencies>
2. Java代码的编写
这里给出一个简单的例子
package com.demo.jasper;
import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.fill.JRAbstractLRUVirtualizer;
import net.sf.jasperreports.engine.fill.JRGzipVirtualizer;
import net.sf.jasperreports.engine.util.JRLoader;
import net.sf.jasperreports.export.ExporterInput;
import net.sf.jasperreports.export.OutputStreamExporterOutput;
import net.sf.jasperreports.export.SimpleExporterInput;
import net.sf.jasperreports.export.SimpleOutputStreamExporterOutput;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Properties;
/**
* @author zhang_hr
* @date 2021/8/17 11:29
* @description Jasper工具类
**/
public class JasperUtils {
/**
* 编译jrxml格式文件
*
* @param jrXmlPath jrxml文件路径
* @param jasperPath jasper文件路径
*/
public static void compileJrXml(String jrXmlPath, String jasperPath) {
try {
// 如果文件夹不存在 先创建文件夹
File jasperDir = new File(jrXmlPath);
if (!(jasperDir.exists())) {
jasperDir.mkdirs();
}
JasperCompileManager.compileReportToFile(jrXmlPath, jasperPath);
} catch (JRException e) {
e.printStackTrace();
}
}
/**
* 根据jasper模板生成pdf报表
*
* @param jasperPath jasper模板路径
* @param reportPath pdf报表生成路径
* @param parameter 参数集合
* @param connection 数据库连接
*/
public static void creatReport(String jasperPath, String reportPath,
HashMap<String, Object> parameter, Connection connection) {
InputStream inputStream = null;
OutputStreamExporterOutput exporterOutput = null;
try {
// 1.加载jasper文件
JasperReport jasperReport;
// 使用FileInputStream时jasperPath要使用绝对路径
inputStream = new FileInputStream(new File(jasperPath));
// springboot项目中使用以下这个,jasperPath填写resources的相对路径
// 如在resources的jasper目录下的demo.jasper jasperPath填写"jasper/demo.jasper"即可
// inputStream = JasperUtils.class.getResourceAsStream(jasperPath);
if (inputStream == null) {
throw new IllegalArgumentException("jasper inputStream is null");
}
jasperReport = (JasperReport) JRLoader.loadObject(inputStream);
// 2.设置参数
JRAbstractLRUVirtualizer virtualizer = new JRGzipVirtualizer(2);
parameter.put(JRParameter.REPORT_VIRTUALIZER, virtualizer);
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameter, connection);
// 3.报表输入设置
ExporterInput exporterInput = new SimpleExporterInput(jasperPrint);
File file = new File(reportPath);
if (file.exists()) {
file.delete();
}
if (!file.getParentFile().exists() && !file.getParentFile().mkdirs()) {
throw new RuntimeException("create dir failed");
}
exporterOutput = new SimpleOutputStreamExporterOutput(file);
// 4.使用导出器导出pdf
JRPdfExporter pdf = new JRPdfExporter();
pdf.setExporterInput(exporterInput);
pdf.setExporterOutput(exporterOutput);
pdf.exportReport();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if (exporterOutput != null) {
exporterOutput.close();
}
}
}
/**
* 获得带注释的数据库连接
*
* @param url 数据库地址
* @param username 数据库用户名
* @param password 数据库密码
* @return 数据库连接
*/
public static Connection getConnection(String url, String username, String password) {
Connection conn = null;
Properties props = new Properties();
try {
props.setProperty("user", username);
props.setProperty("password", password);
props.setProperty("remarks", "true"); //设置可以获取remarks信息
props.setProperty("useInformationSchema", "true");//设置可以获取tables remarks信息
conn = DriverManager.getConnection(url, props);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public static void main(String[] args) throws SQLException {
// 1.编译jrxml
compileJrXml("D:\\iReport-5.6.0\\wokrspace\\jasper-demo.jrxml",
"D:\\iReport-5.6.0\\wokrspace\\1.jasper");
// 2.生成pdf
Connection connection = getConnection("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF8",
"root", "123");
try {
creatReport("D:\\iReport-5.6.0\\wokrspace\\1.jasper", "d:/test/666.pdf", new HashMap<String, Object>(),
connection);
} finally {
connection.close();
}
}
}
打开生成的paf,发现中文不显示
3.中文字符不显示或者乱码解决方案
将图中标记的两处分别选择 :
STSong-Light
UniGB-UCS2-H (Chinese Simplified)
修改过后,重新生成pdf,发现中文字符可以显示了。
4.Jasper附带参数
此时java代码需要修改传入的HashMap
public static void main(String[] args) throws SQLException {
// 1.编译jrxml
compileJrXml("D:\\iReport-5.6.0\\wokrspace\\jasper-demo.jrxml",
"D:\\iReport-5.6.0\\wokrspace\\1.jasper");
// 2.生成pdf
Connection connection = getConnection("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF8",
"root", "123");
try {
HashMap<String, Object> params = new HashMap<String, Object>();
params.put("price","120");
creatReport("D:\\iReport-5.6.0\\wokrspace\\1.jasper", "d:/aaaaaa/666.pdf",params,
connection);
} finally {
connection.close();
}
}
生成的pdf可以根据传入的条件进行显示了,并且是升序排列
5. 常见问题(FAQ)
(1)查询数据列表为空,PDF显示空白页
解决方案:
在iReport界面,右键报表-属性-when no data,选择 "All sections,No Detail "即可,即使查询不到数据,也会导出PDF模板样式。
(2)查询字段为空,报表显示null
解决方案: 字段属性里选中 “blank when null” 即可
(3)多表联表查询
多表联表查询是报表里经常碰到的问题,一般会根据条件进行联表查询, 比如说我们有两张表book、book_type
book表:
id 主键
name 书名
price 价格
book_type表:
id 主键
name 书名
type 书籍种类 || a-科普类 b-历史类 c-故事类 d-其他类
现在我们的需求:
1.把两个表根据name字段来连起来
2.book_type表的type字段要转义
3.获得记录的总条数
4.生成从1开始的自增序列id
5.根据id增序排列
6.要指定价格
7.书籍的价格要保留两位小数(整数的话要输出xxx.00)
其实就是考验sql的基本功(我的sql写的比较烂,各位大神有更好的方式欢迎留言):
SELECT @ROW:=@ROW+1 as id,t1.name,format(t1.price,2) as price,
case
when t2.type='a' then '科普类'
when t2.type='b' then '历史类'
when t2.type='c' then '故事类'
else '其他类' end as type,
(select count(1) from book,book_type where book.name = book_type.name and book.price = '150') as total_num
from book t1,book_type t2,(select @ROW:=0) t3
where t1.name = t2.name and t1.price = '150'
order by id asc;
跟上文描述步骤一样,修改SQL、添加参数
修改报表模板:
运行jJava代码,生成pdf报表: