JavaScud | Forum | JIRA | Blog |
  Dashboard > WebWork2文档中文化计划 > WebWork > JasperReports
  WebWork2文档中文化计划 Log In View a printable version of the current page.  
  JasperReports
Added by Tin Steeler, last edited by scud on Mar 28, 2006  (view change)
Labels: 
(None)

介绍

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 (但是在以前的版本下也应该可以工作)
JasperReports 1.1.0
JDK 1.4.2

好的, 我们开始.

代码

我们先定义一个简单的POJO: Person.java

com.mevipro.test.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

com.mevipro.test.action.JasperAction
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设计器.

our_jasper_template.jrxml
<?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了:

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时,无法显示出图片,请问?这种方法生成的文件是存在好个位置的,如何设置!

Posted by Anonymous at Jun 22, 2006 23:22 | Reply To This

需要在Web.xml文件中配置一个Servlet
<servlet>
<servlet-name>ImageServlet</servlet-name>
<servlet-class>net.sf.jasperreports.j2ee.servlets.ImageServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>ImageServlet</servlet-name>
<url-pattern>/servlets/image</url-pattern>
</servlet-mapping>

Posted by Anonymous at Jan 11, 2007 10:11 | Reply To This

我没有配置Servlet,只把生成的pk图片拷贝到你的web工程目录的images目录下就行了。
pk是只有一个像素的图片,可以在ireport的目录中搜索一下。
他并没有后缀。

Posted by Anonymous at Feb 28, 2007 14:19 | Reply To This

我能成功生成PDF文档和HTML文档,在此表示感谢!!
但是我的PDF文档是在IE外部打开的,并不是内嵌在IE浏览器内部。
请问有没有好的解决办法??

还有,"不要在实际工作状态(production code)这样使用.",
那么在实际工作中应该怎样使用??

Posted by Anonymous at Feb 28, 2007 14:15 | Reply To This

这里说的不要在实际工作中这样使用,是因为例子中的程序每次调用jsper模板时都要重新编译一次模版,效率就会比较低,通常都是通过工具,如ireport等预先编译好,然后让程序调用

Posted by Anonymous at Mar 08, 2007 20:40 | Reply To This

帮一下啊,我的action是这样的:
public String listForJasper() throws Exception {
if (log.isDebugEnabled())

Unknown macro: { log.debug("performing listForJasper() method!"); }

try
Unknown macro: { String reportSource = ServletActionContext.getServletContext().getRealPath("/jasper/provinces_report.jrxml"); File parent = new File(reportSource).getParentFile(); JasperCompileManager.compileReportToFile( reportSource, new File(parent, "provinces_report.jasper").getAbsolutePath()); }
catch (Exception e)
Unknown macro: { e.printStackTrace(); return ERROR; }

provinces=provinceDAO.listAllOrderBy(true,"id");
//provinces = provinceDAO.listByPageOrderBy(pageSize, pageno, true, "id");
return SUCCESS;
}
xwork.xml的配置文件是这样的:
<action name="jasperListForProvice" class="provinceAction" method="listForJasper">
<result name="success" type="jasper">
<param name="location">/jasper/provinces_report.jasper</param>
<param name="dataSource">provinces</param>
<param name="format">PDF</param>
<param name="documentName">provincesreport</param>
</result>
</action>
但显示pdf是空的,没有任何值.全部是null,这是什么原因了

Posted by Anonymous at Mar 28, 2007 15:55 | Reply To This

我按照以上步骤做了之后,控制台没有抛错,但是页面上有抛错,而且pdf出不来,我用的是webwork2.2.2,web.xml关于那个图片的配置不是必须的吧,请问pdf出不来一般是哪些原因造成的,result的配置肯定是对的,.jasper文件也都有了,jasperreport的包我也加了,搞不清楚了

Posted by Anonymous at Mar 29, 2007 13:08 | Reply To This

默认的 jasper result type好像已经从Stuts 2.06的 struts-default.xml中删除了,如果要使用的话,好像要自定义result type了,不知道如何自定义result type,在http://www.opensymphony.com/webwork/wikidocs/Result%20Types.html上有简单的文档,但看了不是很明白,那位高人给点建议,我的邮箱bencmai@21cn.com,希望使用struts2的朋友交流一下

Posted by Anonymous at Jun 14, 2007 02:08 | Reply To This
Site running on a free Atlassian Confluence Open Source Project License granted to WebWork China. Evaluate Confluence today.
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.5.3 Build:#808 May 29, 2007) - Bug/feature request - Contact Administrators