Jasper Reports 简明教程

Report Expression

报表表达式是 JasperReports 的强大功能,它允许我们在报表上显示计算数据。计算数据不是静态数据,也没有特别作为报表参数或数据源字段传递。报表表达式由报表参数、字段和静态数据组合而成。默认情况下,Java 语言用于编写报表表达式。JasperReports 编译器支持用于报表表达式的其他脚本语言,如 Groovy 脚本语言、JavaScript 或 BeanShell 脚本。

Report expressions are the powerful features of JasperReports, which allow us to display calculated data on a report. Calculated data is the data that is not a static data and is not specifically passed as a report parameter or datasource field. Report expressions are built from combining report parameters, fields, and static data. The Java language is used for writing report expressions by default. Other scripting languages for report expressions like Groovy scripting language, JavaScript, or BeanShell script are supported by JasperReports compilers.

本章将为您解释报表表达式如何工作,假设报表表达式仅使用 Java 语言编写。在一个 JRXML 报表模板中,有若干元素定义表达式,如下 −

This chapter will explain you − how do report expressions work, assuming that they have been written using the Java language only. In a JRXML report template, there are several elements that define expressions as −

  1. <variableExpression>

  2. <initialValueExpression>

  3. <groupExpression>

  4. <printWhenExpression>

  5. <imageExpression>

  6. <textFieldExpression>

Expression Declaration

基本上,所有报表表达式都是 Java 表达式,可以引用报表字段、报表变量和报表参数。

Basically, all report expressions are Java expressions, which can reference the report fields, report variables, and report parameters.

Field Reference in Expression

要在表达式中使用报表字段引用,必须将字段的名称放在 $F{*and }* 字符序列之间,如下所示 −

To use a report field reference in an expression, the name of the field must be put between $F{*and}* character sequences, as shown below −

<textfieldexpression>
   $F{Name}
</textfieldexpression>

以下是现有 JRXML 文件中的一段代码(第 Report Designs) 章 −

Following is a piece of code from our existing JRXML file (chapter Report Designs)

<textFieldExpression class = "java.lang.String">
   <![CDATA[$F{country}]]>
</textFieldExpression>

Variable Reference in Expression

要在表达式中引用变量,必须将变量名称放在 $V{*and }* 之间,如下面给出的示例所示 −

To reference a variable in an expression, we must put the name of the variable between $V{*and}* as shown in the example given below −

<textfieldexpression>
   "Total height : " + $V{SumOfHeight} + " ft."
</textfieldexpression>

Parameter Reference in Expression

要在表达式中引用参数,应该将参数名称放在 $P{*and }* 之间,如下面给出的示例所示 −

To reference a parameter in an expression, the name of the parameter should be put between $P{*and}* as shown in the example given below −

<textfieldexpression>
   "ReportTitle : " + $P{Title}
</textfieldexpression>

以下是现有 JRXML 文件中的一段代码,它说明了如何在表达式中引用参数。(第 Report Designs 章的 JRXML) −

Following is a piece of code from our existing JRXML file, which demonstrates the referencing of parameter in an expression. (JRXML from chapter Report Designs) −

<textField isBlankWhenNull = "true" bookmarkLevel = "1">
   <reportElement x = "0" y = "10" width = "515" height = "30"/>

   <textElement textAlignment = "Center">
      <font size = "22"/>
   </textElement>

   <textFieldExpression class = "java.lang.String">
      <![CDATA[$P{ReportTitle}]]>
   </textFieldExpression>

   <anchorNameExpression>
      <![CDATA["Title"]]>
   </anchorNameExpression>
</textField>

<textField isBlankWhenNull = "true">
   <reportElement  x = "0" y = "40" width = "515" height = "20"/>

   <textElement textAlignment = "Center">
      <font size = "10"/>
   </textElement>

   <textFieldExpression class = "java.lang.String">
      <![CDATA[$P{Author}]]>
   </textFieldExpression>
</textField>

如您在上面看到的那样,参数、字段和变量引用实际上是真正的 Java 对象。通过在报表模板中进行参数、字段或变量声明了解它们的类,我们甚至可以在表达式中对那些对象引用调用方法。

As you have seen above, the parameter, field, and variable references are in fact real Java objects. Knowing their class from the parameter, field, or variable declaration made in the report template, we can even call methods on those object references in the expressions.

以下示例显示了如何从 java.lang.String 报表字段“Name”中提取并显示第一个字母 −

The following example shows − how to extract and display the first letter from java.lang.String report field "Name" −

<textFieldExpression>
   $F{Name}.substring(0, 1)
</textFieldExpression>

Resource Bundle Reference in Expression

