在公司的项目中用JapserReport也做了不少报表了,现在也做个记录吧,很多东西都从网上而来,总结一下而已。
注意:本文由 bangke 所撰写 版权归属于bangke 转载请注明出处
1.下载不说了,需要JapserReport和iReport,要pdf支持中文的话需要itextasian.jar(google!)
2.资源:The JasperReports Ultimate Guide.pdf(google!)
http://jasperreports.sourceforge.net/
http://plateau.sicool.com (good!)
源代码包下面的examples
3.先集中说一下中文支持问题:
1)iReport中文显示:去掉iReport lib目录下的tinylaf.jar,会丑点儿:)
2)要在pdf中显示中文:如下图设置字体或定义字体
注意:在iReport中新建一个TextField会自动把pdf字体设为CP1252,需要修改,否则pdf输出会报错说找不到字体
4.明确需求:
JasperReport(0.5.2)目前支持Tabular形式的报表,分组,子报表
不支持cross report(交叉表)和单元格合并。
5.JasperReport简述:
JasperReport总的来说采用报表样式和数据相分离的设计,在报表杨始中定义好和数据源的映射关系,然后在实际应用的时候再用数据源填充样式得到最终的报表输出。
1)数据源:
在JasperReport中可以定义多种数据源,都实现了dori.jasper.engine.JRDataSource接口。
接口有两个方法:
public boolean next() throws JRException;
public Object getFieldValue(JRField jrField) throws JRException;
各个数据源简介:
dori.jasper.engine.JRResultSetDataSource封装了一个java.sql.ResultSet
dori.jasper.engine.JREmptyDataSource在没有实际数据源的数据的时候可以使用它
dori.jasper.engine.data.JRTableModelDataSource封装了javax.swing.table.TableModel
dori.jasper.engine.data.JRBeanArrayDataSource封装了an array of JavaBeans and uses reflection to retrieve report field values.
dori.jasper.engine.data.JRBeanCollectionDataSource封装了java.util.Collection of JavaBeans,和上面的JRBeanArrayDataSource用法相像(强烈推荐,我一直都用它)
简而言之就是JRDataSource中封装了一个循环的集合,在报表中一后会通过(属性名)反射来取得每个数据项的内容
为什么选择JRBeanCollectionDataSource后面会解释。
构造数据源,采用数据工厂(针对JRBeanCollectionDataSource来说),工厂方法:
public static JRDataSource getJRDataSource(String name,HttpServletRequest request) throws Exception{
InterCustomerDS ds = null;//InterCustomerDS是一个interface!
try {
ds = (InterCustomerDS) Class.forName(name).
newInstance();
ds.createDS(request);//这里需要request中的一些parameter来生成数据源
return new JRBeanCollectionDataSource(ds.getBeanCollection());
}
catch (ClassNotFoundException ex) {
throw new Exception(ex.getMessage());
}
catch (IllegalAccessException ex) {
throw new Exception(ex.getMessage());
}
catch (InstantiationException ex) {
throw new Exception(ex.getMessage());
}
}
一个简单的数据源需要两个类,一个POJO,一个InterCustomerDS的实现
POJO:
public class TestVO {
private String portfolio;
private String year;
private String period;
public CCSPVO() {
}
public String getPeriod() {
return period;
}
public String getPortfolio() {
return portfolio;
}
public String getYear() {
return year;
}
public void setPeriod(String period) {
this.period = period;
}
public void setPortfolio(String portfolio) {
this.portfolio = portfolio;
}
public void setYear(String year) {
this.year = year;
}
}
TestDateSource:
public class TestDataSource implements InterCustomerDS {
private Collection co;
public CCSPDataSource() {
}
public void createDS(HttpServletRequest request) throws Exception{
co=new ArrayList();
/**//*
这之中做数据库查询,然后使用查询出来的结果生成TestVO,再把TestVO放入co中
*/
}
public Object[] getBeanArray() {
return co.toArray();
}
public Collection getBeanCollection() {
return co;
}
}
2)报表样式:
JasperReport将一张报表分为了几个Sections,又叫bands(按照一张报表的内容来划分的):title, pageHeader, columnHeader, detail, columnFooter, pageFooter, summary, (如果有group的话,还有groupHeader和groupFooter)。用iReport画报表的工作简单得说就是把特定的内容放在特定的section中。
title和summary在整个报表中只显示一次(不过有个选项可以设置为每页显示一次)
column和page是每页显示一次
detail才是最关键的地方,循环显示数据源的内容,直到全部显示完为止。
在样式中的3个变量:fields,variables,parameters
fields:从数据源传入样式的属性名(日后通过反射取值使用,所以fields名一定要和数据源中的属性名一样!比如使用JRBeanCollectionDataSource的话,fields名就要和javabean中对应的属性名一样!)
parameters:应用程序向报表传入得非数据源形式的数据。
variables:对fields,parameters,也包括所有java对象进行合法运算后得到的变量。(通常用做对数据源某个属性的统计,比如求和什么等等)
具体使用iReport设计报表样式不说了,网上很多资料.
需要注意的是
在报表样式中可以输入表达式,也就是合法的java scriptlet
在JasperReport中存在的都是java object所以某个textfield和对应数据的object类型一定要相同。
parameters除了iReport默认的那些类型外其实可以使用任何java类型的。
每个band在print when expression中输入返回Boolean的表达式可以控制是否显示
可以使用group来添加bands,group其实并不需要和某个field对应,也就是说group没有expression是可以的,只不过又expression的话会按照expression(通常的fields)来动态分组(这里又需要注意,效果上和sql的group by相当,但并不需要在查询数据源的sql中写group by, JasperReport回自己帮你做好的)
在输出数据的时候可以套用pattern,也就是正则表达式,比如输出Double的时候使用 #,##0.00 表示金额:1,234.00, #0.00表示1234.00
3)输出报表
采用一个Helper类,分别使用不同的方法得到填充了数据源的JasperPrint比如:
public JasperPrint getPrinterbyBeanCollection(File reportFile,Map reportParameters,JRBeanCollectionDataSource bean) throws Exception{
try {
if(!reportFile.exists()){
throw new Exception("the jasper file is not exist");
}
JasperReport jasperReport = (JasperReport) JRLoader.loadObject(reportFile.
getPath());
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport,
reportParameters, bean);
return jasperPrint;
}
catch (JRException ex) {
logger.error("report",ex);
throw new Exception(ex.getMessage());
}
}
然后使用JasperPrint得到报表输出,比如html输出:
public void htmlExport(JasperPrint print,Map imagesMap,Object out) throws Exception{
try{
JRHtmlExporter exporter = new JRHtmlExporter();
exporter.setParameter(JRExporterParameter.JASPER_PRINT, print);
exporter.setParameter(JRExporterParameter.OUTPUT_WRITER, out);
exporter.setParameter(JRHtmlExporterParameter.BETWEEN_PAGES_HTML, "");
exporter.setParameter(JRHtmlExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS, Boolean.TRUE);
exporter.setParameter(JRHtmlExporterParameter.IMAGES_MAP, imagesMap);
exporter.setParameter(JRHtmlExporterParameter.IMAGES_URI, "image?image=");
exporter.exportReport();
}catch(Exception ex){
logger.error("report",ex);
throw new Exception(ex.getMessage());
}
}
6.普通报表开发:
开发3步骤
1.定义POJO,写DataSource查询数据库生成一个Collection of POJOs
2.使用iReport设计报表,定义和POJO属性一样的fields等
3.用户输入web页面及输出的Servlet开发
7.SubReport
其实和普通报表开发一样,只不过多写几个报表样式,POJO和DateSource。
关键是在masterreport中对子报表的subreport选项卡中的Connection/DataSource Expression要选DataSource,然后填入你子报表的DataSource,当然先要把子报表的DataSource作为parameter传入masterreport。(这里JasperReport的example全是Connection的example,害的我想了半天,呵呵,实际上在J2EE这个要求解藕程度很高的范围内将sql写在报表样式中是不适合使用的)
8.最后说说为什么使用JRBeanCollectionDataSource,原因上面其实很多地方都说明了
1。使用POJO和Collection简单,规范
2。充分的解除报表样式和数据库之间的耦合,假如我要查询的sql变了,我只需要修改sql和结果集存入POJO的对应处,报表样式是不用修改的。
9.喝咖啡,休息,(其实我更喜欢喝雪碧,呵呵)!
本文由 bangke 所撰写 版权归属于bangke 转载请注明出处
posted on 2005-04-01 17:14
蚌壳 阅读(6814)
评论(11) 编辑 收藏 所属分类:
Java In Work