JasperReports - JSON 数据报告在 运行 in Java 时显示空值

JasperReports - JSON Data Report Shows Null Values when run in Java

我正在使用 JSON 数据测试 JasperReports,运行 遇到一个问题,即从 Java 应用程序中生成时显示空值。这是我到目前为止所做的:

在 Studio 中,我使用包含以下 JSON:

的文件创建了一个使用 JSON 文件数据提供程序的报告
{
    "employees": [
        {
            "fullname":"John Stark",
            "employeeid":"29388282773",
            "phone":"415-293-2928"
        },
        {
            "fullname":"Mike Goodmann",
            "employeeid":"2938828282",
            "phone":"415-293-2726"
        },
        {
            "fullname":"David Simpson",
            "employeeid":"2938822837",
            "phone":"415-293-9826"
        },
        {
            "fullname":"Chris Humpty",
            "employeeid":"2938275452",
            "phone":"415-293-1122"
        }
    ]
}

这是生成的 jrxml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Jaspersoft Studio version 7.1.0.final using JasperReports Library version 6.4.3  -->
<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="testreport" pageWidth="792" pageHeight="612" orientation="Landscape" columnWidth="752" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" >
    <property name="com.jaspersoft.studio.data.defaultdataadapter" value="testdata"/>
    <queryString language="json">
        <![CDATA[employees]]>
    </queryString>
    <field name="fullname" class="java.lang.String">
        <property name="net.sf.jasperreports.json.field.expression" value="fullname"/>
        <fieldDescription><![CDATA[fullname]]></fieldDescription>
    </field>
    <field name="employeeid" class="java.lang.Long">
        <property name="net.sf.jasperreports.json.field.expression" value="employeeid"/>
        <fieldDescription><![CDATA[employeeid]]></fieldDescription>
    </field>
    <field name="phone" class="java.lang.String">
        <property name="net.sf.jasperreports.json.field.expression" value="phone"/>
        <fieldDescription><![CDATA[phone]]></fieldDescription>
    </field>
    <title>
        <band height="79" splitType="Stretch">
            <staticText>
                <reportElement x="240" y="24" width="280" height="30" />
                <text><![CDATA[Employee List]]></text>
            </staticText>
        </band>
    </title>
    <columnHeader>
        <band height="65" splitType="Stretch">
            <staticText>
                <reportElement x="30" y="30" width="180" height="30" />
                <text><![CDATA[Full Name]]></text>
            </staticText>
            <staticText>
                <reportElement x="240" y="30" width="160" height="30" />
                <text><![CDATA[Employee Id]]></text>
            </staticText>
            <staticText>
                <reportElement x="430" y="30" width="180" height="30" />
                <text><![CDATA[Phone Number]]></text>
            </staticText>
            <staticText>
                <reportElement x="299" y="0" width="100" height="30" />
                <text><![CDATA[employeeid]]></text>
            </staticText>
            <staticText>
                <reportElement x="468" y="0" width="100" height="30" />
                <text><![CDATA[phone]]></text>
            </staticText>
        </band>
    </columnHeader>
    <detail>
        <band height="24" splitType="Stretch">
            <textField>
                <reportElement x="30" y="0" width="180" height="20" />
                <textFieldExpression><![CDATA[$F{fullname}]]></textFieldExpression>
            </textField>
            <textField>
                <reportElement x="241" y="0" width="159" height="20" />
                <textFieldExpression><![CDATA[$F{employeeid}]]></textFieldExpression>
            </textField>
            <textField>
                <reportElement x="430" y="0" width="180" height="20" />
                <textFieldExpression><![CDATA[$F{phone}]]></textFieldExpression>
            </textField>
        </band>
    </detail>
</jasperReport>

然后编写了一个简单的控制台应用程序来生成 PDF 格式的报告,但我得到了一行 NULL 值。您会注意到我将 JSON 嵌入到 class 中以简化测试代码,直到我将它正确地设置为 运行,并且我确实将 JSON 数据传递到"JasperFillManager.fillReport()" 电话。 这是我的 Java 代码:

