JavaWeb从入门到精通(视频实战版)
上QQ阅读APP看书,第一时间看更新

6.8 在Struts中使用JasperReports

JasperReports(简称JR)是目前应用广泛并且技术领先的Java开源报表库。它将.jrxml(XML源文件)编译为.jasper(编译后版本)文件,它可以被转换为多种格式输出(PDF、CSV、XLS和HTML)。本节以一个例子讲述JasperReports在Struts2中是如何配置和使用的。关于JasperReports的原理和详细使用方法请参考JasperReports自身文档。

6.8.1 准备JasperReports库

在使用JasperReports之前,需要将JR库添加到classpath。可以从“http://www.sourceforge.net/projects/jasperreports”下载JR项目。将jasperreports-X-project.zip存储到硬盘,将文件解压缩。需要如下文件:

❑ dist/jasperreports-X.jar

❑ lib/commons-*.jar (all the commons-except maybe for commons-logging)

❑ lib/itext-X.jar

❑ lib/jdt-compiler.jar

将这些jar拷贝到/WEB-INF/lib目录,然后将它们添加到CLASSPATH。

JasperReports在Struts2中是作为一个plugin出现的,需要在Struts2包提供的lib目录中找到struts2-jasperreports-plugin-xxx.jar,把这个jar文件也添加到/WEB-INF/lib目录,同样添加到CLASSPATH。

6.8.2 定义值对象

先定义一个简单的POJO(简单的Java对象,Plain Old Java Objects),实际就是普通JavaBeans。使用POJO名称是为了和EJB区分,而且简称比较直接。有一些属性及其getter、setter方法的类,有时可以作为值对象来使用,如实例6-29所示。

【实例6-29】关于对象类:Person.java

01     /*
02     *简单POJO不包含任何复杂逻辑
03     */
04     public class Person {
05          //创建各种变量
06          private Long id;                                               //创建id变量
07          private String name;                                           //创建name变量
08          private String lastName;                                        //创建lastName 变量
09          //无参数构造函数
10          public Person() {
11          }
12          //带参构造函数
13          public Person(String name, String lastName) {
14                this.name = name;
15                this.lastName = lastName;
16          }
17          //带参构造函数
18          public Person(Long id, String name, String lastName) {
19                this.id = id;
20                this.name = name;
21                this.lastName = lastName;
22          }
23          /**
24           * @返回 id
25           */
26          public Long getId() {
27                return id;
28          }
29
30          /**
31           * @id的setter方法
32           */
33          public void setId(Long id) {
34                this.id = id;
35          }
36
37          /**
38           * @返回 lastName
39           */
40          public String getLastName() {
41                return lastName;
42          }
43
44          /**
45           * @ lastName 的setter方法
46           */
47          public void setLastName(String lastName) {
48                this.lastName = lastName;
49          }
50
51          /**
52           * @返回 name
53           */
54          public String getName() {
55                return name;
56          }
57
58          /**
59           * @name属性的setter方法
60           */
61          public void setName(String name) {
62                this.name = name;
63          }
64     }

【代码剖析】在上述代码中,首先定义了三个成员变量id、name和lastName,然后又创建了三个构造函数,最后为所有的成员变量创建getter和setter方法。

6.8.3 编写action类

JasperAction创建了一些人员的列表。JasperCompileManager会将jrxml模板编译为.jasper文件。在实际程序中不要这样做,不需要在每个请求中都把jrxml文件编译为jasper文件,只需要执行一次就可以了,发布的时候直接使用jasper文件就可以了,如实例6-30所示。

【实例6-30】关于action类:ActionSupport.java

