本文转自:http://www.java125.cn/article.asp?id=1729
转帖目录:http://www.java125.cn/search.asp?SearchContent=jasperreport&searchType=title
第1章 概述
本章对JasperReports的功能和特点进行概要说明。具体内容包括:
JasperReports历史
JasperReports是什么,它可以为我们做什么
JasperReports开源许可的简单讨论
JasperReports的特点
JasperReports类库的依赖关系
用JasperReports生成报表所需步骤的简要概述
从哪里获得JasperReports的支持
JasperReports历史
JasperReports 由Teodor Danciu于2001年创立。那时他接受一项任务,为他参预的项目做报表工具的评估。他发现现存的方案对他们的项目预算来说都过于昂贵,于是他决定编写自己的报表工具。后来,这个项目被取消了。于是他开始在业余时间开发JasperReports,并于2001年9月在http://sourceforge.net注册了这个项目。不久以后,他就开始收到来自潜在用户的邮件,尽管他还没有提交任何代码。
JasperReports 于2001年11月发布了它的0.1.5版。从那以后,JasperReports被广泛地使用。如今,它已是最流行的报表工具之一。作为 JasperReports享有巨大声望的一个证明,用Google搜索java reporting tool,返回的第一条结果就是 JasperReports网站。
一直以来,JasperReports都是一个单人项目,Teodor用业余时间对它进行开发。在 2005年4月,一家名为JasperSoft的公司在加利福尼亚的MySQL 用户会议上正式启动。JasperSoft资助了 JasperReports的开发,使Teodor和其他的JasperSoft开发人员可以全身心地投入到JasperReports工作中。 JasperSoft同时为JasperReports和相关产品提供商业支持与服务,包括用于JasperReports的 iReport Visual Designer。除了为JasperReports和iReport提供支持外,JasperSoft还销售整合了 JasperReports的商业应用软件。
JasperSoft获得了八百万美元的风险投资,这在dotcom时代是个不小的壮举。这些投资表明了风险投资家们对JasperSoft和JasperReports的成功充满了信心。据JasperSoft统计,JasperReports已经被下载300,000次以上,平均每月就有20,000次下载。它已被10,000多家公司和独立软件供应商 (ISV)所采用。
JasperReports是什么
JasperReports是一个面向开发人员设计的开源 Java类库,通过它可以为Java应用程序增加报表功能。由于JasperReports不是独立的工具,所以不能对它进行独立安装。而是要通过应用程序的CLASSPATH来包含其类库,从而把它嵌入到Java应用程序中。JasperReports是Java类库,也就是说它不是为最终用户准备的。它的目标用户是那些需要为应用程序添加报表功能的Java开发人员。
尽管JasperReports主要用于通过 Servlet API来为基于Web的应用程序增加报表功能,但它并不是完全依赖于Servlet API或任何Java EE类库。因此,它并不仅限于Web应用程序。用JasperReports来建立独立的桌面程序或命令行程序来生成报表的工作从未停止过。可是,话说回来,JasperReports除了是一个Java类库这外,什么都不是。它做的事情只是通过提供API来为各种Java应用程序增加报表功能。
JasperReports 需要Java Development Kit (JDK) 1.3或更新的版本来进行编译,以便和JasperReports的Java类库一同工作。同时还需要Java Runtime Environment 1.3或更新的版本来运行这些应用程序。早期版本的JasperReports需要JDK 来运行JasperReports 应用程序(严格地讲,JasperReports需要tools.jar被设置在CLASSPATH环境变量中,JDK包含了tools.jar,而JRE中没有)。然而,从0.6.4版以后,JasperReports把 Eclipse Java Development Tools (JDT)编译器捆绑在一起,因此不再需要JDK来运行部署后的应用程序。本书的例子是用JDK1.5开发的,但它们在JasperReports支持其它JDK或JRE上也应该能够编译和运行。
JasperReports的开源许可
JasperReports 的许可遵循Lesser GNU Public License (LGPL)。与GPL不同,JasperReports选择的许可协议允许其被用于开源的或非开源的应用程序。连接到JasperReports Java类库的应用程序可以不开放源代码,但是,如果你要修改了现存的 JasperReports源代码,那么所修改的内容也必须遵照LGPL进行发布。请查看http://jasperreports.sourceforge.net/license.html 获取完整的许可协议。
JasperReports的特点
除了以文本方式生成报表外,JasperReports还可以生成包含图片、图表和图形的专业报表。JasperReports的主要特点包括:
灵活的报表排版
以文本或图形方式显示数据
允许用户以多种方式提供数据
支持多种数据源
生成水印
生成子报表
以多种格式输出报表
下面的各小节将对这些特点做简要介绍。
灵活的报表排版
JasperReports允许我们把报表分割成若于区域,这些区域包括:
表头 它在报表的顶部出现一次
页眉 它在每页的顶部出现一次
详情区域 通常包含主要的报表数据
页脚 它在每页的底部出现一次
汇总区域 它出现在报表的末尾
除了允许定义报表区域外,JasperReports还允许我们基于报表的内容创建精细的动态版面。例如,根据报表中域的值,可以把数据隐藏或显示,也可以把数据分组到逻辑区域中。假如,我们要创建一个关于汽车的报表,JasperReports允许我们根据产地、型号、年代或它们的组合来对报表中的数据进行分组。数据分组使我们能够对报表更好地布局,还可以基于报表中的部分数据进行求和计算。分组还用于为图表和图形定义数据集。
多种方式显示数据
JasperReports可以用文本方式或图形方式来显示报表。它还允许用户通过表示式来生成报表,从而动态地显示数据。也就是说,数据并不是直接被传到报表,或保存在什么地方。而是通过对来自数据源的数据和/或参数来计算得到。
多种方式提供数据
JasperReports允许开发人员通过传递报表参数的形式来提供数据,这些报表参数可以是Java类的实例。
数据还可以通过称为数据源的特殊类来提供给报表。报表参数和数据源可以组合使用,以达到最大的灵活性。
多种数据源
JasperReports 可以通过JDBC来把任何关系数据库中的数据生成报表,但并不是只限于数据库报表。它还可以从许多数据源来生成报表,包括:XML文件、简单Java对象 (POJO)、任何实现了java.util.Map接口的类、以及任何实现了javax.swing.TableModel接口的类。
JasperReports还支持空数据源,它被用于生成不需要显示动态数据的简单报表。如果要从一个JasperReports不直接支持的数据源来生成报表,我们可以创建自定义数据源。JDBC数据源以及其它的数据源类型将在后续的章节详细讨论,包括自定义数据源。
水印
JasperReports可以在它生成的报表的背景层生成图片或文本。这些图片可以用作报表的“水印”,它就象是在主图象下面的二级图像。
水印可用于为报表添加商标。也可用于安全目的,因为这样的报表不易被仿制。所有的报表页都会有相同的水印,这使得报表具有一致的外观。
子报表
JasperReports还能创建子报表,也称为报表中的报表。Subreports把报表的设计变得简单化,它可以让我们把复杂报表中的一部分摘取出来在另外一个报表里进行设计,然后把它合并到主报表中。
报表导出能力
JasperReports 生成的报表可以导出为多种格式,包括:PDF、XLS、RTF、HTML、XML、CSV、简单文本。有一个第三方的库可以把JasperReports 的报表导出为开放文档格式(ODF)。这种格式是一种OASIS组织开发的标准化的XML文件,专门用于办公软件。OpenOffice.org的2.0 版就是把ODF作为其默认格式。
注:JasperReports开放文本格式导出器是由Google于2005年夏开发的,相关的更详细信息可以查询网站http://netmoc.cpe.ucf.edu/Projects/jasper.html。
下面的屏幕截图演示了JasperReports的一些特性,包括:数据分组、添加图片和水印、导出为PDF。
生成上面截图中的报表,需要用到JasperReports的数据分组功能来为country、state和city进行分组,这样显示的数据具有逻辑性,而且容易被理解。此外,还需要用到JasperReports的图片功能来为报表添加水印和商标。表头部分的字体被编辑为更大的粗黑体,详细的数据以容易理解的格式进行编排。
上图中用到了免费的Evince文档阅读器。当然,导出的PDF报表也可以用其它的任何PDF阅读器查看,包括:Adobe Acrobat、Foxit、xPDF。
类库依赖
JasperReports借用了其它的开源Java类库来实现其部分功能,其中有:
iText: iText是一个用于生成和处理PDF的类库。另外,它不可以生成和处理RTF、XML和HTML文档。JasperReports用它来导出PDF和RTF格式的报表。要获得有关iText的更详细介绍,可以访问http://www.lowagie.com/iText/。
JFreeChart: JFreeChart是一个Java类库,可用于生成各种图表,包括:饼图、条形图、线形图、区域图、等等。JasperReports通过JFreeChart来实现其图形功能。有关JFreeChart的更详细介绍可以查阅http://www.jfree.org/jfreechart/index.php。
Jakarta POI: Jakarta POI 是一个Java类库,用于创建和处理各种建立在Microsoft的OLE2混合文档格式基础上的Microsoft Office格式的文档。 JasperReports通过Jakarta POI来导出XLS格式的报表,更多的Jakarta POI有关介绍可查阅http://jakarta.apache.org/poi/。
JAXP: JAXP是Java SE 5.0中的用于解析和转换XML文档的Java API,JasperReports用它来解析XML文件。如果使用更早版本的Java SE,需要独立地下载它。有关JAXP的更详细介绍可以查阅http://java.sun.com/webservices/jaxp/index.jsp。
Jakarta Commons: Jakarta Commons 是一套Java类库,提供了大量的可重用组件。JasperReports使用了其中的Digester、BeanUtils、Logging组件来完成 XML的JAXP解析。关于Jakarta Commons的更详细介绍可查阅http://jakarta.apache.org/commons/。
注:这里给出URL的目的是为了提供信息,JasperReports类库已经包含了这里列出的所需JAR文件。我们没有必要自己再下载它们,以获得其在JasperReports中的相应功能。
典型的流程
下面的图形简单地示范了用JasperReports创建报表的典型流程:
用 JasperReports进行工作时,第一步要创建报表模板,它是一个XML文件。它可以通过手工编码来完成,也可以用图形化的报表设计器完成。虽然 JasperReports的报表模板是XML文件,但其文件名却用.jrxml来作为扩展名。JasperReports XML模板通常就是指 JRXML文件,本书中会用到这一术语。
下面是一个典型的JRXML文件的内容:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jasperReport PUBLIC "//JasperReports//DTD Report Design//EN"
"http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">
<jasperReport name="simple_template">
<title>
<band height="50">
</band>
</title>
<pageHeader>
<band height="50">
</band>
</pageHeader>
<columnHeader>
<band height="30">
</band>
</columnHeader>
<detail>
<band height="100">
</band>
</detail>
<columnFooter>
<band height="30">
</band>
</columnFooter>
<pageFooter>
<band height="50">
</band>
</pageFooter>
<lastPageFooter>
<band height="50">
</band>
</lastPageFooter>
<summary>
<band height="50">
</band>
</summary>
</jasperReport>
这个JRXML文件大致说明了JRXML文件中的主要元素。除了<jasperReport>根元素外,这个文件中的其它元素都是可选的。在编译和填充时,上面的JRXML文件会生成一个空表。它本身没有什么用处,但我们可以用它来作为一个模板,进而编写更有用的报表。我们在上面的例子中可以看到,JRXML文件的每个主元素都包含一个<band>元素作为它的子元素。Band包含了报表中要显示的数据。上例中,所有的Band都是空的。在实际的JRXML文件中,Band包含的子元素用于:定位、格式化、显示实际报表的文本和图形数据。有一些商用的开源可视化设计工具可用于开发 JRXML文件。JsperReports的官方报表设计工具是iReport。
JRXML文件需要被编译成 JasperReports本地二进制模板。我们可以通过调用适当的JasperReports类库方法 (compileReportToFile()),或者使用自定义的ANT任务(可以在一次操作中编译多个XML报表设计文件,要编译的文件可以通过包含它们的根目录,或用文件选择模式来指定)。模板编译生成的结果通常称为Jasper文件,其扩展名为.jasper。Jasper文件用于和所需的数据一同生成最后的报表,这一过程被称为填充(filling)报表。JRXML文件只需被编译一次,编译生成的Jasper文件可以根据需要被多次填充,从而创建和显示报表。
填充后的报表可以JasperReports本地格式保存到磁盘,这种格式的文件通常称为JasperPrint文件,其扩展名为.jrprint。JasperPrint files只能用JasperReports特定的阅读器来查看。我们可以把它导出为其它的格式,这样就可以用一些通用的工具来打开查看了,如PDF阅读器和Word。
从哪里获得帮助
JasperReports有官方的在线论坛和邮件列表,可以提问寻求帮助。这些论坛和邮件列表打包存档的地址是http://sourceforge.net/projects/jasperreports。
JasperReports网站有相关的提示、诀窍、JavaDoc API文档、以及JRXML元素的参考,本指南不会重复这些内容,读者可以自行到网上在线查阅它们。JasperReports的网站地址是http://jasperreports.sourceforge.net。
JasperSoft和其它一些三方厂商还提供商业支持和培训。
小结
本章我们对JasperReports进行了介绍。不仅提到JasperReports从很小的个人项目发展为一个由一家公司支持的项目,获得了数百万美元的风险投资,还大致浏览了JasperReports。JasperReports不仅是一个独立的报表解决方案,它还是一个Java类库,我们可以通过它来为自己的应用程序添加报表处理的功能。
另外,还提到了JasperReports的开源许可(LGPL)。本章简要地罗列了 JasperReports的功能,包括:报表排版、以文本方或图形方式显示数据、数据分组、JasperReports类库的依赖关系、报表设计的一般流程。最后还给出了用以寻求帮助的官方在线论坛和邮件列表。
第3章 创建第一份报表
本章我们将创建、编译、预览第一份报表,通过本章学习,我们将能够:
* 创建一份简单的JRXML报表模板
* 编译JRXML文件生成Jasper二进制报表模板
* 用JasperReports自定义的ANT目标预览报表模板
* 编写从JasperReports模板生成报表的代码
* 通过JaspreReports提供的工具浏览生成的本地格式的报表
* 生成能够显示在浏览器中的报表
* 识别与报表中各片段相对应的JRXML元素
创建JRXML报表模板
创建报表的第一步是创建一份JRXML模板,JasperReports的JRXML模板是标准的XML文件。通常情况下,其扩展名为. jrxml,也称为JRXML文件或JRXML模板。所有的JRXML文件都包含一个<jasperReport>根元素,它又包含若干子元素。所有的子元素都是可选的。而我们在这里所以去掉了大多数<jasperReport>子元素,只用了一个名为< detail>的子元素,为的是对报表的设计能有个感性认识。
我们的第一份报表将显示一个静态的字符串,其JRXML如下:
<?xml version="1.0"?>
<!DOCTYPE jasperReport PUBLIC "-//JasperReports//DTD Report Design//EN"
"http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">
<jasperReport name="FirstReport">
<detail>
<band height="20">
<staticText>
<reportElement x="20" y="0" width="200" height="20"/>
<text><![CDATA[If you don't see this, it didn't work]]></text>
</staticText>
</band>
</detail>
</jasperReport>
在这些JRXML文件的元素中:
<staticText> 定义了静态文本,它不需要依赖于任何数据源、变量、参数或报表表达式。
<reportElement> 定义了<staticText>元素的位置和宽度。
<text> 定义了显示在报表上的实际静态文本。
在上面的例子中,我们看到了<band>元素。<detail>元素只能包含一个单独的<band>元素作为其子元素,而<band>元素可以包含许多不同的元素,用来显示文本、图表、图片或几何图形。本例中,它只包含了一个< staticText>元素。
注:对于<staticText>元素和所有<band>元素的子元素,< reportElement>元素都是必需的。<reportElement>中的定义的x和y是相对于其父元素< band>的(本例中为<staticText>)。
预览XML报表模板
JasperReports里有个工具可以用来预见览报表设计,使得不用编译和填充就能立即对报表进行预览,从而大大地加快了设计报表的速度。这个工具是独立的Java应用程序,它包含在JasperReports的JAR文件中。
需要执行的类是net.sf.jasperreports.view.JasperDesignViewer,执行它的最简单方法是使用 ANT,类路径中已包含了全部所需的库。我们使用工程ZIP文件中的JasperReports范例时会使用这种方法,下面的ANT构建文件将加载JasperDesignViewer来预览报表:
<project name="FirstReport XML Design Preview" default="viewDesignXML" basedir=".">
<description>Previews our First Report XML Design</description>
<property name="file.name" value="FirstReport"/>
<!-- Directory where the JasperReports project file was extracted
needs to be changed to match the local environment -->
<property name="jasper.dir" value="/usr/local/share/java/jasperreports-1.1.0"/>
<property name="classes.dir" value="${jasper.dir}/build/classes"/>
<property name="lib.dir" value="${jasper.dir}/lib"/>
<path id="classpath">
<pathelement location="./"/>
<pathelement location="${classes.dir}"/>
<fileset dir="${lib.dir}">
<include name="**/*.jar"/>
</fileset>
</path>
<target name="viewDesignXML"
description="Launches the design viewer to preview the XML report design.">
<java classname="net.sf.jasperreports.view.JasperDesignViewer" fork="true">
<arg value="-XML"/>
<arg value="-F${file.name}.jrxml"/>
<classpath refid="classpath"/>
</java>
</target>
</project>
这个ANT构建文件必须和JRXML文件保存在相同的目录中,建议把JRXML文件的报表名和文件名使用一致的名称。报表名称在< jasperReport>根元素中定义,在这里,我们用FirstReport作为报表名称。因此,推荐报表模板的文件名使用 FirstReport.jrxml。
如果我们保存ANT构建文件为标准名称build.xml,就不需要在命令行中再指定构建文件名。此处的示例中,构建文件有一个名为 viewDesignXML的<target>元素。由于它是缺省的目标,我们就不需要在命令行中指定它。只需要输入ant,缺省的目标就会被执行,并显示出预览报表。
$ ant Buildfile: previewReportDesignXML.xml
viewDesignXML:
执行完viewDesignXML目标后,我们会看到一个窗口显示出预览状态的报表,其标签名称为JasperDesignViewer。
通过关闭窗口,或在命令行窗口中输入Ctrl-c,这个JasperDesignViewer可以被安全地关闭。
在预览状态中,我们能看到全部文本,这是因为此报表只包含了静态文本。如果报表的数据是来源于数据库或报表参数,此处的实际文本将显示包含了要显示的数据的表达式。这是因为JasperDesignViewer不会对数据源或报表参数进行实际访问。
创建二进制报表模板
JRXML不能用来直接生成报表,它们需要被编译成JasperReports的本地二进制格式,编译后的报表模板称为Jasper文件。有两种不同的方法来把JRXML文件编译成Jasper文件:编程实现,或通过JasperReports提供的自定义ANT任务来实现。
编译JRXML模板
通过调用net.sf.jasperreports.engine.JasperCompileManager类的 compileReportToFile()方法,可以把JRXML模板编译成Jasper文件。 JasperCompileManager.compileReportToFile()方法有三个重载版本,如下所示:
* JasperCompileManager.compileReportToFile(String sourceFileName).
* JasperCompileManager.compileReportToFile(String sourceFileName, String destFileName).
* JasperCompileManager.compileReportToFile(JasperDesign jasperDesign, String destFileName).
下面的表格对这些方法的参数进行了说明:
参数
描述
String sourceFileName
此参数指定JRXML模板的位置,它被用于编译生成报表模板。它可以是绝对路径,也可以相对路径。编译生成的报表模板会保存到和它相同的位置,并以.jasper作为扩展名。
String destFileName
此参数指定在文件系统中用于保存编译生成的报表模板的文件名,它可以是绝对路径或相对路径。
JasperDesign jasperDesign
这是报表在内存中的存在形式,net.sf.jasperreports.engine.design.JasperDesign实例可以通过在net.sf.jasperreports.engine.xml.JRXmlLoader中调用相应的方法来创建。
下面的代码段演示了怎样使用JasperCompileManager.compileReportToFile()方法:
package net.ensode.jasperbook;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperCompileManager;
public class FirstReportCompile {
public static void main(String[] args) {
try {
System.out.println("Compiling report");
JasperCompileManager.compileReportToFile( "reports/FirstReport.jrxml");
System.out.println("Done!");
}
catch (JRException e) {
e.printStackTrace();
}
}
}
编译执行上面的代码,我们会得到一个名为FirstReport.jasper的文件。此文件就是编译生成的JasperReports本地格式的模板。假如我们使用前面讨论的第一个版本的JasperCompileManager.compileReportToFile()方法,源文件名会被用于编译生成的报表。如果我们希望编译后的报表为不同的文件名,就需要使用第二个版本的 JasperCompileManager.compileReportToFile()方法,并在其第二个参数中指定要生成的名字。
预览编译后的报表模板
前面讨论的net.sf.jasperreports.view.JasperDesignViewer可用于预览编译后的报表模板,就象JRXML模板一样。执行此工具的最简单的方法是在ANT目标中封装一个调用。下面,我们在build.xml文件中添加第二个ANT目标,我们把它命名为 viewDesign,它将使我们能够预览编译后的报表。
<project name="FirstReport XML Design Preview" default="viewDesignXML" basedir=".">
<description>Previews our First Report Design</description>
<property name="file.name" value="FirstReport"/>
<!-- Directory where the JasperReports project file was extracted,
needs to be changed to match the local environment -->
<property name="jasper.dir" value="/usr/local/share/java/jasperreports-1.1.0"/>
<property name="classes.dir" value="${jasper.dir}/build/classes"/>
<property name="lib.dir" value="${jasper.dir}/lib"/>
<path id="classpath">
<pathelement location="./"/>
<pathelement location="${classes.dir}"/>
<fileset dir="${lib.dir}">
<include name="**/*.jar"/>
</fileset>
</path>
<target name="viewDesignXML"
description="Launches the design viewer to preview the XML report design.">
<java classname="net.sf.jasperreports.view.JasperDesignViewer" fork="true">
<arg value="-XML"/>
<arg value="-F${file.name}.jrxml"/>
<classpath refid="classpath"/>
</java>
</target>
<target name="viewDesign"
description="Launches the design viewer to preview the compiled report design.">
<java classname="net.sf.jasperreports.view.JasperDesignViewer" fork="true">
<arg value="-F${file.name}.jasper"/>
<classpath refid="classpath"/>
</java>
</target>
</project>
我们可以从命令行调用这个新目标: ant viewDesign
调用完成后,我们会看到一个和前面的JRXML模板预览相同的窗口。
用ANT来编译JRXML模板
JasperReports 包含一个自定义的ANT任务,用它可以来编译报表模板。其编译方式非常便利,我们不需要编写执行编译的代码。然而,对于一些特殊的应用程序,还是需要通过编写相应的代码来编译报表,比如JRXML文件是在运行时进行创建的情况。JasperReports中的自定义ANT任务在 net.sf.jasperreports.ant.JRAntCompileTask类中进行定义,它会被JRC调用。下面,我们将在 build.xml中添加一个自定义的目标来调用JRC任务。
<project name="FirstReport XML Design Preview" default="viewDesignXML" basedir=".">
<description>Previews and compiles our First Report</description>
<property name="file.name" value="FirstReport"/>
<!-- Directory where the JasperReports project file was extracted,
needs to be changed to match the local environment -->
<property name="jasper.dir" value="/usr/local/share/java/jasperreports-1.1.0"/>
<property name="classes.dir" value="${jasper.dir}/build/classes"/>
<property name="lib.dir" value="${jasper.dir}/lib"/>
<path id="classpath">
<pathelement location="./"/>
<pathelement location="${classes.dir}"/>
<fileset dir="${lib.dir}">
<include name="**/*.jar"/>
</fileset>
</path>
<target name="viewDesignXML"
description="Launches the design viewer to preview the XML report design.">
<java classname="net.sf.jasperreports.view.JasperDesignViewer" fork="true">
<arg value="-XML"/>
<arg value="-F${file.name}.jrxml"/>
<classpath refid="classpath"/>
</java>
</target>
<target name="viewDesign"
description="Launches the design viewer to preview the compiled report design.">
<java classname="net.sf.jasperreports.view.JasperDesignViewer" fork="true">
<arg value="-F${file.name}.jasper"/>
<classpath refid="classpath"/>
</java>
</target>
<target name="compile"
description="Compiles the XML report design 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>
可以从命令行来调用这个新目标: ant compile
编译目标会产生如下的输出:
Buildfile: build.xmlcompile: [jrc] Compiling 1 report design files. [jrc] log4j:WARN No appenders could be found for logger (org.apache.commons.digester.Digester.sax). [jrc] log4j:WARN Please initialize the log4j system properly. [jrc] File : /home/heffel/personal_workspace/JasperBookExamples/reports/FirstReport.jrxml ... OK.BUILD SUCCESSFULTotal time: 4 seconds
目标编译完成后,我们会在文件系统里得到一个FirstReport.jasper文件。
这个文件和通过调用net.sf.jasperreports.engine.JasperCompileManager.compileReportToFile()生成的文件是一样的。
注:从上面的输出可以看到,JRC目标会生成log4j警告,我们可以放心地忽略掉它们。
这里生成的Jasper文件也可以用JasperReports中包含的JasperDesign工具进行预览,其输出与前面的介绍是相同的。
生成报表
按照JasperReports的习惯,从报表模板或Jasper文件生成报表的处理过程,称为填充(filling)报表。报表通过程序来进行填充,具体调用的是net.sf.jasperreports.engine.JasperFillManager类的fillReportToFile()方法。此方法会将填充完的报表保存到磁盘。
fillReportToFile()方法有六个重载版本,如下所示:
* JasperFillManager.fillReportToFile(JasperReport jasperReport, String destFileName, Map parameters, Connection connection)
* JasperFillManager.fillReportToFile(JasperReport jasperReport, String destFileName, Map parameters, JRDataSource datasource)
* JasperFillManager.fillReportToFile(String sourceFileName, Map parameters, Connection connection)
* JasperFillManager.fillReportToFile(String sourceFileName, Map parameters, JRDatasource dataSource)
* JasperFillManager.fillReportToFile(String sourceFileName, String destFileName, Map parameters, Connection connection)
* JasperFillManager.fillReportToFile(String sourceFileName, String destFileName, Map parameters, JRDataSource dataSource)
下面的表格对这些方法的参数进行了说明:
参数
描述
JasperReport jasperReport
此参数用于报表模板,of net.sf.jasperreports.engine.JasperReport实例是编译后的报表模板在内存中的存在形式。
String destFileName
指定用于保存报表的目标文件名。
Map parameters
这是一个java.util.Map接口实现类的实例,用于初始化报表模板中定义的所有报表参数。
Connection connection
此参数用于连接数据库,以便执行报表模板中定义的SQL查询。
JRDataSource dataSource
这是一个net.sf.jasperreports.engine.JRDataSource接口实现类的实例。JasperReports提供了一些JRDataSource接口的实现类,我们也可以创建自己的实现类。
String sourceFileName
此参数指定编译后的报表模板在文件系统中的位置,生成的报表使用和它相同的文件名,只是用.jrprint扩展名取代了.jasper扩展名。
在大多数情况下,我们通过一个实现了net.sf.jasperreports.engine.JRDataSource接口的类实例来传送填充报表的数据。报表模板可以嵌入SQL查询,它们定义在JRXML文件的<queryString>元素中。包含有SQL查询的报表不会传递 JRDataSource,而是传递一个实现了java.sql.Connection接口的类实例。JasperReports再用这个 Connection对象执行查询,从数据库获取报表数据。
在这里的报表例子中,我们只包含了静态文本,不需要显示动态数据。没有JRDataSource或Connection就没办法填充报表,因此JaspreReports提供了一个不包含任何数据的 JRDataSoruce实现,其名称为JREmptyDataSource。另外,由于我们这里的报表没有参数,所以只需传递一个 java.util.HashMap的空实例。我们将遵循JasperReports推荐的方法,把报表命名为与报表模板相同的名字。在此处,最适当的 fillReportToFile()版本是上面列出的第4个,如下所示:
JasperFillManager.fillReportToFile(String sourceFileName, Map parameters, JRDataSource dataSource)
下面的Java类将添充报表,并把它保存在磁盘里:
package net.ensode.jasperbook;
import java.util.HashMap;
import net.sf.jasperreports.engine.JREmptyDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperFillManager;
public class FirstReportFill {
public static void main(String[] args) {
try {
System.out.println("Filling report");
JasperFillManager.fillReportToFile("reports/FirstReport.jasper",
new HashMap(), new JREmptyDataSource());
System.out.println("Done!");
}
catch (JRException e) {
e.printStackTrace();
}
}
}
执行这个类,我们会在编译FirstReport.jasper报表模板的目录里得到一个名为FirstReport.JRprint的文件。
查看报表
JasperReports 中有个工具类net.sf.jasperreports.view.JasperViewer,可以用来查看生成的报表。其最简使用方法是:把它包装到 ANT目标里。这也是JasperReprots内含示例程序的原因所在。现在让我们添加一个新的目标到ANT构建文件中,按照 JasperReports范例中的惯例,我们将对此目标视图进行命名。
<project name="FirstReport XML Design Preview" default="viewDesignXML" basedir=".">
<description>Previews and compiles our First Report</description>
<property name="file.name" value="FirstReport"/>
<!-- Directory where the JasperReports project file was extracted,
needs to be changed to match the local environment -->
<property name="jasper.dir" value="/usr/local/share/java/jasperreports-1.1.0"/>
<property name="classes.dir" value="${jasper.dir}/build/classes"/>
<property name="lib.dir" value="${jasper.dir}/lib"/>
<path id="classpath">
<pathelement location="./"/>
<pathelement location="${classes.dir}"/>
<fileset dir="${lib.dir}">
<include name="**/*.jar"/>
</fileset>
</path>
<target name="viewDesignXML"
description="Launches the design viewer to preview the XML report design.">
<java classname="net.sf.jasperreports.view.JasperDesignViewer" fork="true">
<arg value="-XML"/>
<arg value="-F${file.name}.jrxml"/>
<classpath refid="classpath"/>
</java>
</target>
<target name="viewDesign"
description="Launches the design viewer to preview the compiled report design.">
<java classname="net.sf.jasperreports.view.JasperDesignViewer" fork="true">
<arg value="-F${file.name}.jasper"/>
<classpath refid="classpath"/>
</java>
</target>
<target name="compile"
description="Compiles the XML report design 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>
<target name="view" 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>
</project>
执行这个新的ANT目标,我们将看到一个如下图所示的窗口:
对,就是它!这就是我们成功创建的第一份报表。
在浏览器中显示报表
前面我们讨论了怎样创建报表,并用JasperReports的本地格式保存了磁盘。下面我们介绍如何在web浏览器里显示报表,这需要借助于Servlet API,如下面的例子所示:
package net.ensode.jasperbook;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashMap;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.jasperreports.engine.JREmptyDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperRunManager;
public class FirstReportSendToBrowserServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletOutputStream servletOutputStream = response.getOutputStream();
InputStream reportStream = getServletConfig().getServletContext()
.getResourceAsStream("/reports/FirstReport.jasper");
try {
JasperRunManager.runReportToPdfStream(reportStream,
servletOutputStream, new HashMap(), new JREmptyDataSource());
response.setContentType("application/pdf");
servletOutputStream.flush();
servletOutputStream.close();
}
catch (JRException e) {
// display stack trace in the browser
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
e.printStackTrace(printWriter);
response.setContentType("text/plain");
response.getOutputStream().print(stringWriter.toString());
}
}
}
由于Web浏览器不能显示JasperReports的本地格式的报表(在不使用applet的情况下),我们必须把报表导出为浏览器可以识别的格式。 JasperReports允许我们把报表导出为PDF等多种格式,由于PDF格式的广泛使用,我们在此处的示例中就选择它作为导出格式。
上例中的Servlet调用了静态方法JasperRunManager.runReportToPdfStream(),其格式为:
runReportToPdfStream ( java.io.InputStream inputStream,
java.io.OutputStream outputStream,
java.util.Map parameters,
JRDataSource dataSource)
要想在浏览器中显示报表,我们需要在第一个参数中以流的形式传入二进制报表模板,也就是Jasper文件。我们可以通过调用 javax.servlet.ServletContext.getResourceAsStream()方法达到这个目的,它需要传入一个包含 Jasper文件位置的String作为参数。此方法返回一个java.io.InputStream实例,我们可以把它用作 JasperRunManager.runReportToPDFStream()方法的第一个参数。
JasperRunManager.runReportToPDFStream ()方法需要一个java.io.OutputStream()实例来对编译后的报表执行写操作。我们可以简单地使用Servlet的缺省的输出流,可以通过调用javax.servlet.http.HttpServletResponse.getOutputStream()方法得到它。
JasperRunManager.runReportToPDFStream ()方法的另外两个参数是java.util.Map和JRDataSource,前者用于传递报表的任意参数,后者用于以 net.sf.jasperreports.engine.JRDataSource形式传递数据。这里的例子中,我们不需要传递任何参数和数据,所以使用一个空的HashMap和JREmptyDataSource。
为了确保浏览器正确地显示报表,我们必须把内容类型设置为application/pdf,通过调用javax.servlet.http.HttpServletResponse.setContentType()方法可以完成这件事。
最后的示例代码需要部署到一个Servlet容器中,我们可以通过ANT脚本来自动地完成这一过程。下面的屏幕截图显示了浏览器中的PDF格式报表:
JRXML报表模板的元素
在前面的袋子中,我们用JRXML报表模板的<detail>元素来生成了一个显示静态文本的报表,<detail>元素表示报表的主区域。当然,JRXML模板还可以包含许多其它元素来在报表中显示次级辅助数据、执行类似导入Java包的任务、设置报表字体等。除个别特例外,大部分的元素都可以在模板中使用多次。下面就来介绍一下<jasperReporot>根元素的全部子元素。
<property>
此元素用来给报表模板添加任意的信息。
<property name="someproperty" value="somevalue"/>
加裁了报表的Java应用程序通过调用JasperReport.getProperty()方法可以载入这些属性。JRXML模板可以包含零个或多个<property>元素。
<import>
此元素用于导入个别的Java类或完整的包。
<import value="java.util.HashMap"/>
JRXML模板可以包含零个或多个<import>元素。
<reportFont>
此元素用来定义一个或多个字体,这些字体可用于报表中显示的文本。
<reportFont name="Arial" isDefault="true" fontName="Arial" size="12"
isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false"
pdfFontName="Helvetica" pdfEncoding="CP1252" isPdfEmbedded="false"/>
JRXML模板可以包含零个或多个<reportFont>元素。
<parameter>
此元素用于定义报表参数,参数值通过调用JasperReports API中的相应方法以java.uitl.Map来提供。
<parameter name="SomeParameter" class="java.lang.String"/>
JRXML模板可以包含零个或多个<parameter>元素。
<queryString>
此元素用于定义从数据库获取数据的SQL查询。
<queryString>
<![CDATA[Select column_name FROM table_name]]>
</queryString>
JRXML模板可以包含零个或一个<queryString>元素。如果我们希望把SQL查询嵌入到报表模板中,必需使用此元素。
<field>
此元素用于把从数据源或查询获取的数据映射到报表模板。Field可以嵌入到报表表达式中,从而获得所需的输出。
<field name="FieldName" class="java.lang.String"/>
JRXML模板可以包含零个或多个<field>元素。
<variable>
报表中多次使用的表达式可以赋值给变量,从而简化模板。
<variable name="VariableName" class="java.lang.Double" calculation="Sum">
<variableExpression>
$F{FieldName}
</variableExpression>
</variable>
JRXML模板可以包含零个或多个<variable>元素。
<group>
此元素用于对连续的纪录进行分组,分组的依据是数据源的一些共同特征。
<group name="GroupName">
<groupExpression>
<![CDATA[$F{FieldName}]]>
</groupExpression>
</group>
JRXML模板可以包含零个或多个<group>元素。
<background>
此元素定义页的背景,它对报表的所有页有效。它可以显示图片、文本或水印。
<background>
<band height="745">
<image scaleImage="Clip" hAlign="Left" vAlign="Bottom">
<reportElement x="0" y="0" width="160" height="745"/>
<imageExpression>"image.gif"</imageExpression>
</image>
</band>
</background>
JRXML模板可以包含零个或一个<background>元素。
<title>
这是报表的标题,它只在报表起始处显示一次。
<title>
<band height="50">
<staticText>
<reportElement x="180" y="0" width="200" height="20"/>
<text>
<![CDATA[Title]]>
</text>
</staticText>
</band>
</title>
JRXML模板可以包含零个或一个<title>元素。
<pageHeader>
此元素定义页眉,它在报表每一页的起始处打印。
<pageHeader>
<band height="20">
<staticText>
<reportElement x="180" y="30" width="200" height="20"/>
<text>
<![CDATA[Page Header]]>
</text>
</staticText>
</band>
</pageHeader>
JRXML模板可以包含零个或一个<pageHeader>元素。
<columnHeader>
如果报表只有一列,些元素将被忽略掉。
<columnHeader>
<band height="20">
<staticText>
<reportElement x="180" y="50" width="200" height="20"/>
<text>
<![CDATA[Column Header]]>
</text>
</staticText>
</band>
</columnHeader>
JRXML模板可以包含零个或多个<columnHeader>元素,模板中<columnHeader>元素的数量必需和列数相同。
<detail>
此元素定义报表的详情段,报表数据源的每条纪录都会重复地使用它。
<detail>
<band height="20">
<textField>
<reportElement x="10" y="0" width="600" height="20"/>
<textFieldExpression class="java.lang.String">
<![CDATA[$F{FieldName}]]>
</textFieldExpression>
</textField>
</band>
</detail>
JRXML模板可以包含零个或一个<detail>元素。大多数据报表模板只包含一个<detail>元素,因为通常情况下,这是显示报表主要数据的地方。
<columnFooter>
如果报表只有一列,此元素将被忽略掉。
<columnFooter>
<band height="20">
<staticText>
<reportElement x="0" y="0" width="200" height="20"/>
<text>
<![CDATA[Column Footer]]>
</text>
</staticText>
</band>
</columnFooter>
JRXML模板可以包含零个或多个<columnFooter>元素,模板中<columnFooter>元素的数量必需和列数相同。
<pageFooter>
此元素定义页脚,它在报表每一页的末尾处打印。
<pageFooter>
<band height="20">
<staticText>
<reportElement x="0" y="5" width="200" height="20"/>
<text>
<![CDATA[Page Footer]]>
</text>
</staticText>
</band>
</pageFooter>
JRXML模板可以包含零个或一个<pageFooter>元素。
<lastPageFooter>
此元素定义的数据显示在最后一页的页脚,取代<pageFooter>元素的页脚定义。
<lastPageFooter>
<band height="20">
<staticText>
<reportElement x="0" y="5" width="200" height="20"/>
<text>
<![CDATA[Last Page Footer]]>
</text>
</staticText>
</band>
</lastPageFooter>
JRXML模板可以包含零个或一个<lastPageFooter>元素。
<summary>
它仅在报表末尾打印一次。
<summary>
<band height="20">
<staticText>
<reportElement x="0" y="5" width="200" height="20"/>
<text>
<![CDATA[Summary]]>
</text>
</staticText>
</band>
</summary>
JRXML模板可以包含零个或一个<summary>元素。
和<detail>元素一样,前面讨论的其它的每个元素也都包含一个单独的<band>元素作为其子元素。在此,暂时不对其作更深入的讨论。
从下面的截图中,我们可以直观地看到一个报表中的不同区域所处的相应位置:
需要特别说明的是,正如我们所见,页脚标签为Page Footer/Last Page Footer。如果报表的JRXML模板包含一个<lastPageFooter>元素,它将在最后一页代替<pagefooter>元素进行显示。在一些特殊情况下,如果报表只有一页,并且在模板中既有<pageFooter>元素,又有< lastPageFooter>元素,那么,<lastPageFooter>的内容将被显示。这种情况下,< pageFooter>元素永远不会被显示。此外,<columnHeader>和<columnFooter>元素只有报表多于一列时才会被显示。
小结
本章我们讨论了通过编辑XML文件来创建JRXML报表模板,以及通过JasperReports提供的工具来预览这些模板。同时我们还讨论了通过编码方式或自定义的ANT任务来编译JRXML模板。
编译完报表后,我们通过调用JasperFillManager类提供的相应方法,把数据填充到报表中。还用JaserViewer工具对生成的要地JasperReports格式报表进行预览。我们还了解了JRXML模板中不同的报表区域。
最后,我们创建了基于Web的报表,并在Web浏览器中显示生成的报表。