You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为含多子报表的Jasper Report注入JRBeanCollectionDataSource数据?

解决Jasper Reports子报表通过JRBeanCollectionDataSource注入数据的问题

嘿,作为Jasper新手,遇到子报表数据源的问题很正常,我来一步步帮你搞定!

首先,你当前的代码用了JREmptyDataSource填充主报表,但没有给子报表传递任何数据集合,而且主报表里的子报表配置用了REPORT_CONNECTION(JDBC连接),这和你要使用的JRBeanCollectionDataSource(Bean集合数据源)不匹配,这就是问题所在。

下面是具体的解决步骤:


1. 调整JasperSoft Studio中的主报表配置

首先需要修改主报表里的子报表设置,去掉JDBC连接配置,换成Bean数据源的参数传递:

步骤1.1 为主报表添加参数

在JasperSoft Studio中打开主报表,添加两个参数:

  • 参数名:claimHistoryList,类型选择java.util.List
  • 参数名:claimDetailList,类型选择java.util.List

步骤1.2 修改子报表的数据源配置

把每个子报表的<connectionExpression>替换成<dataSourceExpression>,用我们刚添加的参数来创建JRBeanCollectionDataSource:

第一个子报表(ClaimHistory)的配置修改后:

<subreport> 
    <reportElement positionType="Float" x="18" y="1" width="522" height="65" uuid="f3063ed3-775f-47df-8306-a939aecc9d89"/> 
    <dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($P{claimHistoryList})]]></dataSourceExpression> 
    <subreportExpression><![CDATA["ClaimHistory.jasper"]]></subreportExpression> 
</subreport>

第二个子报表(ClaimDetail)的配置修改后:

<subreport> 
    <reportElement positionType="Float" x="18" y="2" width="522" height="65" uuid="a70d75e0-b9d0-4f52-bb84-090993c2e90b"/> 
    <dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($P{claimDetailList})]]></dataSourceExpression> 
    <subreportExpression><![CDATA["ClaimDetail.jasper"]]></subreportExpression> 
</subreport>

注意:如果你的子报表需要其他参数,也可以在主报表里定义并通过子报表的<parameterMapExpression>传递,不过这里我们先解决数据源的核心问题。


2. 修改Java代码,传递子报表数据集合

接下来要在Java代码里准备好子报表需要的数据,然后通过参数传递给主报表:

步骤2.1 准备业务数据

先创建你的实体类(比如ClaimHistory和ClaimDetail),并准备好对应的List集合:

// 你的实体类,必须提供getter方法,字段名要和子报表里的字段对应
class ClaimHistory {
    private String claimId;
    private String claimDate;
    private String claimType;

    // 构造方法
    public ClaimHistory(String claimId, String claimDate, String claimType) {
        this.claimId = claimId;
        this.claimDate = claimDate;
        this.claimType = claimType;
    }

    // Getter方法,Jasper会通过这些方法获取字段值
    public String getClaimId() { return claimId; }
    public String getClaimDate() { return claimDate; }
    public String getClaimType() { return claimType; }
}

class ClaimDetail {
    private String detailId;
    private String itemName;
    private Double amount;

    public ClaimDetail(String detailId, String itemName, Double amount) {
        this.detailId = detailId;
        this.itemName = itemName;
        this.amount = amount;
    }

    public String getDetailId() { return detailId; }
    public String getItemName() { return itemName; }
    public Double getAmount() { return amount; }
}

// 准备数据集合
List<ClaimHistory> claimHistoryList = new ArrayList<>();
claimHistoryList.add(new ClaimHistory("CH001", "2024-01-01", "医疗报销"));
claimHistoryList.add(new ClaimHistory("CH002", "2024-02-15", "意外报销"));

List<ClaimDetail> claimDetailList = new ArrayList<>();
claimDetailList.add(new ClaimDetail("CD001", "药品费", 150.00));
claimDetailList.add(new ClaimDetail("CD002", "检查费", 300.00));

步骤2.2 把数据集合放入参数Map

将上面的List集合添加到参数Map中,同时设置报表文件目录,确保程序能找到子报表文件:

Map<String, Object> params = new HashMap<>();
params.put("claimHistoryList", claimHistoryList);
params.put("claimDetailList", claimDetailList);
// 设置报表文件所在目录,这样子报表可以直接用文件名查找
params.put(JRParameter.REPORT_FILE_DIR, "E:/jasper/");

步骤2.3 填充并导出报表

修改填充报表的代码,把参数Map传进去(主报表没有自己的数据,所以继续用JREmptyDataSource即可):

String jasperFile = "E:/jasper/jasperFile.jrxml"; 
FileInputStream inputStream = new FileInputStream(jasperFile); 
JasperReport jasperReport = JasperCompileManager.compileReport(inputStream); 

// 填充报表,传入参数和空数据源
JasperPrint print = JasperFillManager.fillReport(jasperReport, params, new JREmptyDataSource()); 

List<JasperPrint> jasperPrintList = new ArrayList<>(); 
jasperPrintList.add(print); 

JRPdfExporter exporter = new JRPdfExporter(); 
exporter.setExporterInput(SimpleExporterInput.getInstance(jasperPrintList)); 
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput("E:/output.pdf")); 
exporter.exportReport();

关键注意事项

  • 子报表字段与实体类匹配:子报表里的字段名称必须和实体类的getter方法对应,比如子报表里的claimId字段对应实体类的getClaimId()方法,大小写敏感!
  • 子报表路径问题:确保ClaimHistory.jasper和ClaimDetail.jasper文件在你设置的REPORT_FILE_DIR目录下,或者在子报表表达式里使用绝对路径。
  • 编译子报表:最好在JasperSoft Studio里提前编译好子报表生成.jasper文件,这样Java程序运行时不需要再编译,提升效率。

这样修改后,子报表就能正确获取到JRBeanCollectionDataSource里的数据了,导出的PDF应该就能显示子报表的内容啦!

内容的提问来源于stack exchange,提问作者Ari Wibowo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:45:18