01     package jasperreports;
02     import java.io.File;
03     import java.util.*;
04     import net.sf.jasperreports.engine.JasperCompileManager;
05     import org.apache.struts2.ServletActionContext;
06     public class ActionSupport extends com.opensymphony.xwork2.ActionSupport {
07          // 这个list是作为数据源存在的
08          private List myList;
09          public String execute() throws Exception {              //重写执行方法
10                Person p1 = new Person(new Long(1), "Patrick", "Lightbuddie");
11                Person p2 = new Person(new Long(2), "Jason", "Carrora");
12                Person p3 = new Person(new Long(3), "Alexandru", "Papesco");
13                Person p4 = new Person(new Long(4), "Jay", "Boss");
14                /*
15                 * 把数据保存到一个list中去, 一般情况下这些数据可能来自于数据库, 本例
16     子中为了简单直接在程序中赋值
17                 */
18                myList = new ArrayList();
19                myList.add(p1);
20                myList.add(p2);
21                myList.add(p3);
22                myList.add(p4);
23                /*
24                 * 把 xml jasper 模板编译为一个jasper文件。在实际程序中不要这样做, 不需
25     要每个请求都把jrxml文件编译为jasper文件
26                * 直接使用jasper文件就可以了
27                */
28                try {
29                     String reportSource;
30                     reportSource = ServletActionContext.getServletContext()
31                                .getRealPath("/jasper/jasper_template.jrxml");
32                     File parent = new File(reportSource).getParentFile();
33                     JasperCompileManager.compileReportToFile(reportSource, new
34     File(
35                                parent,
36     "jasper_template.jasper").getAbsolutePath());
37                } catch (Exception e) {
38                     e.printStackTrace();
39                     return ERROR;
40                }
41               // 返回成功字符串
42                return SUCCESS;
43          }
44          /**
45           * @return 返回 myList.
46           */
47          public List getMyList() {                              //关于变量myList的getter方法
48                return myList;
49          }
50     }

【代码剖析】在上述代码中为了方便,手动创建了一个包含4个Person对象的myList集合,然后通过相关方法把jrxml模块编译成一个jasper文件,最后返回成功字符串SUCCESS。为了便于操作,还专门创建了一名为myList的成员变量,并设置该变量的getter方法。

6.8.4 编写Jasper模板

JR使用一种特殊的XML页面来定义模板,它会被编译为.jasper文件。这些模板将会被用来设计结果报表。本例中展示的是一个手写的版本,对于更加复杂的模板建议使用Jasper相关的GUI设计器(如ireport)来定义。

将文件存储到工程的目录下的“WW_WEBAPP/jasper”目录(此目录名是固定的不能改变),命名为“jasper_template.jrxml”。最重要的:声明了name和lastName字段(这两个属性来自Person.class)。这意味着现在可以在Jasper模板中使用这些字段。

定义了两个表头(NAME和LASTNAME),然后将字段添加到一行的detail band。detail band将会从人员的List中迭代。这是JR的默认行为,所以如果想显示人员的更多信息,把它们添加到这个band中。

在detail band使用了

$F{name}

这意味着JR会询问Struts如何获取字段的值。将会从Struts值栈中寻找这些值(寻找人员,调用getName()这个getter),然后返回它后面的:

$F{lastName}

余下部分的大部分标记用来定义布局,如实例6-31所示。

【实例6-31】JasperReports模板:jasper_template.jrxml

01     <?xml version="1.0"?>
02          <!DOCTYPE jasperReport
03        PUBLIC "-//JasperReports//DTD Report Design//EN"
04        "http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">
05          <jasperReport name="jasper_test">
06             <!--our fields-->
07             <field name="name" class="java.lang.String"/>
08             <field name="lastName" class="java.lang.String"/>
09             <title>
10                <band height="50">
11                  <staticText>
12                     <reportElement x="0" y="0" style="width:180" height="15"/>
13                     <textElement/>
14                     <text>
15                        <![CDATA[Webwork JasperReports Sample]]>
16                     </text>
17                  </staticText>
18                </band>
19             </title>
20             <pageHeader>
21                <band></band>
22             </pageHeader>
23             <columnHeader>
24                <band height="20">
25                  <staticText>
26                     <reportElement x="180" y="0" style="width:180" height="20"/>
27                     <textElement>
28                        <font isUnderline="true"/>
29                     </textElement>
30                     <text>
31                        <![CDATA[NAME]]>
32                     </text>
33                  </staticText>
34                  <staticText>
35                     <reportElement x="360" y="0" style="width:180" height="20"/>
36                     <textElement>
37                        <font isUnderline="true"/>
38                     </textElement>
39                     <text>
40                        <![CDATA[LASTNAME]]>
41                     </text>
42                  </staticText>
43                </band>
44             </columnHeader>
45             <detail>
46                <band height="20">
47                  <textField>
48                     <reportElement x="180" y="0" style="width:180" height="15"/>
49                     <textElement/>
50                     <textFieldExpression>
51                        <![CDATA[$F{name}]]>
52                     </textFieldExpression>
53                  </textField>
54                  <textField>
55                     <reportElement x="360" y="0" style="width:180" height="15"/>
56                     <textElement/>
57                     <textFieldExpression>
58                        <![CDATA[$F{lastName}]]>
59                     </textFieldExpression>
60                  </textField>
61                </band>
62             </detail>
63             <columnFooter>
64                <band></band>
65             </columnFooter>
66             <pageFooter>
67                <band height="15">
68                  <staticText>
69                     <reportElement x="0" y="0" style="width:40" height="15"/>
70                     <textElement/>
71                     <text>
72                        <![CDATA[Page:]]>
73                     </text>
74                  </staticText>
75                  <textField>
76                     <reportElement x="40" y="0" style="width:100" height="15"/>
77                     <textElement/>
78                     <textFieldExpression class="java.lang.Integer">
79                        <![CDATA[$V{PAGE_NUMBER}]]>
80                     </textFieldExpression>
81                  </textField>
82                </band>
83             </pageFooter>
84             <summary>
85                <band></band>
86             </summary>
87          </jasperReport>

