介绍
JasperReports(http://jasperreports.sourceforge.net)是领先的java开源报表库. 它将.jrxml(XML源文件)编译为.jasper(=编译后版本)文件, 它可以被转换为多种格式输出(PDF, CSV, XLS and HTML).
下面的例子, 我们使用Webwork动态创建人员列表的PDF文件. 我们的WW action用来创建对象的List, 而JasperReport Result用这个list来填充模版, 返回PDF文件.
我们假设你已经掌握WW web应用程序基本知识.
注意: 虽然例子非常简单, 我还是建议你详细的阅读WW和JR的相关文档. |
使用的版本 Webwork 2.2 beta 3 (但是在以前的版本下也应该可以工作) |
好的, 我们开始.
代码
我们先定义一个简单的POJO: Person.java
package com.mevipro.test;
public class Person {
private Long id;
private String name;
private String lastName;
public Person() {
super();
}
public Person(String name, String lastName) {
super();
this.name = name;
this.lastName = lastName;
}
public Person(Long id, String name, String lastName) {
super();
this.id = id;
this.name = name;
this.lastName = lastName;
}
/**
* @return Returns the id.
*/
public Long getId() {
return id;
}
/**
* @param id The id to set.
*/
public void setId(Long id) {
this.id = id;
}
/**
* @return Returns the lastName.
*/
public String getLastName() {
return lastName;
}
/**
* @param lastName The lastName to set.
*/
public void setLastName(String lastName) {
this.lastName = lastName;
}
/**
* @return Returns the name.
*/
public String getName() {
return name;
}
/**
* @param name The name to set.
*/
public void setName(String name) {
this.name = name;
}
}
没什么特殊之处. 只有简单的属性, 构造方法, 还有getters和setters.
JasperReports库
在我们继续之前, 我们需要将JR库添加到classpath. 你可以从这里下载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拷贝到你的WW_WEBAPP/WEB-INF/lib目录, 然后将它们添加到你的classpath.
让我们看看Action
package com.mevipro.test.action;
import java.util.ArrayList;
import java.util.List;
import net.sf.jasperreports.engine.JasperCompileManager;
import com.mevipro.test.Person;
import com.opensymphony.xwork.ActionSupport;
public class JasperAction extends ActionSupport {
//basic List - it will serve as our dataSource later on
private List myList;
/*
* (non-Javadoc)
*
* @see com.opensymphony.xwork.ActionSupport#execute()
*/
public String execute() throws Exception {
// create some imaginary persons
Person p1 = new Person(new Long(1), "Patrick", "Lightbuddie");
Person p2 = new Person(new Long(2), "Jason", "Carrora");
Person p3 = new Person(new Long(3), "Alexandru", "Papesco");
Person p4 = new Person(new Long(4), "Jay", "Boss");
/*
* store everything in a list - normally, this should be coming from a
* database but for the sake of simplicity, I left that out
*/
myList = new ArrayList();
myList.add(p1);
myList.add(p2);
myList.add(p3);
myList.add(p4);
/*
* Here we compile our xml jasper template to a jasper file.
* Note: this isn't exactly considered 'good practice'.
* You should either use precompiled jasper files (.jasper) or provide some kind of check
* to make sure you're not compiling the file on every request.
* If you don't have to compile the report, you just setup your data source (eg. a List)
*/
try {
JasperCompileManager.compileReportToFile(
"WW_WEBAPP/jasper/our_jasper_template.jrxml",
"WW_WEBAPP/jasper/our_compiled_template.jasper");
} catch (Exception e) {
e.printStackTrace();
return ERROR;
}
//if all goes well ..
return SUCCESS;
}
/**
* @return Returns the myList.
*/
public List getMyList() {
return myList;
}
}
和刚才的代码一样--无需解释就很清楚了. 我们的JasperAction创建了一些人员的list. JasperCompileManager会将jrxml模版编译为.jasper文件.
不要在实际工作状态(production code)这样使用. 你当然应该提供编译后的模版文件, 或者做好变更检测, 来避免在每次请求时都重新编译模版. 但是在我们演示或者开发的过程中这样的方式很方便. |
我们的Jasper模版
JR使用一种特殊的XML页面定义模版, 它会被编译为.jasper文件. 这些模版将会被用来设计结果报表. 它相当直接.
这是一个手写的版本 - 对于更加复杂的版本我强烈建议你看看各种各样的GUI设计器.
<?xml version="1.0"?> <!DOCTYPE jasperReport PUBLIC "-//JasperReports//DTD Report Design//EN" "http://jasperreports.sourceforge.net/dtds/jasperreport.dtd"> <jasperReport name="jasper_test"> <!-- our fields --> <field name="name" class="java.lang.String"/> <field name="lastName" class="java.lang.String"/> <title> <band height="50"> <staticText> <reportElement x="0" y="0" width="180" height="15"/> <textElement/> <text> <![CDATA[Webwork JasperReports Sample]]> </text> </staticText> </band> </title> <pageHeader> <band></band> </pageHeader> <columnHeader> <band height="20"> <staticText> <reportElement x="180" y="0" width="180" height="20"/> <textElement> <font isUnderline="true"/> </textElement> <text> <![CDATA[NAME]]> </text> </staticText> <staticText> <reportElement x="360" y="0" width="180" height="20"/> <textElement> <font isUnderline="true"/> </textElement> <text> <![CDATA[LASTNAME]]> </text> </staticText> </band> </columnHeader> <detail> <band height="20"> <textField> <reportElement x="180" y="0" width="180" height="15"/> <textElement/> <textFieldExpression> <![CDATA[$F{name}]]> </textFieldExpression> </textField> <textField> <reportElement x="360" y="0" width="180" height="15"/> <textElement/> <textFieldExpression> <![CDATA[$F{lastName}]]> </textFieldExpression> </textField> </band> </detail> <columnFooter> <band></band> </columnFooter> <pageFooter> <band height="15"> <staticText> <reportElement x="0" y="0" width="40" height="15"/> <textElement/> <text> <![CDATA[Page:]]> </text> </staticText> <textField> <reportElement x="40" y="0" width="100" height="15"/> <textElement/> <textFieldExpression class="java.lang.Integer"> <![CDATA[$V{PAGE_NUMBER}]]> </textFieldExpression> </textField> </band> </pageFooter> <summary> <band></band> </summary> </jasperReport>
将文件存储到WW_WEBAPP/jasper/, 命名为'our_jasper_template.jrxml'.
最重要的:我们声明了name和lastName字段(不奇怪, 这两个属性来自我们的Person.class). 这意味着我们现在可以在我们的Jasper模版中使用这些字段.
我们定义了两个表头(NAME和LASTNAME), 然后将我们的字段们添加到一行的detail band(详细的解释请参照JR的教程). 'detail' band将会从人员的List中迭代. 这是JR的默认行为 - 所以如果你想显示人员的更多信息, 把它们添加到这个band中.
在detail band我们使用了
$F{name}
表达式. 这意味着JR会询问WW如何获取字段的值. 我们将会从WW值栈中寻找这些值(寻找人员, 调用getName()这个getter), 然后返回它. 后面的也一样
$F{lastName}
余下部分的大部分标记用来定义布局.
如果你遇到困难,在debug状态下通过logger(commons-logging, log4j, ..)来观察com.opensymphony.webwork.views.jasperreports可以方便寻找问题所在. |
注册Action
好了, 可以将我们的action添加到xwork.xml了:
<action name="myJasperTest" class="com.mevipro.test.action.JasperAction"> <result name="success" type="jasper"> <param name="location">/jasper/our_compiled_template.jasper</param> <param name="dataSource">myList</param> <param name="format">PDF</param> </result> </action>
我们进一步看一看. 我假设你已经熟悉了xwork的符号和schema, 如果你还不熟悉请查阅文档.
<action name="myJasperTest" class="com.mevipro.test.action.JasperAction">
我们将我们的JasperAction注册为'myJasperTest' - 这意味着我们可以在浏览器中通过myJasperTest.action发出请求来执行我们的Action.
<result name="success" type="jasper">
当我们的JasperAction执行正确, 我们使用注册为'jasper'的Result type. 如果你include了webwork-default, 它就已经被配置好了
<include file="webwork-default.xml"/>
这种result type根据我们的参数params配置, 配置如下:
<param name="location">/jasper/our_compiled_template.jasper</param>
这个参数定义了我们编译好的jasper文件的位置, 它将被WW根据我们的数据源dataSource填充:
<param name="dataSource">myList</param>
数据源的名称 - 就是你需要调用的getter的名字(上面的配置会调用你的JasperAction中的getMyList()方法). 它将被用来以数据填充模版.
<param name="format">PDF</param>
这一行制定了jasper被转换成的文件格式. 值可以是: PDF, CSV, XLS and HTML.
结论
你现在可以执行http://localhost:8080/YOUR_WEBAPP/myJasperTest.action - 然后你会看到一个不错的名字列表.
WW提供了处理JasperReport文件的最优雅解决方案(也许); 指定.jasper文件的位置, 指定你希望使用的数据源dataSource, 然后它就可以工作了.
我直接生成html时,无法显示出图片,请问?这种方法生成的文件是存在好个位置的,如何设置!