说说 Jaspersoft Studio 中的参数以及与应用之间的交互

报表中的参数(Parameters )是应用程序与报表引擎之间沟通的桥梁,它可以用于以下用途:

  • 传递 SQL 查询中的参数值,比如 SQL 语句中的 where 条件。
  • 提供数据源所无法提供的值,比如自定义表头、生成该报表的账号、应用所指定的图片路径等等。

参数由一个名称和一个 Java 实现类(Class)组成。比如 java.sql.Connection 类型的参数,一般用于子报表(subreport);而 java.lang.Boolean 类型的参数,用于是否展示报表的某一部分。

参数可以设定一个默认值,这样如果应用没有传递该参数值,JasperReports 也能正确解析。

1 管理参数

可以使用 outline 面板来管理参数。

Parameters 下的那些灰色参数,表示是系统级的参数,不能编辑或者删除它。

右键点击 Parameters ,就可以创建参数:

右键点击某个具体参数,就可以选择删除它。

点击某个具体参数,就可以在 Properties 面板中,对其进行查看或设置:

有以下这些可设置项:

设置项 说明
Name 参数名。
Class 参数实现类。
Default Value Expression 参数默认值,它可以是一个表达式。
Description 参数说明。JasperReports 没有直接使用该值,但为了便于未来维护,建议还是要填写下。
Is for Prompting 如果勾选该项,当在 Jaspersoft Studio 中点击 Preview 预览报表时,就会弹出参数输入框,供预览者依据实际情况填写报表所需的参数值。

在 Properties 面板的 Advanced 选项卡中,可以按照键值对的方式,对其进行设置:

2 内置参数

Jaspersoft Studio 定义了一些内置参数,具体说明如下:

内置参数 说明
REPORT_PARAMETERS_MAP 使用者调用 API 中的 fillReport() 方法所传入的 Map 型键值对参数。
REPORT_CONNECTION 报表中的 JDBC connection,用于执行 SQL 语句。
REPORT_MAX_COUNT 报表所能填充的最大记录数。如果未指定,则没有限制。
REPORT_DATA_SOURCE 如果没有使用 JDBC connection(比如非数据库的数据源 CSV 等),将会使用这个参数。
REPORT_SCRIPTLET 报表创建时的脚本实例,默认使用 net.sf.jasperreports.engine.JRDefaultScriptlet。
REPORT_LOCALE locale 区域设置,一般用于国际化场景。默认为系统值。
REPORT_TIME_ZONE 所在时区,默认为系统值。
REPORT_FORMAT_FACTORY 默认实现是 net.sf.jasperreports.engine.util.FormatFactory。可以参考该工厂类,实现自定义工厂。
REPORT_CLASS_LOADER 可用于设置报表填充时的 class loader。
REPORT_URL_HANDLER_FACTORY 可用于指定创建 URL handlers 实现工厂。
REPORT_FILE_RESOLVER 默认实现是 net.sf.jasperreports.engine.util.FileResolver,用于解析报表中的资源路径,也可以自定义。
REPORT_VIRTUALIZER 定义报表填充器的实现类,默认为 JRVirtualizer 接口的实现类。
IS_IGNORE_PAGINATION Boolean 类型,分页开关。默认情况下,除了导出 excel 与 HTML 之外,其它情况不分页。

3 查询场景

一般情况下,JasperReports 会把传入的参数放入 sql statement 中,然后再执行查询,这样可以避免 SQL 注入问题。当然这也会使得参数不够灵活,无法把 SQL 片段作为参数传入语句。

3.1 SQL 语句中的参数

参数可以定义在 where 条件中,用于过滤数据,语法为 $P{参数名},比如:

... and T3.STAFF_NO = $P{staff_no}

这条语句将会以 prepared statement 形式加以执行:

... and T3.STAFF_NO = ?

在 Jaspersoft Studio 的 Input Parameters 中,输入 staff_no 参数(记得先定义好这个参数)值:

输出结果:

参数也可以传入 SQL 片段,用于拼接 SQL 语句,语法为 $P!{参数名},比如:

