返回

JasperReports报表Detail不显示数据?排查与解决

javascript

JasperReports 报表 Detail Band 不显示数据问题排查与解决

在使用 JasperReports 生成报表时, 咱们可能会遇到这样一个问题:用 JRBeanCollectionDataSource 传递动态获取的数据到报表模板,数据提取没问题(调试确认过),但报表的 Detail Band 就是不显示数据,一片空白。

问题原因分析

这种情况,多半是以下几个原因造成的:

  1. JRXML 模板配置错误: 模板可能没有正确绑定数据源,或者字段映射有问题。
  2. 数据源传递问题: Java 代码中创建的 JRBeanCollectionDataSource 对象没有正确传递给报表引擎。
  3. 字段名称不匹配: JRXML 模板中定义的字段名 (field name) 和 Java Bean 中的属性名不一致。
  4. 数据类型不匹配: JRXML 模板中定义的字段类型和 Java Bean 中对应属性的类型不一致。
  5. 数据源使用方式错误: 使用JRBeanCollectionDataSource时, 第二个参数设置可能有误。

解决方案

下面,针对这些可能的原因,一步步排查和解决问题。

1. 检查 JRXML 模板配置

首先看看 JRXML 模板文件,确保正确定义了 parameter 和 field。

检查点:

  • parameter 定义: 确保定义了名为 TEST_DATA_SOURCE 的 parameter,且其 class 属性设置为 net.sf.jasperreports.engine.JRDataSource

    <parameter name="TEST_DATA_SOURCE" class="net.sf.jasperreports.engine.JRDataSource"/>
    
  • field 定义: 确保定义了与 Java Bean 属性对应的 field,并且 name 属性与 Bean 中的属性名一致,class 属性与属性的类型一致。

    <field name="TEST1" class="java.lang.String"/>
    <field name="TEST2" class="java.lang.String"/>
    <field name="TEST3" class="java.lang.String"/>
    <field name="TEST4" class="java.lang.String"/>
    <field name="TEST5" class="java.lang.String"/>
    
  • TEST1 定义了 java.lang.String, 而在fillParameters() 里使用了parseInt。请保证类型匹配, 或使用相同的类型。例如都用java.lang.String

 // ...
 var extractedRow = {
     TEST1: row.getFieldAsString("TEST1") || "0", // 将 TEST1 保持为字符串
     // ...其他字段
 };
```xml
 <field name="TEST1" class="java.lang.String"/>
```
  • Detail Band 绑定: 在 Detail Band 中,使用 <textFieldExpression>![CDATA[$F{fieldName}]]</textFieldExpression> 来绑定字段。确保 fieldName 与上面定义的 field 的 name 属性一致。

    <detail>
        <band height="30">
            <textField>
                <reportElement x="0" y="0" width="172" height="30"/>
                <textFieldExpression><![CDATA[$F{TEST1}]]></textFieldExpression>
            </textField>
            </band>
    </detail>
    

2. 检查数据源传递

在 Java 代码 (这里是 JavaScript) 中,要确保创建了 JRBeanCollectionDataSource 对象,并将其正确地放入 parameterMap

检查点:

  • 正确创建 JRBeanCollectionDataSource: 使用 Java.type 获取 JRBeanCollectionDataSource 类,然后用你的数据列表创建实例。第二个参数应设为false,这表示传入的集合不是嵌套的数据源。

    var JRBeanCollectionDataSource = Java.type("net.sf.jasperreports.engine.data.JRBeanCollectionDataSource");
    var jrDataSource = new JRBeanCollectionDataSource(extractedData, false);
    
  • 正确放入 parameterMap: 使用 parameterMap.put("TEST_DATA_SOURCE", jrDataSource); 将数据源放入参数映射中。确保 key 与 JRXML 中定义的 parameter 的 name 一致。

3. 字段名称和类型匹配

仔细对比 JRXML 中的 field 定义和 Java Bean 中的属性,确保名称和类型完全一致。

  • 大小写敏感: Java 和 JRXML 中的字段名都是大小写敏感的。TEST1test1 是不同的。
  • 类型一致: java.lang.Stringjava.lang.Integer 是不同的类型。