要在表达式中引用资源,应将键放在 $R{*and }* 之间,如下面给出的示例所示 −

To reference a resource in an expression, the key should be put between $R{*and}* as shown in the example given below −

<textfieldexpression>
   $R{report.title}
</textfieldexpression>

基于运行时提供的语言环境和 report.title 键,加载与报表模板关联的资源包。因此,通过从资源包中提取 String 值来显示报表标题。关于国际化的更多信息可以在第 Internationalization 章中找到。

Based on the runtime-supplied locale and the report.title key, the resource bundle associated with the report template is loaded. Hence, the title of report is displayed by extracting the String value from the resource bundle. More on internationalization can be found in the chapter Internationalization.

Calculator

计算器是 JasperReports 中的一个实体,它在报告填充时评估表达式并增加变量或数据集。在编译过程中,编译器将生成信息并将其存储在编译报告中。在报告填充时,使用此信息来构建 net.sf.jasperreports.engine.fill.JRCalculator 类的实例。

Calculator is an entity in JasperReports, which evaluates expressions and increments variables or datasets at report-filling time. During compiling process, the information is produced and stored in the compile report by the compiler. This information is used during the report-filling time to build an instance of the net.sf.jasperreports.engine.fill.JRCalculator class.

Java 源文件由基于 Java 的报告编译器动态生成和编译。这个生成的类是 JRCalculator 的子类,编译生成字节码存储在 JasperReport 对象中。在报告填充时加载这个字节码,并实例化结果类以获取表达式评估所需的计算器对象。

Java source file is generated and compiled by Java-based report compilers on the fly. This generated class is a subclass of the JRCalculator, and the bytecode produced by compiling it is stored inside the JasperReport object. This bytcode is loaded at the report filling time and the resulting class is instantiated to obtain the calculator object needed for expression evaluation.

Conditional Expressions

定义变量表达式时,JasperReports 不支持 if-else 语句。相反,可以使用三元运算符 {cond} ? {statement 1} : {statement 2} 。此运算符可以嵌套在 Java 表达式中,以根据多种条件获取所需输出。

JasperReports doesn’t support if-else statements when defining variable expressions. Instead, you can use the ternary operators {cond} ? {statement 1} : {statement 2}. This operator can be nested inside a Java expression to obtain the desired output based on multiple conditions.

Example of conditional Expression in Report

让我们修改现有的报告模板(第 Report Designs 章),并为 country 字段添加条件表达式。修改后的报告模板 (jasper_report_template.jrxml) 如下。将其保存到 C:\tools\jasperreports-5.0.1\test 目录中−

Let’s modify existing report template (Chapter Report Designs) and add a conditional expression for the field country. The revised report template (jasper_report_template.jrxml) is as follows. Save it to C:\tools\jasperreports-5.0.1\test directory −

<?xml version = "1.0"?>
<!DOCTYPE jasperReport PUBLIC
   "//JasperReports//DTD Report Design//EN"
   "http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">

<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 = "jasper_report_template" pageWidth = "595" pageHeight = "842"
   columnWidth = "515" leftMargin = "40" rightMargin = "40"
   topMargin = "50" bottomMargin = "50">

   <parameter name = "ReportTitle" class = "java.lang.String"/>
   <parameter name = "Author" class = "java.lang.String"/>

   <queryString>
      <![CDATA[]]>
   </queryString>

   <field name = "country" class = "java.lang.String">
      <fieldDescription><![CDATA[country]]></fieldDescription>
   </field>

   <field name = "name" class = "java.lang.String">
      <fieldDescription><![CDATA[name]]></fieldDescription>
   </field>

   <sortField name = "country" order = "Descending"/>
   <sortField name = "name"/>

   <title>
      <band height = "70">

         <line>
            <reportElement x = "0" y = "0" width = "515" height = "1"/>
         </line>

         <textField isBlankWhenNull = "true" bookmarkLevel = "1">
            <reportElement x = "0" y = "10" width = "515" height = "30"/>

            <textElement textAlignment = "Center">
               <font size = "22"/>
            </textElement>

            <textFieldExpression class = "java.lang.String">
               <![CDATA[$P{ReportTitle}]]>
            </textFieldExpression>

            <anchorNameExpression>
               <![CDATA["Title"]]>
            </anchorNameExpression>
         </textField>

         <textField isBlankWhenNull = "true">
            <reportElement  x = "0" y = "40" width = "515" height = "20"/>

            <textElement textAlignment = "Center">
               <font size = "10"/>
            </textElement>

            <textFieldExpression class = "java.lang.String">
               <![CDATA[$P{Author}]]>
            </textFieldExpression>
         </textField>

      </band>
   </title>

   <columnHeader>
      <band height = "23">

         <staticText>
            <reportElement mode = "Opaque" x = "0" y = "3" width = "535" height = "15"
               backcolor = "#70A9A9" />

            <box>
               <bottomPen lineWidth = "1.0" lineColor = "#CCCCCC" />
            </box>

            <textElement />
            <text>
               <![CDATA[]]>
            </text>
         </staticText>

         <staticText>
            <reportElement x = "414" y = "3" width = "121" height = "15" />

            <textElement textAlignment = "Center" verticalAlignment = "Middle">
               <font isBold = "true" />
            </textElement>

            <text><![CDATA[Country]]></text>
         </staticText>

         <staticText>
            <reportElement x = "0" y = "3" width = "136" height = "15" />

            <textElement textAlignment = "Center" verticalAlignment = "Middle">
               <font isBold = "true" />
            </textElement>

            <text><![CDATA[Name]]></text>
         </staticText>

      </band>
   </columnHeader>

   <detail>
      <band height = "16">

         <staticText>
            <reportElement mode = "Opaque" x = "0" y = "0" width = "535" height = "14"
               backcolor = "#E5ECF9" />

            <box>
               <bottomPen lineWidth = "0.25" lineColor = "#CCCCCC" />
            </box>

            <textElement />
            <text>
               <![CDATA[]]>
            </text>
         </staticText>

         <textField>
            <reportElement x = "414" y = "0" width = "121" height = "15" />

            <textElement textAlignment = "Center" verticalAlignment = "Middle">
               <font size = "9" />
            </textElement>

            <textFieldExpression class = "java.lang.String">
               <![CDATA[$F{country}.isEmpty() ? "NO COUNTRY" : $F{country}]]>
            </textFieldExpression>
         </textField>

         <textField>
            <reportElement x = "0" y = "0" width = "136" height = "15" />
            <textElement textAlignment = "Center" verticalAlignment = "Middle" />

            <textFieldExpression class = "java.lang.String">
               <![CDATA[$F{name}]]>
            </textFieldExpression>
         </textField>

      </band>
   </detail>

</jasperReport>

报告填充的 Java 代码如下。文件 C:\tools\jasperreports-5.0.1\test\src\com\tutorialspoint\JasperReportFill.java 的内容为 −

The java codes for report filling are as follows. The contents of the file C:\tools\jasperreports-5.0.1\test\src\com\tutorialspoint\JasperReportFill.java are as −

package com.tutorialspoint;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;

public class JasperReportFill {
   @SuppressWarnings("unchecked")
   public static void main(String[] args) {
      String sourceFileName =
      "C://tools/jasperreports-5.0.1/test/jasper_report_template.jasper";

      DataBeanList DataBeanList = new DataBeanList();
      ArrayList<DataBean> dataList = DataBeanList.getDataBeanList();

      JRBeanCollectionDataSource beanColDataSource =
      new JRBeanCollectionDataSource(dataList);

      Map parameters = new HashMap();
      /**
       * Passing ReportTitle and Author as parameters
       */
      parameters.put("ReportTitle", "List of Contacts");
      parameters.put("Author", "Prepared By Manisha");

      try {
         JasperFillManager.fillReportToFile(
         sourceFileName, parameters, beanColDataSource);
      } catch (JRException e) {
         e.printStackTrace();
      }
   }
}

POJO 文件 C:\tools\jasperreports-5.0.1\test\src\com\tutorialspoint\DataBean.java 的内容为 -

The contents of the POJO file C:\tools\jasperreports-5.0.1\test\src\com\tutorialspoint\DataBean.java are as −

package com.tutorialspoint;

public class DataBean {
   private String name;
   private String country;

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public String getCountry() {
      return country;
   }

   public void setCountry(String country) {
      this.country = country;
   }
}

我们会在 Java Bean List 中添加一条新记录,country 字段为空。文件 C:\tools\jasperreports-5.0.1\test\src\com\tutorialspoint\DataBeanList.java 的内容为 −

We will add a new record with country field as empty in our Java bean List. The contents of the file C:\tools\jasperreports-5.0.1\test\src\com\tutorialspoint\DataBeanList.java are as −

package com.tutorialspoint;

import java.util.ArrayList;

public class DataBeanList {
   public ArrayList<DataBean> getDataBeanList() {
      ArrayList<DataBean> dataBeanList = new ArrayList<DataBean>();

      dataBeanList.add(produce("Manisha", "India"));
      dataBeanList.add(produce("Dennis Ritchie", "USA"));
      dataBeanList.add(produce("V.Anand", "India"));
      dataBeanList.add(produce("Shrinath", "California"));
      dataBeanList.add(produce("Tanmay", ""));

      return dataBeanList;
   }