public class ReportTester {
    String jsonData = "{\n" +
            "    \"employees\": [\n" +
            "        {\n" +
            "            \"fullname\":\"John Stark\",\n" +
            "            \"employeeid\":\"29388282773\",\n" +
            "            \"phone\":\"415-293-2928\"\n" +
            "        },\n" +
            "        {\n" +
            "            \"fullname\":\"Mike Goodmann\",\n" +
            "            \"employeeid\":\"2938828282\",\n" +
            "            \"phone\":\"415-293-2726\"\n" +
            "        },\n" +
            "        {\n" +
            "            \"fullname\":\"David Simpson\",\n" +
            "            \"employeeid\":\"2938822837\",\n" +
            "            \"phone\":\"415-293-9826\"\n" +
            "        },\n" +
            "        {\n" +
            "            \"fullname\":\"Chris Humpty\",\n" +
            "            \"employeeid\":\"2938275452\",\n" +
            "            \"phone\":\"415-293-1122\"\n" +
            "        }\n" +
            "    ]\n" +
            "}";
    String reportFile = "/testreport.jrxml";
    String outputPdf = "testreport.pdf";
    JasperReport jasperReport;

    public void printme() {
        try {
            InputStream employeeReportStream = getClass().getResourceAsStream(reportFile);
            jasperReport = JasperCompileManager.compileReport(employeeReportStream);

            ByteArrayInputStream jsonDataStream = new ByteArrayInputStream(jsonData.getBytes());
            JsonDataSource ds = new JsonDataSource(jsonDataStream);
            JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, new HashMap<String, Object>(), ds);

            JRPdfExporter exporter = new JRPdfExporter();
            exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
            exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(outputPdf));
            SimplePdfReportConfiguration reportConfig = new SimplePdfReportConfiguration();
            reportConfig.setSizePageToContent(true);
            reportConfig.setForceLineBreakPolicy(false);
            exporter.setConfiguration(reportConfig);

            exporter.exportReport();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

任何人都可以帮助指出这有什么问题以及为什么报告没有生成数据吗?

怎么了

你没有select数据正确。这意味着 JR 引擎为报告准备了错误的输入数据。

如何修复

您只需将表达式传递给 JsonDataSource 实例以获得 select 正确的数据。

示例:

JasperReport jasperReport;
try {
    try (InputStream inputStream = getClass().getResourceAsStream(reportTemplate)) {
        jasperReport = JasperCompileManager.compileReport(inputStream);
    }

    File outputFile = new File(outputFileName);
    SimplePdfExporterConfiguration configuration = new SimplePdfExporterConfiguration();
    ByteArrayInputStream jsonDataStream = new ByteArrayInputStream(jsonData.getBytes());
    JsonDataSource ds = new JsonDataSource(jsonDataStream, "employees");
    JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, Maps.newHashMap(), ds);

    try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
         OutputStream fileOutputStream = new FileOutputStream(outputFile)) {
        JRPdfExporter exporter = new JRPdfExporter();

        exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
        exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(byteArrayOutputStream));
        exporter.setConfiguration(configuration);
        exporter.exportReport();
        byteArrayOutputStream.writeTo(fileOutputStream);
    }
} catch (IOException | JRException e) {
    throw new RuntimeException("Failed to build report", e);
}

所有魔法都在这里:

JsonDataSource ds = new JsonDataSource(jsonDataStream, "employees");

在表达式 employees 的帮助下,我们正在 select 所有节点。您在 JSS.

的模板或数据适配器上执行相同的操作

我们可以查看JsonDataSourceclass的源码。我们需要 moveFirst 方法。

@Override
public void moveFirst() throws JRException {
    if (jsonTree == null || jsonTree.isMissingNode()) {
        throw 
            new JRException(
                EXCEPTION_MESSAGE_KEY_NO_DATA,
                (Object[])null);
    }

    currentJsonNode = null;
    JsonNode result = getJsonData(jsonTree, selectExpression);
    if (result != null && result.isObject()) {
        final List<JsonNode> list = new ArrayList<JsonNode>();
        list.add(result);
        jsonNodesIterator = new Iterator<JsonNode>() {
            private int count = -1;
            @Override
            public void remove() {
                list.remove(count);
            }

            @Override
            public JsonNode next() {
                count ++;
                return list.get(count);
            }

            @Override
            public boolean hasNext() {
                return count < list.size()-1;
            }
        };
    } else if (result != null && result.isArray()) {
        jsonNodesIterator = result.elements();
    }
}

如果 select 使用 employees 表达式处理数据,我们有 "employee" 个实体的列表,这些实体具有 全名、员工 ID 和 phone属性。

借助调试工具我们可以查看到这行代码的数据: JsonNode result = getJsonData(jsonTree, selectExpression);

如果使用您的代码:ByteArrayInputStream jsonDataStream = new ByteArrayInputStream(jsonData.getBytes()); 数据将是: