共三篇,下接:http://jimmy-shine.iteye.com/blog/123595
为了开发报表,已经拜读了一大堆的资料,其中大部分是重复的。可以看得出,国人还是比较热衷于copy&paste的工作。所以找了一大堆的资料都是相同的,或者可以用一个词来形容,换汤不换药的。
有必要对于jasper Report的学习进度进行一下总结,一来可以更新一下以前的资料中的一些旧得不能再旧的不再适用的东西,二来让后来者可以轻松的上手。
首先,jasperReport是一个以java实现的报表工具,(好像是句废话)。可以实现多种格式的报表。
再我们先理解一下jasperReport的实现过程。笔者不再画图,网上到处都是。
1)定制报表格式。
2)填充数据。
3)显示或打印。
看起来是不是很简单,对,确实很简单。
笔者主要从事基于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
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方式来获得。可以参照笔者写的如下:
-
- 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!"); -
} -
} -
- }
-
-
- 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; -
- }
-
对于其它的数据源,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); -
} -
} -
-
// 内部类,作为demo时使用 -
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()); -
} - }
-
以上的例子应当很清楚的写明了如何生成数据源。
对于数据源的填充,笔者使用了二个类,分别用来对应使用Connction及JavaBean Collection进行填充。
-
- 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 JasperPrintWithConnectio n { -
-
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 JasperPrintWithConnectio n() { -
super(); -
} -
-
public JasperPrintWithConnectio n(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 { -
// Load编译好的模板 -
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 JasperPrintWithDataSourc e { -
-
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 JasperPrintWithDataSourc e() { -
super(); -
} -
-
public JasperPrintWithDataSourc e(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 { -
// Load编译好的模板 -
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有误!"); -
} -
-
} - }
-
其中使用的JasperReportException为笔者定义的异常,用来统一处理报表异常。
5、报表产生
报表产生是程序中最终可见的一部分,在jasperReport的demo中,大部分中使用了jasperReport的net.sf.jasperreports.j2ee.servlets.*中的类来生成。其实这也算是开源的产品的一个问题,其实jasperReport提供的report的工具,只能算是demo级别的,不能算是产品级别的。相信很多的朋友在使用的时候就碰上无法生成的问题。笔者在此基础上封装了一下。
具体参见以下: