发布于2026-07-26 阅读(0)
扫一扫,手机访问
在Ja va报表领域,JasperReports是一个绕不开的名字。下面从几个方面来深入解析,看看它到底是什么、怎么用,以及如何在实际项目中落地。
JasperReports 是 Ja va 生态中最流行的开源报表引擎,专门用于生成格式化的文档(PDF、Excel、Word、HTML、CSV 等)。它的核心价值是将数据和模板分离,通过模板定义报表样式,运行时填充数据后生成最终文档。

Word 邮件合并: 模板(.docx)+ 数据(Excel联系人) → 批量生成信件 JasperReports: 模板(.jrxml/.jasper)+ 数据(数据库/Ja va对象) → 批量生成 PDF/Excel/HTML
| 场景 | 示例 |
|---|---|
| 发货单打印 | 选中订单 → 生成 PDF 发货单(含条码/表格/签章) |
| 财务报表 | 月度销售汇总 → 导出 Excel |
| 物流面单 | 快递单/运单 → 生成固定格式 PDF 批量打印 |
| 库存盘点表 | 仓库商品清单 → 导出打印 |
| 对账单 | 供应商对账 → 生成 PDF 发送邮件 |
| 概念 | 说明 | 文件格式 |
|---|---|---|
| JRXML | 报表模板源文件,XML 格式,定义报表布局和样式 | .jrxml |
| Jasper | 编译后的模板文件(二进制),运行时直接加载 | .jasper |
| JasperPrint | 填充数据后的内存报表对象,可导出为各种格式 | 内存对象 |
| DataSource | 数据源,为报表提供数据(JDBC/Ja va集合/JSON等) | - |
| Parameter | 报表参数,从外部传入的变量(如标题、日期、Logo等) | - |
| Field | 数据字段,对应数据源中每条记录的列 | - |
| Band | 报表区域/带区(页眉/列头/明细/页脚/汇总等) | - |
┌─────────────────────────────────────────┐ │ Title Band(标题区) │ ← 整个报表只出现一次 ├─────────────────────────────────────────┤ │ Page Header(页眉) │ ← 每页顶部 ├─────────────────────────────────────────┤ │ Column Header(列标题) │ ← 表格列名 ├─────────────────────────────────────────┤ │ Detail Band(明细区) │ ← 每条数据重复一次 │ ┌────┬──────┬────┬──────┬─────┐ │ │ │序号│ 商品名 │数量│ 单价 │ 金额 │ │ │ ├────┼──────┼────┼──────┼─────┤ │ │ │ 1 │冰箱 │ 2 │3999 │7998 │ │ │ │ 2 │洗衣机 │ 1 │2999 │2999 │ │ │ │... │... │... │... │... │ │ │ └────┴──────┴────┴──────┴─────┘ │ ├─────────────────────────────────────────┤ │ Column Footer(列汇总) │ ← 合计行 ├─────────────────────────────────────────┤ │ Page Footer(页脚) │ ← 每页底部(页码等) ├─────────────────────────────────────────┤ │ Summary(总汇总) │ ← 整个报表最后 └─────────────────────────────────────────┘
设计阶段(开发时):
Jaspersoft Studio 设计模板 → 保存为 .jrxml 文件
│
▼
编译模板:JasperCompileManager.compileReport() → .jasper 文件
│
▼(部署到项目 resources 目录)
运行阶段(运行时):
加载 .jasper 模板
│
▼
填充数据:JasperFillManager.fillReport(模板, 参数, 数据源) → JasperPrint
│
▼
导出文档:JasperExportManager.exportReportToPdf(jasperPrint) → PDF/Excel/HTML
│
▼
返回给前端下载/预览/打印
Controller 接收请求(如:打印发货单) │ ├─→ Service 查询数据库获取发货单数据 │ └── List数据集 │ ├─→ 组装参数 Map(标题、公司名、打印日期等) │ ├─→ 创建数据源 JRBeanCollectionDataSource(数据集) │ ├─→ 加载模板 .jasper(从 classpath 或数据库) │ ├─→ JasperFillManager.fillReport(模板, 参数, 数据源) │ └── → JasperPrint(内存中的完整报表) │ ├─→ 导出为目标格式 │ ├── PDF:JasperExportManager.exportReportToPdfStream() │ ├── Excel:JRXlsxExporter │ ├── Word:JRDocxExporter │ └── HTML:HtmlExporter │ └─→ 写入 HttpServletResponse 输出流 └── 前端收到文件下载/预览
| 知识点 | 说明 |
|---|---|
| Jaspersoft Studio | Eclipse 插件形式的可视化模板设计器(拖拽式) |
| JRXML 语法 | XML 格式的模板描述语言 |
| 表达式语言 | $F{fieldName}(字段)、$P{paramName}(参数)、$V{varName}(变量) |
| 子报表(Subreport) | 报表嵌套,主报表中嵌入子报表 |
| 条件样式 | 根据数据值动态改变颜色/字体/可见性 |
| 条码/二维码 | 内置 Barcode4J 支持各种条码格式 |
| 图表 | 内置 JFreeChart 支持柱状图/折线图/饼图 |
| 数据源 | 类 | 场景 |
|---|---|---|
| Ja va Bean 集合 | JRBeanCollectionDataSource | 最常用,传入 List |
| JDBC 直连 | JRResultSetDataSource | 直接执行 SQL |
| 空数据源 | JREmptyDataSource | 只有参数没有明细数据 |
| Map 集合 | JRMapCollectionDataSource | List数据 |
| JSON | JsonDataSource | JSON 字符串/文件 |
| 格式 | 导出器类 | 用途 |
|---|---|---|
JasperExportManager | 打印、归档 | |
| Excel (xlsx) | JRXlsxExporter | 数据分析 |
| Word (docx) | JRDocxExporter | 文档编辑 |
| HTML | HtmlExporter | 在线预览 |
| CSV | JRCsvExporter | 数据交换 |
| 图片 (PNG) | JRGraphics2DExporter | 缩略图 |
| 模式 | 应用 |
|---|---|
| 模板方法 | 编译 → 填充 → 导出的固定流程 |
| 策略模式 | 不同 Exporter 实现不同格式导出 |
| 建造者模式 | ExporterInput/OutputItem 的构建 |
| 工厂模式 | JasperCompileManager/JasperFillManager 工厂方法 |
net.sf.jasperreports jasperreports 6.20.0 net.sf.jasperreports jasperreports-fonts 6.20.0 org.apache.poi poi-ooxml 5.2.3
package com.example.utils;
import ja va.io.ByteArrayOutputStream;
import ja va.io.InputStream;
import ja va.util.List;
import ja va.util.Map;
import ja vax.servlet.http.HttpServletResponse;
import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.export.ooxml.JRDocxExporter;
import net.sf.jasperreports.engine.export.ooxml.JRXlsxExporter;
import net.sf.jasperreports.export.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* JasperReports 报表工具类.
* 封装编译、填充、导出的完整流程.
*/
public class JasperUtil {
private static final Logger log = LoggerFactory.getLogger(JasperUtil.class);
/**
* 导出类型枚举.
*/
public enum DocType {
PDF, EXCEL, WORD, HTML
}
/**
* 生成报表并写入 HTTP 响应(文件下载).
*
* @param templatePath 模板路径(classpath 下的 .jasper 文件)
* @param params 报表参数
* @param dataList 数据集合(对应模板中的 Field)
* @param fileName 下载文件名
* @param docType 导出格式
* @param response HTTP 响应
*/
public static void exportToResponse(
String templatePath,
Map params,
List dataList,
String fileName,
DocType docType,
HttpServletResponse response) {
try {
byte[] bytes = generateReport(templatePath, params, dataList, docType);
// 设置响应头
String contentType;
String extension;
switch (docType) {
case PDF:
contentType = "application/pdf";
extension = ".pdf";
break;
case EXCEL:
contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
extension = ".xlsx";
break;
case WORD:
contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
extension = ".docx";
break;
default:
contentType = "text/html";
extension = ".html";
}
response.setContentType(contentType);
response.setHeader("Content-Disposition",
"attachment; filename=" + ja va.net.URLEncoder.encode(fileName + extension, "UTF-8"));
response.setContentLength(bytes.length);
response.getOutputStream().write(bytes);
response.getOutputStream().flush();
} catch (Exception e) {
log.error("报表导出失败", e);
throw new RuntimeException("报表导出失败", e);
}
}
/**
* 生成报表字节数组.
*/
public static byte[] generateReport(
String templatePath,
Map params,
List dataList,
DocType docType) throws Exception {
// 1. 加载编译好的模板
InputStream templateStream = JasperUtil.class.getClassLoader()
.getResourceAsStream(templatePath);
JasperReport jasperReport = (JasperReport) JRLoader.loadObject(templateStream);
// 2. 创建数据源
JRDataSource dataSource;
if (dataList != null && !dataList.isEmpty()) {
dataSource = new JRBeanCollectionDataSource(dataList);
} else {
dataSource = new JREmptyDataSource();
}
// 3. 填充数据 → 生成 JasperPrint
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, params, dataSource);
// 4. 导出为目标格式
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
switch (docType) {
case PDF:
JasperExportManager.exportReportToPdfStream(jasperPrint, outputStream);
break;
case EXCEL:
exportToExcel(jasperPrint, outputStream);
break;
case WORD:
exportToWord(jasperPrint, outputStream);
break;
default:
JasperExportManager.exportReportToHtmlFile(jasperPrint, outputStream.toString());
}
return outputStream.toByteArray();
}
private static void exportToExcel(JasperPrint jasperPrint, ByteArrayOutputStream out) throws Exception {
JRXlsxExporter exporter = new JRXlsxExporter();
exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(out));
SimpleXlsxReportConfiguration config = new SimpleXlsxReportConfiguration();
config.setOnePagePerSheet(false);
config.setDetectCellType(true);
exporter.setConfiguration(config);
exporter.exportReport();
}
private static void exportToWord(JasperPrint jasperPrint, ByteArrayOutputStream out) throws Exception {
JRDocxExporter exporter = new JRDocxExporter();
exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(out));
exporter.exportReport();
}
}
@RestController
public class DeliveryPrintController {
@Resource
private DeliveryService deliveryService;
/**
* 打印发货单(导出PDF).
*/
@GetMapping("/api/delivery/print")
public void printDeliveryOrder(
@RequestParam Integer deliveryId,
HttpServletResponse response) {
// 1. 查询发货单数据
DeliveryOrderDto order = deliveryService.getDeliveryOrder(deliveryId);
List items = deliveryService.getDeliveryItems(deliveryId);
// 2. 组装报表参数
Map params = new HashMap<>();
params.put("companyName", "xxx科技");
params.put("deliveryCode", order.getDeliveryCode());
params.put("printDate", DateUtil.formatStandardDate(new Date()));
params.put("customerName", order.getCustomerName());
params.put("address", order.getShipToAddress());
// 3. 导出 PDF
JasperUtil.exportToResponse(
"print/delivery_order.jasper", // classpath 下的模板
params,
items, // 明细数据
"发货单_" + order.getDeliveryCode(),
JasperUtil.DocType.PDF,
response);
}
/**
* 批量打印(多个发货单合并为一个PDF).
*/
@PostMapping("/api/delivery/batch-print")
public void batchPrint(
@RequestBody List deliveryIds,
HttpServletResponse response) {
List prints = new ArrayList<>();
for (Integer id : deliveryIds) {
DeliveryOrderDto order = deliveryService.getDeliveryOrder(id);
List items = deliveryService.getDeliveryItems(id);
Map params = new HashMap<>();
params.put("deliveryCode", order.getDeliveryCode());
// ... 其他参数
// 生成每个发货单的 JasperPrint
InputStream template = getClass().getClassLoader()
.getResourceAsStream("print/delivery_order.jasper");
JasperReport report = (JasperReport) JRLoader.loadObject(template);
JasperPrint print = JasperFillManager.fillReport(report, params,
new JRBeanCollectionDataSource(items));
prints.add(print);
}
// 合并导出为一个 PDF
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=batch_delivery.pdf");
JRPdfExporter exporter = new JRPdfExporter();
exporter.setExporterInput(SimpleExporterInput.getInstance(prints));
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(response.getOutputStream()));
exporter.exportReport();
}
}
/**
* 发货单明细DTO(字段名需与JRXML中的Field名称一致).
*/
@Data
public class DeliveryItemDto {
private String productCode; // 对应 $F{productCode}
private String productName; // 对应 $F{productName}
private Integer quantity; // 对应 $F{quantity}
private BigDecimal price; // 对应 $F{price}
}
1. 下载安装 Jaspersoft Studio(免费,基于 Eclipse)
2. 新建 Jasper Report → 选择模板尺寸(A4/自定义)
3. 拖拽组件到 Band 中:
- Static Text:固定文本
- Text Field:动态字段 $F{xxx}
- Image:图片/Logo
- Barcode:条码
- Line/Rectangle:线条/边框
4. 定义 Parameters(外部传入的参数)
5. 定义 Fields(对应数据源的字段)
6. 预览效果 → 保存为 .jrxml
7. 编译为 .jasper → 放到项目 resources/print/ 目录
src/main/resources/ ├── print/ │ ├── delivery_order.jrxml ← 模板源文件(用于修改) │ ├── delivery_order.jasper ← 编译后模板(运行时加载) │ ├── outbound_order.jasper ← 出库单模板 │ └── stock_report.jasper ← 库存报表模板 ├── font/ │ └── simsun.ttf ← 中文字体文件 └── jasperreports.properties ← JasperReports 配置
| 设计要点 | 实现方式 | 收益 |
|---|---|---|
| 数据与模板分离 | .jasper 模板 + List 数据 | 修改样式不改代码,修改逻辑不改模板 |
| 预编译模板 | .jrxml → .jasper(开发时编译) | 运行时直接加载,无需编译开销 |
| 多格式输出 | 同一模板导出 PDF/Excel/Word/HTML | 一次设计,多种输出 |
| 批量合并 | 多个 JasperPrint 合并为一个 PDF | 批量打印只需下载一个文件 |
| 中文支持 | 嵌入字体文件到项目中 | 避免服务器字体缺失导致中文乱码 |
| 参数化 | $P{paramName} 动态传入 | 同一模板适配不同场景(换标题/Logo/签章) |
| 子报表嵌套 | Subreport 组件 | 主从报表(如订单主信息 + 商品明细) |
| 表达式计算 | $V{variable} + calculation=Sum | 自动计算合计/平均/计数 |
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8