- jimmy.shine
- 等级:
- 性别:
- 文章: 100
- 积分: 190
- 来自: 北京
|
共三篇,下接:http://jimmy-shine.iteye.com/blog/123595
为了开发报表,已经拜读了一大堆的资料,其中大部分是重复的。可以看得出,国人还是比较热衷于copy&paste的工作。所以找了一大堆的资料都是相同的,或者可以用一个词来形容,换汤不换药的。
有必要对于jasper Report的学习进度进行一下总结,一来可以更新一下以前的资料中的一些旧得不能再旧的不再适用的东西,二来让后来者可以轻松的上手。
首先,jasperReport是一个以java实现的报表工具,(好像是句废话)。可以实现多种格式的报表。
再我们先理解一下jasperReport的实现过程。笔者不再画图,网上到处都是。
1)定制报表格式。
有二种方式,一种就是写jrxml文件,其实就是xml文件,只不过是后缀名不一样罢了。另一种方式更直接,就是生成一个JasperDesign类的实例,在japsperDesign中自己定义模板。jrxml文件也是通过一个JRXmlLoad加载过来,转成JasperDesign类的实例。也就是说写jrxml文件还需要进行解析,加载。现实中我们使用的报表一般格式比较固定,因而可以通过先使用iReport工具生成模板,再加载解析的方式。这种方式简单,而且可见性强。
2)填充数据。
在最新版(2007.4.30发布)的jasperReports1.3.3中,支持了很多的格式,包括了对于Hibernate的支持。填充数据对于我们经常使用的来说,一般是二种方式,一种方式是通过JDBC连接提供数据源,一种就是通过javaBean的集合提供数据源。当然还有web Service的xml文件提供的。我的建议是,如果你的程序中的统计直接使用Jdbc就可以完成,那么就使用jdbc数据源的方法,反之,使用javaBean的集合是不错的选择,因为这样不会在意你的数据的来源,你也可以任意处理,比如说,要通过权限检查的数据才在报表中生成的话,就可以过滤到不符合权限的数据。
3)显示或打印。
显示,即将JasperReport生成的文件直接显示出来,打印所使用的方式其实就是生成文件,然后调用打印来对文件进行打印。
看起来是不是很简单,对,确实很简单。
笔者主要从事基于B/S模式的开发,相信大部分人的使用也是基于web进行使用。故笔者对于基于web的开发进行详细讲述。
1、工程环境配置。
将以下包加入WEB-INF/lib中。
commons-beanutils-1.7.jar;commons-collections-2.1.jar;commons-digester-1.7.jar;commons-logging-1.0.2.jar;commons-logging-api-1.0.2.jar;itext-1.3.1.jar;jasperreports-1.3.3.jar;jdt-compiler-3.1.1.jar;jxl-2.6.jar;png-encoder-1.5.jar;poi-2.0-final-20040126.jar
以上包是jasperReport必须。
2、iReport的安装
这个很简单,直接下一步就可以了。
3、使用iReport生成 .jasper文件
.jasper是经过编译的japserReport模板,即.jrxml编译后的。
对于iReport的使用网络上已经有了详细的中文的文档,具体可以下载附件查看。使用.jasper文件可以避免在系统中再进行编译,增加系统的压力。
4、数据填充
数据填充是相对于比较重要的一步,数据填充的目的是为了将数据填充进去,生成一个JapserPrint对象。笔者在之前已经阐述过,现在主要是基于关系型数据库(比较简单的,没有权限控制的),以及基于JavaBean Collection进行数据填充。进行数据填充的基本就是一定要实现JRDataSource,JRDataSource定义了二个方法,一个是指针移动的方法next(),另一个是取值的getFieldValue()方法,用来取值填充。
对于关系型数据库,即直接利用数据库的表来生成报表的,只需要传入一个Java Connection即可。JasperReport已经有了个默认的实现的JRDataSource的接口了。对于Java Conncetion的获得,笔者建议使用工厂方法或者使用Spring方式来获得。可以参照笔者写的如下:
java 代码
-
-
-
-
- package cn.com.reachway.framework.report;
-
- import java.sql.Connection;
- import java.sql.DriverManager;
-
- import cn.com.reachway.framework.exception.JasperReportException;
-
-
-
-
- public class JDBCConnection {
-
-
-
- private String jdbcDriver;
-
-
-
-
- private String jdbcUrl;
-
- private String dbUser;
-
- private String dbPassword;
-
- public String getDbPassword() {
- return dbPassword;
- }
-
- public void setDbPassword(String dbPassword) {
- this.dbPassword = dbPassword;
- }
-
- public String getDbUser() {
- return dbUser;
- }
-
- public void setDbUser(String dbUser) {
- this.dbUser = dbUser;
- }
-
- public String getJdbcDriver() {
- return jdbcDriver;
- }
-
- public void setJdbcDriver(String jdbcDriver) {
- this.jdbcDriver = jdbcDriver;
- }
-
- public String getJdbcUrl() {
- return jdbcUrl;
- }
-
- public void setJdbcUrl(String jdbcUrl) {
- this.jdbcUrl = jdbcUrl;
- }
-
- public JDBCConnection() {
- super();
- }
-
-
-
-
-
- public Connection getConnection() throws JasperReportException {
- Connection con;
- try {
- check();
- Class.forName(this.jdbcDriver);
- con = DriverManager.getConnection(this.jdbcUrl, this.dbUser, this.dbPassword);
- return con;
- } catch (Exception e) {
- e.printStackTrace();
- throw new JasperReportException("Get JDBC Connection Error");
- }
- }
-
-
-
-
-
- private void check() throws JasperReportException {
- if (this.jdbcDriver == null || this.jdbcDriver.equals("") || this.jdbcUrl == null || this.jdbcUrl.equals("")
- || this.dbUser == null || this.dbUser.equals("") || this.dbPassword == null) {
- throw new JasperReportException("Jdbc Configure error!");
- }
- }
-
- }
-
java 代码
-
-
-
-
- package cn.com.reachway.framework.report.dataSource;
-
- import net.sf.jasperreports.engine.JRDataSource;
- import net.sf.jasperreports.engine.JRException;
- import net.sf.jasperreports.engine.JRField;
-
-
-
-
- public abstract class ReportDataSource implements JRDataSource {
-
-
-
-
- public abstract Object getFieldValue(JRField jrField) throws JRException;
-
-
-
-
- public abstract boolean next() throws JRException;
-
- }
-
这样可以共用配置文件中的jdbc连接的相关参数。
对于其它的数据源,JavaBean Collection,笔者采用了一个抽象类,使用抽象类的目的,是为了使开发者尽可能不用直接接触jasperReport(此为笔者自己的方式,笔者是PM,为了考虑底下的人的开发)。以下为抽象类以及笔者提供的一个sample:
-
-
-
-
- package cn.com.reachway.framework.report.dataSource;
-
- import java.util.ArrayList;
- import java.util.List;
-
- import net.sf.jasperreports.engine.JRException;
- import net.sf.jasperreports.engine.JRField;
-
-
-
-
- public class ReportDataSourceSample extends ReportDataSource {
-
- private List docs = new ArrayList();
-
- private int index = -1;
-
- public ReportDataSourceSample() {
- for (int i = 0; i < 10; i++) {
- Document doc = new Document("ViewTimes is:" + i, i);
- this.docs.add(doc);
- }
- }
-
-
- private class Document {
- private String name;
-
- private int viewTimes;
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public int getViewTimes() {
- return viewTimes;
- }
-
- public void setViewTimes(int viewTimes) {
- this.viewTimes = viewTimes;
- }
-
- public Document() {
- }
-
- public Document(String name, int viewTimes) {
- this.name = name;
- this.viewTimes = viewTimes;
- }
- }
-
- public List getDocs() {
- return docs;
- }
-
- public void setDocs(List docs) {
- this.docs = docs;
- }
-
- @Override
- public Object getFieldValue(JRField jrField) throws JRException {
-
- String fieldName = jrField.getName();
- Document doc = this.docs.get(index);
- if ("name".equals(fieldName)) {
- return doc.getName();
- }
- if ("viewTimes".equals(fieldName)) {
- return doc.getViewTimes();
- }
- return null;
- }
-
- @Override
- public boolean next() throws JRException {
- index++;
- return (index < this.docs.size());
- }
- }
-
java 代码
以上的例子应当很清楚的写明了如何生成数据源。
对于数据源的填充,笔者使用了二个类,分别用来对应使用Connction及JavaBean Collection进行填充。
java 代码
-
-
-
-
- package cn.com.reachway.framework.report.jasperPrint;
-
- import java.io.File;
- import java.sql.Connection;
- import java.util.Map;
-
- import net.sf.jasperreports.engine.JRException;
- import net.sf.jasperreports.engine.JasperFillManager;
- import net.sf.jasperreports.engine.JasperPrint;
- import net.sf.jasperreports.engine.JasperReport;
- import net.sf.jasperreports.engine.util.JRLoader;
- import cn.com.reachway.framework.exception.JasperReportException;
-
-
-
-
- public class JasperPrintWithConnection {
-
- private Map params;
-
- private String reportFilePath;
-
- private Connection con;
-
- public Connection getCon() {
- return con;
- }
-
- public void setCon(Connection con) {
- this.con = con;
- }
-
- public Map getParams() {
- return params;
- }
-
- public void setParams(Map params) {
- this.params = params;
- }
-
- public String getReportFilePath() {
- return reportFilePath;
- }
-
- public void setReportFilePath(String reportFilePath) throws JasperReportException {
- if (reportFilePath == null || !reportFilePath.endsWith(".jasper"))
- throw new JasperReportException("您传入的模板文件格式不对,请传入以.jasper为后缀的文件!");
- this.reportFilePath = reportFilePath;
- }
-
- public JasperPrintWithConnection() {
- super();
- }
-
- public JasperPrintWithConnection(String reportFilePath, Map params, Connection con) throws JasperReportException {
- if (reportFilePath == null || !reportFilePath.endsWith(".jasper"))
- throw new JasperReportException("模板文件格式不对,请传入以.jasper为后缀的文件!");
- if (con == null)
- throw new JasperReportException("Conncetion不应当为null!");
- this.setReportFilePath(reportFilePath);
- this.setParams(params);
- this.setCon(con);
- }
-
-
-
-
-
-
- public JasperPrint getJasperPrint() throws JasperReportException {
- File reportFile = new File(this.reportFilePath);
- if (!reportFile.exists())
- throw new JasperReportException("传入的模板文件不存在!");
-
- try {
-
- JasperReport jasperReport = (JasperReport) JRLoader.loadObject(reportFile.getPath());
-
- JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, this.params, this.con);
- return jasperPrint;
-
- } catch (JRException jre) {
- jre.printStackTrace();
- throw new JasperReportException("在进行数据填充时发生了错误中,请检查是否是数据库连接错误或者是用来填充的参数map有误!");
- }
-
- }
- }
-
-
-
-
-
- package cn.com.reachway.framework.report.jasperPrint;
-
- import java.io.File;
- import java.util.Map;
-
- import net.sf.jasperreports.engine.JRDataSource;
- import net.sf.jasperreports.engine.JRException;
- import net.sf.jasperreports.engine.JasperFillManager;
- import net.sf.jasperreports.engine.JasperPrint;
- import net.sf.jasperreports.engine.JasperReport;
- import net.sf.jasperreports.engine.util.JRLoader;
- import cn.com.reachway.framework.exception.JasperReportException;
-
-
-
-
- public class JasperPrintWithDataSource {
-
- private Map params;
-
- private String reportFilePath;
-
- private JRDataSource dataSource;
-
- public JRDataSource getDataSource() {
- return dataSource;
- }
-
- public void setDataSource(JRDataSource dataSource) {
- this.dataSource = dataSource;
- }
-
- public Map getParams() {
- return params;
- }
-
- public void setParams(Map params) {
- this.params = params;
- }
-
- public String getReportFilePath() {
- return reportFilePath;
- }
-
- public void setReportFilePath(String reportFilePath) throws JasperReportException {
- if (reportFilePath == null || !reportFilePath.endsWith(".jasper"))
- throw new JasperReportException("您传入的模板文件格式不对,请传入以.jasper为后缀的文件!");
- this.reportFilePath = reportFilePath;
- }
-
- public JasperPrintWithDataSource() {
- super();
- }
-
- public JasperPrintWithDataSource(String reportFilePath, Map params, JRDataSource dataSource)
- throws JasperReportException {
- if (reportFilePath == null || !reportFilePath.endsWith(".jasper"))
- throw new JasperReportException("模板文件格式不对,请传入以.jasper为后缀的文件!");
- if (dataSource == null)
- throw new JasperReportException("DataSource不应当为null!");
- this.setReportFilePath(reportFilePath);
- this.setParams(params);
- this.setDataSource(dataSource);
- }
-
-
-
-
-
- public JasperPrint getJasperPrint() throws JasperReportException {
- File reportFile = new File(this.reportFilePath);
- if (!reportFile.exists())
- throw new JasperReportException("传入的模板文件不存在!");
-
- try {
-
- JasperReport jasperReport = (JasperReport) JRLoader.loadObject(reportFile.getPath());
-
- JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, this.params, this.dataSource);
- return jasperPrint;
-
- } catch (JRException jre) {
- jre.printStackTrace();
- throw new JasperReportException("在进行数据填充时发生了错误中,请检查是否是数据库连接错误或者是用来填充的参数map有误!");
- }
-
- }
- }
-
java 代码
其中使用的JasperReportException为笔者定义的异常,用来统一处理报表异常。
5、报表产生
报表产生是程序中最终可见的一部分,在jasperReport的demo中,大部分中使用了jasperReport的net.sf.jasperreports.j2ee.servlets.*中的类来生成。其实这也算是开源的产品的一个问题,其实jasperReport提供的report的工具,只能算是demo级别的,不能算是产品级别的。相信很多的朋友在使用的时候就碰上无法生成的问题。笔者在此基础上封装了一下。
具体参见以下:
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
返回顶楼 |
|
|
- lumi
- 等级: 初级会员
- 文章: 98
- 积分: 30
- 来自: ...
|
楼主,我也一直在用jasperreport + iReports开发报表,如果不嫌弃,可以一起研究研究!
我看的文档有些比较陈旧,新的文档真的很难找到,据说要U$的!
一直想用其解决复杂交叉报表的展示,但是不知道怎么用,楼主如果有这方面的经验,可否共享一下!
我用的是“通过javaBean的集合提供数据源”的方式!在程序中调用存储过程,把存储过程返回的结果封装成javaBean,然后展示,请问这样有什么可以改进的地方?
|
返回顶楼 |
|
|
- spinach
- 等级:
- 性别:
- 文章: 161
- 积分: 114
|
文章才开了个头
怎么就10个良好了
难道他们不期待下文了?
|
返回顶楼 |
|
|
- jimmy.shine
- 等级:
- 性别:
- 文章: 100
- 积分: 190
- 来自: 北京
|
近一周由于项目做评审,没有时间及时更新,报表将在本周完成,届时一定完成承诺的jasper report的总结。并提供样例,供大家参加!
谢谢大家的关注!
|
返回顶楼 |
|
|
- lumi
- 等级: 初级会员
- 文章: 98
- 积分: 30
- 来自: ...
|
楼主,黄花菜都凉了!
|
返回顶楼 |
|
|
- jimmy.shine
- 等级:
- 性别:
- 文章: 100
- 积分: 190
- 来自: 北京
|
公共开发体系仍在调整中,故无法发布。基本框架已经出来,但是大部分是基于jasper report的源码的抽象。
需要进一步重构。
|
返回顶楼 |
|
|
- tangyuanjian2007
- 等级: 初级会员
- 文章: 12
- 积分: 30
- 来自: ...
|
楼主,解决了客户端调用打印预览的applet没有?
|
返回顶楼 |
|
|
- jimmy.shine
- 等级:
- 性别:
- 文章: 100
- 积分: 190
- 来自: 北京
|
回tangyuanjian2007
我没有使用applet来进行预览,因为我们是定制的用户,现在大多数浏览器中还没有装上java虚拟机。不好意思,请自己查看demo。
|
返回顶楼 |
|
|
- fins
- 等级: 资深会员
- 性别:
- 文章: 3196
- 积分: 2953
- 来自: 小胖儿的大城
|
加个 把代码框起来 看着会舒服些
楼主加一下吧 加完我投良好贴 呵呵
|
返回顶楼 |
|
|
- lhbdir
- 等级: 初级会员
- 性别:
- 文章: 9
- 积分: 32
|
请教一个问题,我在iReport做设计时,sql语句写存储过程该怎样写呀!我试过好多次,{call procedureName(arg)}和exec procedureName(arg),两种方式都不行.主要是数据库是oracle参数为是返回值(即游标类型),在iReport中游标类型应该怎么传值呀?
|
返回顶楼 |
|
|