JasperReports 完整教程
目录
-
第一部分:初识 JasperReports
(图片来源网络,侵删)- 1 什么是 JasperReports?
- 2 核心概念
- 3 为什么选择 JasperReports?
- 4 环境准备
-
第二部分:你的第一个 JasperReport 报表
- 1 设计报表模板(.jrxml)
- 2 编译模板(.jasper)
- 3 填充数据(.jrprint)
- 4 导出报表
-
第三部分:报表设计详解
- 1 JasperReports 结构
- 2 常用设计元素
- 3 数据源
- 4 参数
- 5 变量
-
第四部分:进阶功能
- 1 子报表
- 2 分组与排序
- 3 图表
- 4 条件样式
- 5 脚本
-
第五部分:实战案例
(图片来源网络,侵删)- 1 案例一:从数据库生成简单列表报表
- 2 案例二:带分组的销售报表
- 3 案例三:使用子报表的订单详情报表
-
第六部分:集成与部署
- 1 在 Java Web 应用中集成
- 2 在 Spring Boot 中集成
-
第七部分:学习资源与最佳实践
第一部分:初识 JasperReports
1 什么是 JasperReports?
JasperReports 是一个功能强大的开源 Java 报表工具,它允许开发者以 XML 格式(.jrxml)设计报表模板,然后通过 Java 代码将数据填充到模板中,最终生成各种格式的报表,如 PDF、HTML、Excel、CSV 等。
它的核心思想是 “模板 + 数据 = 报表”。

