如何在Jasper Reports主报表中实现子报表循环展示(Spring Boot)
解决Jasper Reports子报表循环展示问题
1. 调整主报表(Main report.jrxml)设计
- 将子报表组件放置在Detail带中(Detail带会随数据源自动循环渲染)
- 主报表添加参数:
mainUserId(用于显示顶部的用户编号) - 主报表的数据源对应子报表数据列表,每个数据项包含子用户编号和商品列表
- 配置子报表组件的参数与数据源:
- 参数传递:将当前Detail行的
subUserId传入子报表(参数名设为subUserId) - 数据源表达式:
new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{products})(绑定当前子报表数据中的商品列表)
- 参数传递:将当前Detail行的
2. 调整子报表(sub reports.jrxml)设计
- 添加参数:
subUserId(用于显示子用户编号) - 子报表的Detail带绑定商品数据字段:
name、costPrice、salePrice,对应表格行
3. Java Spring Boot端数据准备
定义实体类对应数据结构:
// 商品实体 public class Product { private String name; private BigDecimal costPrice; private BigDecimal salePrice; // 构造器、getter/setter } // 子报表数据实体 public class SubReportData { private String subUserId; private List<Product> products; // 构造器、getter/setter }
准备测试数据:
// 主用户编号 String mainUserId = "u123"; // 子报表1数据 List<Product> products1 = Arrays.asList( new Product("橙子", new BigDecimal("90.00"), new BigDecimal("50.00")), new Product("香蕉", new BigDecimal("10.00"), new BigDecimal("9.00")), new Product("苹果", new BigDecimal("100.00"), new BigDecimal("90.00")) ); SubReportData sub1 = new SubReportData("u123-01", products1); // 子报表2数据 List<Product> products2 = Arrays.asList( new Product("蛋糕", new BigDecimal("9.00"), new BigDecimal("5.00")), new Product("牛奶", new BigDecimal("10.00"), new BigDecimal("9.00")), new Product("薯片", new BigDecimal("10.00"), new BigDecimal("8.00")) ); SubReportData sub2 = new SubReportData("u123-02", products2); // 主报表数据源:子报表数据列表 List<SubReportData> mainDataSourceList = Arrays.asList(sub1, sub2);
4. 报表填充与PDF生成
@Autowired private ResourceLoader resourceLoader; public byte[] generateReport() throws JRException, IOException { // 加载主报表和子报表文件 Resource mainReportResource = resourceLoader.getResource("classpath:reports/MainReport.jasper"); Resource subReportResource = resourceLoader.getResource("classpath:reports/SubReport.jasper"); // 参数映射 Map<String, Object> parameters = new HashMap<>(); parameters.put("mainUserId", mainUserId); // 传递子报表输入流供主报表调用 parameters.put("subReportStream", subReportResource.getInputStream()); // 主报表数据源 JRBeanCollectionDataSource mainDataSource = new JRBeanCollectionDataSource(mainDataSourceList); // 填充报表 JasperPrint jasperPrint = JasperFillManager.fillReport( mainReportResource.getInputStream(), parameters, mainDataSource ); // 导出为PDF字节数组 return JasperExportManager.exportReportToPdf(jasperPrint); }
关键注意点
- 主报表的Detail带必须包含子报表组件,主数据源的每个元素会触发一次子报表渲染
- 子报表的数据源必须绑定主报表当前行的商品列表,确保数据对应正确
- 可预先将jrxml编译为jasper文件,提升报表加载与填充效率
内容的提问来源于stack exchange,提问作者enzioJr
相关产品推荐
相关产品推荐