4. JRBeanCollectionDataSource 的第二个参数

JRBeanCollectionDataSource 的构造函数有两个参数:

  • 第一个参数是你的数据集合(List、Array 等)。
  • 第二个参数是一个布尔值,用来指示 JasperReports 是否使用 bean 属性的名称作为字段名。
    当传入 false 时,意味着集合本身就是数据行,不需要进一步分解。应当确保您将此设置为false,因为它指示 JasperReports 不要查找 TEST1, TEST2等属性extractedData 集合上, 而是在该集合的每一个项目里查找。

修改 fillParameters() 函数如下:

function fillParameters() {
    try {
        var rawData = datasourceHelper.get("testDataSource").getRows();

        if (!rawData || rawData.length === 0) {
            throwError("No data retrieved from 'testDataSource'.");
            return; //明确表示在没取到数据时不进行操作。
        }

        var extractedData = [];

        for (var i = 0; i < rawData.length; i++) {
            var row = rawData[i];

            var extractedRow = {
                TEST1: row.getFieldAsString("TEST1") || "0",
                TEST2: row.getFieldAsString("TEST2") || "",
                TEST3: row.getFieldAsString("TEST3") || "",
                TEST4: row.getFieldAsString("TEST4") || "",
                TEST5: row.getFieldAsString("TEST5") || ""
            };

            extractedData.push(extractedRow);
        }

        var JRBeanCollectionDataSource = Java.type("net.sf.jasperreports.engine.data.JRBeanCollectionDataSource");
        var jrDataSource = new JRBeanCollectionDataSource(extractedData, false); // 重点:第二个参数设为 false
        parameterMap.put("TEST_DATA_SOURCE", jrDataSource);

    } catch (e) {
        throwError("ERROR: " + e.message);
    }
}

5. 使用 Jaspersoft Studio 调试 (进阶技巧)

如果上述步骤都检查过了,还是不行,可以用 Jaspersoft Studio 来调试报表。

  1. 在 Jaspersoft Studio 中打开 JRXML 文件。

  2. 配置数据源:

    • 在 "Data" 选项卡中,点击 "Add" -> "Dataset and Query".
    • 选择 "JavaBean datasource"。
    • 输入你的 JavaBean 类的完整类名(即使是在JavaScript中使用的模拟结构, 在测试时这里提供一个形式)。
    • "Factory class": 可以填写一个空的工厂类,这个工厂类只需要一个静态方法,用于返回测试的list, 这个方法甚至可以返回空的List. 比如
        public class TestBeanFactory {
          public static List<TestBean> getTestData() {
            // 即使是空list, 也是用来给Jaspersoft Studio识别字段类型的。
            return Collections.emptyList(); 
              // 或 List.of(new TestBean(...)); //使用真实的测试数据.
            }
         }
      
       public class TestBean{
         private String TEST1;
         private String TEST2;
         private String TEST3;
         private String TEST4;
         private String TEST5;
      
           public TestBean(String TEST1, String TEST2, String TEST3, String TEST4, String TEST5) {
               this.TEST1 = TEST1;
               this.TEST2 = TEST2;
               this.TEST3 = TEST3;
               this.TEST4 = TEST4;
               this.TEST5 = TEST5;
           }
      
           //Getter Setter...
        }
      
    • 然后 "Read attributes", Jaspersoft Studio应该可以发现这些定义的fields。
  3. 预览报表: 点击 "Preview" 按钮。如果数据源配置正确,应该能看到数据。即使实际运行环境没有这个TestBeanFactory, 但是这里能提供设计时需要的字段结构, 不妨碍Jaspersoft Studio中预览和设计。

通过 Jaspersoft Studio 的调试,可以快速定位是 JRXML 模板的问题还是 Java 代码的问题。

通过以上几个方面的排查和修改, 一般就能解决 JasperReports Detail Band 不显示数据的问题。细心是关键! Good Luck!