and $P!{conditions}

在 Jaspersoft Studio 的 Input Parameters 中,输入 conditions 参数值:``T3.STAFF_NO = 1`,输出结果与上例相同。

利用该语法,甚至可以把整个 SQL 语句作为参数传入报表引擎。形如 $P!{自定义SQL语句}


一个 query 可以包含任意个入参,当遇到语法 $P!{xxx} 时,就会被替换为所传入的实际值。

注意: 必须为参数设置默认值,让报表更健壮。

3.2 处理 SQL 语句中的 Null

$P{parametername} 格式的参数,无法正确处理 Null 值,我们可以使用 $X{EQUAL,fieldname,parametername}来处理 Null 值。

比较这两种写法的区别:

  1. $P{param} 模式的语句为 select * from client where address = $P{address_param}
  2. $X{EQUAL, column_name, param_name} 模式的语句为 select * from client where $X{EQUAL, address , address_param}
  • 如果 address_param 参数值不为 Null,那么这两种写法,都会被解析为 select * from client where address = '北京'
  • 如果 address_param 参数值为 Null,那么 $P{} 模式会被解析为 select * from client where address = null,而 $X{} 模式会被解析为 select * from client where address is null

很明显,$X{} 的解析模式才是正确的 SQL 处理 null 的模式。

3.3 处理 SQL 语句中的 IN 与 NOT IN 形式

JasperReports 使用特殊语法来应对 where 中的 IN 与 NOT IN 形式。

IN 一般用于一系列的值,比如:

select * from client where address in ('北京','上海','广州')

address 的参数值一般是一个列表(最好是 java.util.Collection)或者一个数组,之前的 SQL 可以用以下语法来表示:

select * from client where $X{IN, address,address_values}

address_values 是包含一系列地址数据的参数,$X{} 支持三个入参:

  1. IN 或者 NOTIN
  2. 字段名
  3. 参数名

如果传入的参数是 null 或者是一个空列表,$X{} 会解析为 0 = 0

3.4 处理时间

3.4.1 表达式

可以使用类型为 DateRange 的参数,来作为时间条件,过滤数据。

表达式格式为 <Keyword>+/-<N>,具体说明如下:

  • <Keyword> 指定时间单位,可为 DAY, WEEK, MONTH, QUARTER, SEMI 和 YEAR。
  • <+/-> 表示是在该时间之前(-)还是之后(+)。
  • <N> 表示 N 个时间单位。

比如 DAY - 1 表示前一天。

这种表达方式存在一定的局限性,只能表示某个时间点的左右偏移量。如果要表示时间范围,可以用 BETWEEN 语法:

$X{BETWEEN, column, startParam, endParam}

比如说要设置当前周到某一天的,可以这样表示:

$X{BETWEEN, column, WEEK, DAY}

3.4.2 时间范围参数类型

参数类型 说明 示例
net.sf.jasperreports.types.date.DateRange 以 YYYY-MM-DD 格式表示的日期字符串。 <parameter name="myParam" class="net.sf.jasperreports.types.date.DateRange">
net.sf.jasperreports.types.date.TimestampRange 以 YYYY-MM-DD HH:mm:ss 格式表示的日期时间字符串。 <parameter name="myParam" class="net.sf.jasperreports.types.date.TimestampRange">

3.4.3 在查询中的写法

必须使用 $X{} 表达式来处理时间范围。

可以使用 DateRangeBuilder() 类把时间范围参数的默认表达式转换为相应的时间范围参数类型。

示例 说明
new net.sf.jasperreports.types.date.DateRangeBuilder("DAY-1").toDateRange() 表示前一天,并转换为 DateRange 类型。
new net.sf.jasperreports.types.date.DateRangeBuilder("WEEK").set(Timestamp.class).toDateRange() 表示一整周,并转换为 TimestampRange 类型。
new net.sf.jasperreports.types.date.DateRangeBuilder("2020-02-01").toDateRange() 把日期字符串,转换为 DateRange 类型。
new net.sf.jasperreports.types.date.DateRangeBuilder("2020-02-01 12:33:55").toDateRange() 把时间字符串,转换为 TimestampRange 类型。

比如说,需要展示前一天的数据,可以这样定义参数与 SQL 表达式(JRXML 形式):

<parameter name="myParameter" class="net.sf.jasperreports.types.date.DateRange">
    <defaultValueExpression>
        <![CDATA[new DateRangeBuilder("DAY-1").toDateRange()]]>
    </defaultValueExpression>
</parameter>
<queryString>
    <![CDATA[Select * from account where $X{EQUAL, create_date, myParameter}]]>
</queryString>

展示上个月最后一天之前的数据:

<parameter class="net.sf.jasperreports.types.date.DateRange" name="EndDate">
    <defaultValueExpression>
        <![CDATA[new net.sf.jasperreports.types.date.DateRangeBuilder("MONTH-1").toDateRange().getEnd()]]>
    </defaultValueExpression>
</parameter>
<queryString>
    <![CDATA[SELECT * FROM orders WHERE $X{LESS, order_date, EndDate}]]>
</queryString>

指定时间范围或者相对入参的时间偏移量,可以照以下步骤进行:

  1. 定义两个时间范围入参并指定好类型,比如 StartDate 与 EndDate。
  2. 设置该参数的默认表达式,此为可选项。
  3. 在查询语句中使用带 BETWEEN 函数的 $X{} 表达式。

比如希望查找 1 年前的所有数据,StartDate 表示 1 年前,EndDate 表示精确到日,可以这样表示:

<parameter name="StartDate" class="net.sf.jasperreports.types.date.DateRange">
    <defaultValueExpression>
        <![CDATA[(new net.sf.jasperreports.types.date.DateRangeBuilder("YEAR-1")).toDateRange()]]>
    </defaultValueExpression>
</parameter>
<parameter name="EndDate" class="net.sf.jasperreports.types.date.DateRange">
    <defaultValueExpression>
        <![CDATA[(new net.sf.jasperreports.types.date.DateRangeBuilder("DAY")).toDateRange()]]>
    </defaultValueExpression>
</parameter>
<queryString language="SQL">
    <![CDATA[select name from employee where
$X{BETWEEN, HIRE_DATE, StartDate, EndDate} limit 200]]>
</queryString>

还可以使用 getStart() 与 getEnd() 方法来精确指定时间范围的起止点,比如入参 Period 是时间范围,而我们实际需要的是 Date,那么可以这样表示:

<parameter name="StartDate" class="java.util.Date" nestedType="java.util.Date">
    <defaultValueExpression>
        <![CDATA[$P{Period}.getStart()]]>
    </defaultValueExpression>
</parameter>

3.5 代码中传参

使用 HashMap 来传递参数,代码模板如下:

...
HashMap hm = new HashMap();
...
JasperPrint print = JasperFillManager.fillReport(
fileName,
hm,
new JREmptyDataSource());
...

HashMap 是键值对结构,设置参数值是可以这样写:

...
HashMap hm = new HashMap();
hm.put("参数名","参数值")
...

如果设置的参数值为 null,那么 JasperReports 会使用默认值表达式赋予初始值。

4 测试

可以在 Jaspersoft Studio 中把参数设置为 Prompt,这样可以在 Preview 预览模式中,填入报表入参,验证生成的报表数据是否满足业务需求。

在左侧 Parameters 中,点击某个需要设置 Prompt 的参数,然后在对应的 Properties 中,把 Is For Prompting 设置为 true:

接着点击 Preview 进入预览模式,就会出现 Input Parameters,用于输入需要测试的报表入参。输入入参后,点击下面的执行按钮,就可以测试我们所设计的报表咯:


Jaspersoft Studio 对入参考虑的比较全面,关键就是多实践。选择最适合的方式,来实现业务所需的报表。

发布了636 篇原创文章 · 获赞 719 · 访问量 93万+

猜你喜欢

转载自blog.csdn.net/deniro_li/article/details/104338992
今日推荐