【代码剖析】在上述代码中大部分内容都是自动生成的,所以这里就不详细介绍了。

6.8.5 配置struts.xml

将action添加到struts.xml,给这个action配置一个类型为jasper的result。Jasper类型的result不是Struts2默认就提供的,而是作为一个plugin出现,所以在配置中要继承包jasperreports-default,如实例6-32所示。

【实例6-32】JasperReports配置文件:struts.xml

01     <!DOCTYPE struts PUBLIC
02          "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
03          "http://struts.apache.org/dtds/struts-2.0.dtd">
04     <struts>
05          <!--JasperReports在struts.xml中的配置 -->
06          <package name="default" extends="struts-default,jasperreports-default">
07                <action name="PDF" class="jasperreports.ActionSupport">
08                     <result name="success" type="jasper">
09                          <param
10     name="location">/jasper/jasper_template.jasper</param>
11                          <param name="dataSource">myList</param>
12                          <param name="format">PDF</param>
13                     </result>
14               </action>                                    <!--当请求参数为HTML时-->
15                <action name="HTML" class="jasperreports.ActionSupport">
16                     <result name="success" type="jasper">
17                          <param
18     name="location">/jasper/jasper_template.jasper</param>
19                          <param name="dataSource">myList</param>
20                          <param name="format">HTML</param>
21                     </result>
22               </action>                                    <!--当请求参数为XML时-->
23                <action name="XML" class="jasperreports.ActionSupport">
24                     <result name="success" type="jasper">
25                          <param
26     name="location">/jasper/jasper_template.jasper</param>
27                          <param name="dataSource">myList</param>
28                          <param name="format">XML</param>
29                     </result>
30               </action>                                    <!--当请求参数为CSV时-->
31                <action name="CSV" class="jasperreports.ActionSupport">
32                     <result name="success" type="jasper">
33                          <param
34     name="location">/jasper/jasper_template.jasper</param>
35                          <param name="dataSource">myList</param>
36                          <param name="format">CSV</param>
37                     </result>
38               </action>                                    <!--当请求参数为XLS时-->
39                <action name="XLS" class="jasperreports.ActionSupport">
40                     <result name="success" type="jasper">
41                          <param
42     name="location">/jasper/jasper_template.jasper</param>
43                          <param name="dataSource">myList</param>
44                          <param name="format">XLS</param>
45                     </result>
46                </action>
47          </package>
48     </struts>

【代码剖析】

1)将ActionSupport注册为“PDF”这意味着可以在浏览器中通过PDF.action发出请求来执行这个Action。

2)当ActionSupport执行正确,由于继承了jasperreports-default,它就已经被配置好了。所以报表类型已经配置好。

<result name="success" type="jasper">

3)这种result type根据参数params配置。配置如下:

<param name="location">/jasper/jasper_template.jasper </param>

4)这个参数定义了编译好的jasper文件的位置,它将被Struts根据的数据源dataSource填充。数据源的名称就是需要调用的getter的名字(上面的配置会调用JasperAction中的getMyList()方法):

<param name="dataSource">myList</param>

5)它将被用来以数据填充模板,这一行指定了jasper被转换成的文件格式。值可以是PDF、CSV、XLS和HTML:

<param name="format">PDF</param>

注意

生成HTML报表时jasperreports会引用到WebRoot/images下一个名为px的文件(没有扩展名)。可以将jasperreports-2.0.2\net\sf\jasperreports\engine\images下的pixel.GIF文件复制到这个目录下并重命名为px。