Jaspersoft-Parameter-1

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

转载文档:https://www.freesion.com

标签: 企业报表设计指南(Jaspersoft Studio+jasperreport)
报表中的参数(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{参数名},比如:

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

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

1
... and T3.STAFF_NO = ?

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

输出结果:

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

1
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 值。
比较这两种写法的区别:

$P{param} 模式的语句为

1
select * from client where address = $P{address_param}

$X{EQUAL, column_name, param_name} 模式的语句为

1
select * from client where $X{EQUAL, address , address_param}

如果 address_param 参数值不为 Null,那么这两种写法,都会被解析为

1
select * from client where address = '北京'

如果 address_param 参数值为 Null,那么 $P{} 模式会被解析为

1
select * from client where address = null,而 

$X{} 模式会被解析为

1
select * from client where address is null

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

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

JasperReports 使用特殊语法来应对 where 中的 IN 与 NOT IN 形式。
IN 一般用于一系列的值,比如:

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

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

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

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

IN 或者 NOTIN
字段名
参数名

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

3.4 处理时间

3.4.1 表达式

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

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

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

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

1
$X{BETWEEN, column, startParam, endParam}

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

1
$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>

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

定义两个时间范围入参并指定好类型,比如 StartDate 与 EndDate。
设置该参数的默认表达式,此为可选项。
在查询语句中使用带 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 对入参考虑的比较全面,关键就是多实践。选择最适合的方式,来实现业务所需的报表。

Contents
  1. 1. 说说 Jaspersoft Studio 中的参数以及与应用之间的交互
    1. 1.1. 1 管理参数
    2. 1.2. 2 内置参数
    3. 1.3. 3 查询场景
      1. 1.3.1. 3.1 SQL 语句中的参数
      2. 1.3.2. 3.2 处理 SQL 语句中的 NULL
      3. 1.3.3. 3.3 处理 SQL 语句中的 IN 与 NOT IN 形式
      4. 1.3.4. 3.4 处理时间
        1. 1.3.4.1. 3.4.1 表达式
        2. 1.3.4.2. 3.4.2 时间范围参数类型
        3. 1.3.4.3. 3.4.3 在查询中的写法
      5. 1.3.5. 3.5 代码中传参
    4. 1.4. 4 测试
|