2 核心概念
- Report Template (报表模板): 一个 XML 文件(
.jrxml),定义了报表的布局、样式、字段位置等,这是报表的“骨架”。 - Data Source (数据源): 提供报表所需数据的来源,可以是 Java 对象数组、
java.sql.Connection、JRBeanCollectionDataSource、CSV文件等。 - Parameters (参数): 传递给报表的值,用于报表的标题、过滤条件或作为子报表的连接参数,它们在报表执行时是只读的。
- Fields (字段): 代表数据源中每一条记录的单个数据项,如果数据源是
User对象列表,fieldsusername,email等。 - Variables (变量): JasperReports 在报表生成过程中计算出的值。
COUNT(计数)、SUM(求和)、TOTAL_PAGE(总页数)等。 - Compiled Report (编译后的报表): 将
.jrxml文件编译后生成的二进制文件(.jasper),这个文件包含了报表的所有设计信息和格式指令,可以被 JasperReports 引擎直接使用。
3 为什么选择 JasperReports?
- 功能强大: 支持复杂报表、交叉表、图表、子报表等。
- 格式多样: 可导出为 PDF、HTML、Excel、XML、CSV、ODT 等多种格式。
- 开源免费: 无需支付任何费用。
- 跨平台: 基于 Java,可在任何支持 Java 的平台上运行。
- 灵活: 可以轻松集成到任何 Java 应用程序(桌面、Web、移动)中。
4 环境准备
- JDK: 安装 JDK 8 或更高版本。
- IDE: 推荐使用 IntelliJ IDEA 或 Eclipse。
- JasperReports 库: 从 JasperReports 官网 下载最新的 JAR 包,或在 Maven 项目中添加依赖。
<!-- Maven 依赖 --> <dependency> <groupId>net.sf.jasperreports</groupId> <artifactId>jasperreports</artifactId> <version>6.20.6</version> <!-- 请使用最新版本 --> </dependency>
第二部分:你的第一个 JasperReport 报表
我们将创建一个简单的 "Hello World" 报表,它不依赖数据库,而是使用硬编码数据。
步骤 1: 设计报表模板 (.jrxml)
创建一个名为 report_template.jrxml 的文件,这是一个标准的 XML 文件。
<?xml version="1.0" encoding="UTF-8"?>
<!--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="MyFirstReport" pageWidth="595" pageHeight="842" whenNoDataType="AllSectionsNoDetail" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20">
<band height="50">
<staticText>
<reportElement x="0" y="0" width="555" height="50"/>
<textElement textAlignment="Center">
<font size="24" isBold="true"/>
</textElement>
<text><![CDATA[Hello JasperReports!]]></text>
</staticText>
</band>
</title>
<detail>
<band height="100">
<staticText>
<reportElement x="0" y="0" width="200" height="30"/>
<textElement>
<font size="16"/>
</textElement>
<text><![CDATA[这是我的第一个报表,]]></text>
</staticText>
</band>
</detail>
</jasperReport>
模板解释:
<jasperReport>: 根元素,定义报表的基本属性(页面大小、边距等)。<title>: 报表的标题带,通常出现在第一页的顶部。<band>: 报表中的一个带(或区域),有固定的高度。<staticText>: 静态文本,内容在编译时确定。<detail>: 报表的细节带,对于数据源中的每一条记录,这里的内容都会被渲染一次。
步骤 2: 编译模板
使用 Java 代码编译 .jrxml 文件,生成 .jasper 文件。
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperReport;
import java.io.File;
import java.io.InputStream;
public class CompileReport {
public static void main(String[] args) {
try {
// 加载 jrxml 文件(从 classpath)
InputStream jrxmlStream = CompileReport.class.getResourceAsStream("/report_template.jrxml");
// 编译 jrxml 文件,生成 jasper 文件
JasperReport jasperReport = JasperCompileManager.compileReport(jrxmlStream);
// (可选)将编译后的 jasper 文件保存到磁盘
JasperCompileManager.writeReportToFile("C:/temp/MyFirstReport.jasper", jasperReport);
System.out.println("报表编译成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
步骤 3: 填充数据
由于我们的报表没有使用数据源,这一步很简单,我们只需要创建一个空的 JasperPrint 对象。
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class FillReport {
public static void main(String[] args) {
try {
// 1. 加载编译后的报表文件
JasperReport jasperReport = (JasperReport) JRLoader.loadObject(new File("C:/temp/MyFirstReport.jasper"));
// 2. 准备参数 (Map)
Map<String, Object> parameters = new HashMap<>();
// 3. 准备数据源 (本例为空)
// JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(getData());
// 因为我们的报表没有字段,所以可以传 null
// 4. 填充报表
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, null);
System.out.println("报表填充成功!");
} catch (Exception e) {
e.printStackTrace();
}
// 下一步是导出...
}
// 一个示例数据源方法,用于后续例子
private static List<User> getData() {
List<User> users = new ArrayList<>();
users.add(new User("张三", 25, "北京"));
users.add(new User("李四", 30, "上海"));
users.add(new User("王五", 28, "广州"));
return users;
}
}
// POJO 类
class User {
private String name;
private Integer age;
private String city;
// 构造器、Getter 和 Setter
public User(String name, Integer age, String city) {
this.name = name;
this.age = age;
this.city = city;
}
public String getName() { return name; }
public Integer getAge() { return age; }
public String getCity() { return city; }
}
步骤 4: 导出报表
将填充好的 JasperPrint 对象导出为 PDF 文件。
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperPrint;
import java.io.File;
public class ExportReport {
public static void main(String[] args) {
try {
// 假设 jasperPrint 已经在 FillReport 步骤中生成
JasperPrint jasperPrint = FillReport.getJasperPrint(); // 需要修改 FillReport 使其返回 jasperPrint
// 导出为 PDF
JasperExportManager.exportReportToPdfFile(jasperPrint, "C:/temp/MyFirstReport.pdf");
System.out.println("报表导出成功!请查看 C:/temp/MyFirstReport.pdf");
} catch (Exception e) {
e.printStackTrace();
}
}
}
将以上四个步骤的代码整合起来,你就成功生成了你的第一个 JasperReports PDF 报表!
第三部分:报表设计详解
1 JasperReports 结构
一个典型的 .jrxml 文件结构如下:
<jasperReport ...>
<import>...</import> <!-- Java 类导入 -->
<style>...</style> <!-- 样式定义 -->
<parameter>...</parameter> <!-- 参数定义 -->
<field>...</field> <!-- 字段定义 -->
<variable>...</variable> <!-- 变量定义 -->
<queryString>...</queryString> <!-- SQL 查询语句 (用于 JDBC 数据源) -->...</title> <!-- 标题带 -->
<pageHeader>...</pageHeader> <!-- 页眉带 -->
<columnHeader>...</columnHeader> <!-- 列标题带 -->
<detail>...</detail> <!-- 细节带 -->
<columnFooter>...</columnFooter> <!-- 列脚带 -->
<pageFooter>...</pageFooter> <!-- 页脚带 -->
<summary>...</summary> <!-- 总结带 -->
</jasperReport>
2 常用设计元素
<staticText>: 静态文本。<textField>: 动态文本,用于显示字段、参数或变量的值。<textFieldExpression><![CDATA[$F{fieldName}]]></textFieldExpression>: 显示字段fieldName的值。<textFieldExpression><![CDATA[$P{parameterName}]]></textFieldExpression>: 显示参数parameterName的值。
<image>: 显示图片。<line>,<rectangle>,<ellipse>: 绘制图形元素。<frame>: 一个容器,可以包含其他元素,方便布局。
3 数据源
JasperReports 支持多种数据源:
-
JRBeanCollectionDataSource: 最常用的数据源之一,用于 Java 对象的集合。
List<User> users = ...; // 你的数据列表 JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(users);
-
JDBCConnectionDataSource: 直接使用数据库连接。
Connection conn = DriverManager.getConnection(url, user, password); JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, conn);
-
JRBeanArrayDataSource: 用于 Java 对象数组。
-
JRMapCollectionDataSource: 用于
Map对象的集合,Map的 key 对应报表的 field name。
4 参数
参数在报表设计时定义,在填充时传入。
在 .jrxml 中定义参数:
<parameter name="ReportTitle" class="java.lang.String">
<defaultValueExpression><![CDATA["客户列表"]]></defaultValueExpression>
</parameter>
在 Java 中传入参数:
Map<String, Object> parameters = new HashMap<>();
parameters.put("ReportTitle", "年度客户报表");
在报表中使用参数:
<staticText>
<reportElement x="0" y="0" width="200" height="30"/>
<textElement/>
<text><![CDATA[$P{ReportTitle}]]></text>
</staticText>
5 变量
变量用于在报表生成过程中进行计算。
在 .jrxml 中定义变量:
<variable name="TotalAge" class="java.lang.Integer" calculation="Sum">
<variableExpression><![CDATA[$F{age}]]></variableExpression>
</variable>
变量计算类型:
Sum: 求和Count: 计数Average: 平均值Highest: 最大值Lowest: 最小值
在报表中使用变量:
<textField>
<reportElement x="400" y="0" width="100" height="30"/>
<textElement/>
<textFieldExpression><![CDATA[$V{TotalAge}]]></textFieldExpression>
</textField>
第四部分:进阶功能
1 子报表
子报表是嵌入到主报表中的一个独立报表,常用于显示一对多的关系,例如一个订单(主报表)包含多个订单项(子报表)。
步骤:
- 分别设计主报表模板(
.jrxml)和子报表模板(.jrxml),并编译它们。 - 在主报表中,使用
<subreport>元素。 - 使用参数传递数据给子报表。
主报表中的 <subreport> 元素:
<subreport>
<reportElement x="0" y="50" width="500" height="100"/>
<!-- 指定子报表的 .jasper 文件路径 -->
<subreportExpression><![CDATA["C:/temp/OrderItems.jasper"]]></subreportExpression>
<!-- 传递参数给子报表 -->
<subreportParameterExpression>
<map>
<entry key="OrderId" value="$F{orderId}"/>
</map>
</subreportParameterExpression>
</subreport>
2 分组与排序
使用 <group> 元素可以对数据进行分组。
<group name="GroupByCity">
<groupExpression><![CDATA[$F{city}]]></groupExpression> <!-- 分组表达式 -->
<groupHeader>
<band height="30">
<staticText>
<reportElement x="0" y="0" width="100" height="30"/>
<textElement/>
<text><![CDATA["城市: " + $V{GROUP_NAME}]]></text> <!-- GROUP_NAME 是内置变量 -->
</staticText>
</band>
</groupHeader>
<groupFooter>
<band height="20">
<!-- 可以在这里放分组的总结信息,如小计 -->
</band>
</groupFooter>
</group>
3 图表
JasperReports 内置了对 JFreeChart 的支持,可以轻松添加图表。
- 在
.jrxml中添加<chart>元素。 - 使用
<pieChart>,<barChart>,<lineChart>等定义图表类型。 - 使用
<categorySeries>或<pieSeries>定义数据系列,数据源通常是报表的变量。
4 条件样式
可以使用 ConditionalStyle 为元素(如文本、单元格)设置动态样式。
<textField>
<reportElement x="100" y="0" width="100" height="20"/>
<textElement/>
<textFieldExpression><![CDATA[$F{age}]]></textFieldExpression>
<!-- 条件样式 -->
<conditionalStyle>
<conditionExpression><![CDATA[$F{age} > 30]]></conditionExpression>
<style mode="Opaque" backcolor="#FFCCCC"/> <!-- 年龄大于30岁时,背景变红 -->
</conditionalStyle>
</textField>
5 脚本
JasperReports 支持 Java 代码片段,可以在报表生命周期的特定时刻执行(如 report、column、band、element 级别)。
<report ... scriptletClass="com.example.MyScriptlet">
...
</report>
MyScriptlet.java:
import net.sf.jasperreports.engine.JRDefaultScriptlet;
import net.sf.jasperreports.engine.JRScriptlet;
public class MyScriptlet extends JRDefaultScriptlet {
@Override
public void afterGroupInit(String groupName) {
// 在组初始化后执行
System.out.println("Group " + groupName + " initialized.");
}
}
第五部分:实战案例
从数据库生成简单列表报表
目标: 从数据库查询用户列表,并生成 PDF 报表。
-
创建
users表:CREATE TABLE users ( id INT PRIMARY KEY, name VARCHAR(100), email VARCHAR(100), registration_date DATE ); -
设计
UserList.jrxml:- 定义字段:
id,name,email,registration_date。 - 在
<detail>带中使用<textField>显示这些字段。
- 定义字段:
-
编写 Java 代码:
import net.sf.jasperreports.engine.*; import net.sf.jasperreports.engine.util.JRLoader; import java.sql.Connection; import java.sql.DriverManager; import java.util.HashMap; import java.util.Map; public class DatabaseReport { public static void main(String[] args) { String jdbcUrl = "jdbc:mysql://localhost:3306/your_database"; String user = "your_username"; String password = "your_password"; String jrxmlPath = "UserList.jrxml"; String jasperPath = "UserList.jasper"; String pdfPath = "UserList.pdf"; try (Connection conn = DriverManager.getConnection(jdbcUrl, user, password)) { // 1. 编译 jrxml JasperReport jasperReport = JasperCompileManager.compileReport(jrxmlPath); // 2. 准备参数 Map<String, Object> parameters = new HashMap<>(); // 3. 填充报表 (直接使用 Connection) JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, conn); // 4. 导出 PDF JasperExportManager.exportReportToPdfFile(jasperPrint, pdfPath); System.out.println("数据库报表生成成功!"); } catch (Exception e) { e.printStackTrace(); } } }
第六部分:集成与部署
1 在 Java Web 应用中集成
通常使用 JasperReports 的 servlet 来处理报表的显示和导出。
-
配置
web.xml:<servlet> <servlet-name>JasperReportServlet</servlet-name> <servlet-class>net.sf.jasperreports.j2ee.servlets.ImageServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>JasperReportServlet</servlet-name> <url-pattern>/report/image</url-pattern> </servlet-mapping> -
创建 JSP 页面:
- 一个表单,用于输入报表参数和选择导出格式。
- 使用
<iframe>或<img>标签来显示由另一个 servlet 生成的 HTML 或图片报表。
-
创建报表生成 Servlet:
- 获取请求参数。
- 连接数据库,填充报表。
- 根据
format参数(如html,pdf)调用相应的导出方法,并将结果写入response的输出流中。
2 在 Spring Boot 中集成
Spring Boot 与 JasperReports 集成非常方便。
-
添加依赖:
<dependency> <groupId>net.sf.jasperreports</groupId> <artifactId>jasperreports</artifactId> <version>6.20.6</version> </dependency> -
创建报表工具类:
@Service public class JasperReportService { public byte[] exportReport(String reportName, Map<String, Object> parameters, List<?> data) throws JRException { // 加载编译后的报表文件 InputStream jasperStream = this.getClass().getResourceAsStream("/reports/" + reportName + ".jasper"); JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(data); JasperPrint jasperPrint = JasperFillManager.fillReport(jasperStream, parameters, dataSource); return JasperExportManager.exportReportToPdf(jasperPrint); } } -
创建 Controller:
@RestController @RequestMapping("/api/reports") public class ReportController { @Autowired private JasperReportService reportService; @GetMapping(value = "/users", produces = MediaType.APPLICATION_PDF_VALUE) public ResponseEntity<byte[]> generateUserReport() { try { List<User> users = userService.findAllUsers(); // 从你的Service获取数据 Map<String, Object> parameters = new HashMap<>(); parameters.put("ReportTitle", "用户列表"); byte[] pdfBytes = reportService.exportReport("UserList", parameters, users); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_PDF); headers.setContentDisposition(ContentDisposition.builder("attachment").filename("user_list.pdf").build()); return new ResponseEntity<>(pdfBytes, headers, HttpStatus.OK); } catch (Exception e) { return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } }
第七部分:学习资源与最佳实践
学习资源
- 官方文档: JasperReports 官方文档 (最权威,但英文)
- 示例项目: 官方网站提供了大量
.jrxml示例,是学习设计技巧的绝佳资源。 - 社区: JasperSoft Community
- 博客和教程: 搜索 "JasperReports tutorial" 可以找到很多中文和英文的博客文章和视频教程。
最佳实践
- 版本控制: 将
.jrxml文件(而不是.jasper文件)纳入版本控制系统(如 Git),这样团队可以协作修改报表设计。 - 报表分离: 将报表模板文件(
.jrxml)放在项目的src/main/resources/reports目录下,便于管理和部署。 - 使用 DTO (Data Transfer Object): 不要直接将 JPA/Hibernate 实体对象作为报表数据源,创建专门的 DTO 类,只包含报表需要的字段,这可以避免
LazyInitializationException并提高性能。 - 缓存编译后的报表: 对于频繁使用的报表,缓存
.jasper文件可以避免每次请求都重新编译,提升性能。 - 性能优化: 对于大数据量报表,考虑使用 SQL 查询进行数据预处理(如分组、求和),而不是在 JasperReports 变量中计算,以减轻 JVM 的压力。
- 模块化: 对于复杂的报表,尽量使用子报表、图表和参数来模块化设计,使主报表更清晰。
希望这份详细的教程能帮助你从入门到精通 JasperReports!祝你学习愉快!