   /**
    * This method returns a DataBean object,
    * with name and country set in it.
    */
   private DataBean produce(String name, String country) {
      DataBean dataBean = new DataBean();
      dataBean.setName(name);
      dataBean.setCountry(country);

      return dataBean;
   }
}

Report Generation

我们使用常规 ANT 构建进程编译并执行上述文件。build.xml 文件(保存在目录 C:\tools\jasperreports-5.0.1\test 下)的内容如下。

We will compile and execute the above file using our regular ANT build process. The contents of the file build.xml (saved under directory C:\tools\jasperreports-5.0.1\test) are given below.

导入文件 - baseBuild.xml 取自第 Environment Setup ,应放在与 build.xml 相同的目录中。

The import file - baseBuild.xml is picked from chapter the Environment Setup and should be placed in the same directory as the build.xml.

<?xml version = "1.0" encoding = "UTF-8"?>
<project name = "JasperReportTest" default = "viewFillReport" basedir = ".">
   <import file = "baseBuild.xml" />

   <target name = "viewFillReport" depends = "compile,compilereportdesing,run"
      description = "Launches the report viewer to preview
      the report stored in the .JRprint file.">

      <java classname = "net.sf.jasperreports.view.JasperViewer" fork = "true">
         <arg value = "-F${file.name}.JRprint" />
         <classpath refid = "classpath" />
      </java>
   </target>

   <target name = "compilereportdesing" description = "Compiles the JXML file and
      produces the .jasper file.">

      <taskdef name = "jrc" classname = "net.sf.jasperreports.ant.JRAntCompileTask">
         <classpath refid = "classpath" />
      </taskdef>

      <jrc destdir = ".">
         <src>
            <fileset dir = ".">
               <include name = "*.jrxml" />
            </fileset>
         </src>
         <classpath refid = "classpath" />
      </jrc>

   </target>

</project>

接下来,打开命令行窗口,并转到放置 build.xml 的目录。最后,执行命令 ant -Dmain-class = com.tutorialspoint.JasperReportFill (viewFullReport 是默认目标),如下所示:

Next, let’s open command line window and go to the directory where build.xml is placed. Finally, execute the command ant -Dmain-class = com.tutorialspoint.JasperReportFill (viewFullReport is the default target) as −

C:\tools\jasperreports-5.0.1\test>ant -Dmain-class=com.tutorialspoint.JasperReportFill
Buildfile: C:\tools\jasperreports-5.0.1\test\build.xml

clean-sample:
   [delete] Deleting directory C:\tools\jasperreports-5.0.1\test\classes
   [delete] Deleting: C:\tools\jasperreports-5.0.1\test\jasper_report_template.jasper
   [delete] Deleting: C:\tools\jasperreports-5.0.1\test\jasper_report_template.jrprint

compile:
   [mkdir] Created dir: C:\tools\jasperreports-5.0.1\test\classes
   [javac] C:\tools\jasperreports-5.0.1\test\baseBuild.xml:28:
   warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last;
   set to false for repeatable builds
   [javac] Compiling 3 source files to C:\tools\jasperreports-5.0.1\test\classes

compilereportdesing:
   [jrc] Compiling 1 report design files.
   [jrc] log4j:WARN No appenders could be found for logger
   (net.sf.jasperreports.engine.xml.JRXmlDigesterFactory).
   [jrc] log4j:WARN Please initialize the log4j system properly.
   [jrc] log4j:WARN See
   http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
   [jrc] File : C:\tools\jasperreports-5.0.1\test\jasper_report_template.jrxml ... OK.

run:
   [echo] Runnin class : com.tutorialspoint.JasperReportFill
   [java] log4j:WARN No appenders could be found for logger
   (net.sf.jasperreports.extensions.ExtensionsEnvironment).
   [java] log4j:WARN Please initialize the log4j system properly.

viewFillReport:
    [java] log4j:WARN No appenders could be found for logger
    (net.sf.jasperreports.extensions.ExtensionsEnvironment).
    [java] log4j:WARN Please initialize the log4j system properly.

BUILD SUCCESSFUL
Total time: 5 minutes 5 seconds

C:\tools\jasperreports-5.0.1\test>

作为上述编译的结果,一个 JasperViewer 窗口会打开,如以下给出的屏幕截图所示 -

As a result of above compilation, a JasperViewer window opens up as shown in the screen given below −

report expression example

在这里,我们可以看到,对于最后一条记录,我们没有传递 country 字段的任何数据,“NO COUNTRY” 正在打印。

Here, we can see, for the last record, we had not passed any data for the field country, "NO COUNTRY" is being printed.