📅  最后修改于: 2020-11-16 08:07:09             🧑  作者: Mango
我们在前面的章节中已经看到,报表上显示的数据通常是从报表参数和报表字段中获取的。可以使用报告变量及其表达式来处理此数据。在某些情况下,无法使用报表表达式或变量轻松实现复杂的功能。这样的例子可能是复杂的String操作,地图构建或内存中的对象列表或使用第三方Java API的日期操作。在这种情况下,JasperReports为我们提供了一种使用Scriptlets进行操作的简单而强大的方法。
小脚本是每次报告事件发生时执行的Java代码序列。报告变量的值可以通过脚本影响。
我们可以通过两种方式声明脚本:
使用< scriptlet >元素。该元素具有名称属性和类属性。 class属性应该指定类的名称,该类扩展了JRAbstractScriptlet类。该类必须在报告填充时在类路径中可用,并且必须具有空的构造函数,以便引擎可以即时实例化它。
在报告模板(JRXML)中使用元素< jasperReport >的属性scriptletClass 。通过使用scriptlet的完全限定名称(包括整个程序包名称)设置此属性,表明我们要使用scriptlet。使用此属性创建的scriptlet实例的行为类似于scriptlet列表中的第一个scriptlet,并且具有预定义的名称REPORT。
脚本是Java类,必须扩展以下两个类之一:
net.sf.jasperreports.engine.JRAbstractScriptlet-此类包含许多抽象方法,每个实现中都必须重写这些抽象方法。 JasperReports在适当的时候会自动调用这些方法。开发人员必须实现所有抽象方法。
net.sf.jasperreports.engine.JRDefaultScriptlet-此类包含JRAbstractScriptlet中每个方法的默认空实现。开发人员仅需要实现他/她的项目所需的那些方法。
下表列出了上述类中的方法。在报告填充阶段,报告引擎将在适当的时间调用这些方法。
S.NO | Method and Description |
---|---|
1 |
public void beforeReportInit() Called before report initialization. |
2 |
public void afterReportInit() Called after report initialization. |
3 |
public void beforePageInit() Called before each page is initialized. |
4 |
public void afterPageInit() Called after each page is initialized. |
5 |
public void beforeColumnInit() Called before each column is initialized. |
6 |
public void afterColumnInit() Called after each column is initialized. |
7 |
public void beforeGroupInit(String groupName) Called before the group specified in the parameter is initialized. |
8 |
public void afterGroupInit(String groupName) Called after the group specified in the parameter is initialized. |
9 |
public void beforeDetailEval() Called before each record in the detail section of the report is evaluated. |
10 |
public void afterDetailEval() Called after each record in the detail section of the report is evaluated. |
每个报告可以指定任意数量的脚本。如果未为报告指定脚本,则引擎仍将创建单个JRDefaultScriptlet实例,并使用内置的REPORT_SCRIPTLET参数对其进行注册。
我们可以将所需的任何其他方法添加到脚本中。报表可以使用内置参数REPORT_SCRIPTLET调用这些方法。
我们可以通过另一种方式将脚本集与报表相关联,即通过全局声明脚本集。这使得脚本可以应用于给定JasperReports部署中填充的所有报告。可以将scriptlet作为扩展添加到JasperReports中,这一点很容易实现。 scriptlet扩展点由net.sf.jasperreports.engine.scriptlets.ScriptletFactory接口表示。 JasperReports将在运行时加载通过扩展可用的所有scriptlet工厂。然后,它将向其中的每一个询问要应用到正在运行的当前报告的scriptlet实例的列表。当询问脚本实例的列表时,引擎会提供一些上下文信息,工厂可以使用这些信息来决定哪些脚本实际上适用于当前报告。
调速器只是全局脚本的扩展,使我们能够解决报表引擎在运行时进入无限循环并生成报表的问题。在设计时无法检测到无效的报告模板,因为在大多数情况下,进入无限循环的条件取决于在运行时馈入引擎的实际数据。报表主管可以帮助您确定某个报表是否已进入无限循环,并且可以将其停止。这样可以防止运行报告的计算机耗尽资源。
JasperReports有两个简单的报表管理器,它们将根据指定的最大页面数或指定的超时间隔来停止执行报表。他们是-
net.sf.jasperreports.governors.MaxPagesGovernor-这是一个全局脚本,正在寻找两个配置属性来决定它是否适用于当前正在运行的报表。配置属性是-
net.sf.jasperreports.governor.max.pages.enabled = [true | false]
net.sf.jasperreports.governor.max.pages = [整数]
net.sf.jasperreports.governors.TimeoutGovernor-这也是一个全局脚本,它正在寻找以下两个配置属性来决定其是否适用。
配置属性是-
net.sf.jasperreports.governor.timeout.enabled = [true | false]
net.sf.jasperreports.governor.timeout = [毫秒]
可以在jasperreports.properties文件中或在报告级别将这两个调控器的属性全局设置为自定义报告属性。这很有用,因为不同的报告可能具有不同的估计大小或超时限制,并且还因为您可能想打开所有报告的调控器,而同时关闭某些报告,反之亦然。
让我们编写一个scriptlet类( MyScriptlet )。文件C:\ tools \ jasperreports-5.0.1 \ test \ src \ com \ tutorialspoint \ MyScriptlet.java的内容如下-
package com.tutorialspoint;
import net.sf.jasperreports.engine.JRDefaultScriptlet;
import net.sf.jasperreports.engine.JRScriptletException;
public class MyScriptlet extends JRDefaultScriptlet {
public void afterReportInit() throws JRScriptletException{
System.out.println("call afterReportInit()");
// this.setVariableValue("AllCountries", sbuffer.toString());
this.setVariableValue("someVar", new String("This variable value
was modified by the scriptlet."));
}
public String hello() throws JRScriptletException {
return "Hello! I'm the report's scriptlet object.";
}
}
上述scriptlet类的详细信息如下-
在afterReportInit方法中,我们为变量“ someVar”设置一个值this.setVariableValue(“ someVar”,new String(“此变量值已由scriptlet修改。”)。
在课程结束时,已定义了一个名为“ hello”的额外方法。这是可以添加到Scriptlet中的方法的示例,该方法实际上返回一个值,而不是设置变量。
接下来,我们将scriptlet类引用添加到我们现有的报告模板中(“章报告设计” )。修改后的报告模板(jasper_report_template.jrxml)如下。将其保存到C:\ tools \ jasperreports-5.0.1 \ test目录-
<
![CDATA[Boolean.TRUE]]>
修改后的报告模板的详细信息如下-
我们在
小脚本只能访问,而不能修改报告字段和参数。但是,脚本可以修改报告变量值。这可以通过调用setVariableValue()方法来完成。此方法在JRAbstractScriptlet类中定义,该类始终是任何scriptlet的父类。在这里,我们定义了一个变量someVar ,它将由MyScriptlet修改为具有值。该值已由scriptlet修改。
上面的报告模板在“摘要”区域中有一个方法调用,该方法调用说明了如何编写新方法(在scriptlet中)并在报告模板中使用它们。 ( $ P {REPORT_SCRIPTLET} .hello() )
用于填充报告的Java代码保持不变。文件C:\ tools \ jasperreports-5.0.1 \ test \ src \ com \ tutorialspoint \ JasperReportFill.java的内容如下-
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 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的内容如下所示-
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;
}
}
文件C:\ tools \ jasperreports-5.0.1 \ test \ src \ com \ tutorialspoint \ DataBeanList.java的内容如下所示-
package com.tutorialspoint;
import java.util.ArrayList;
public class DataBeanList {
public ArrayList getDataBeanList() {
ArrayList dataBeanList = new ArrayList();
dataBeanList.add(produce("Manisha", "India"));
dataBeanList.add(produce("Dennis Ritchie", "USA"));
dataBeanList.add(produce("V.Anand", "India"));
dataBeanList.add(produce("Shrinath", "California"));
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;
}
}
我们将使用常规的ANT构建过程来编译并执行上述文件。文件build.xml的内容(保存在目录C:\ tools \ jasperreports-5.0.1 \ test下)如下所示。
导入文件-baseBuild.xml是从“环境设置”一章中提取的,应与build.xml放在同一目录中。
接下来,让我们打开命令行窗口并转到build.xml所在的目录。最后,将命令ant -Dmain-class = com.tutorialspoint.JasperReportFill (viewFullReport是默认目标)执行为-
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 bu
[javac] Compiling 4 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.
[java] call afterReportInit()
[java] call afterReportInit()
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: 18 minutes 49 seconds
经过上述编译,JasperViewer窗口打开,如下图所示:
在这里,我们看到MyScriptlet类显示了两条消息-