使用JasperReport与iBATIS开发Web报表(二)

三、        处理iBati返回数据

  如果iBATIS没有采用JavaBean作为返回对象,则可以采用java.util.map作为数据的返回对象。采用java.util.Map对象,需要额外的一些步骤。下面的代码则说明了iBATIS的select语句返回的java.util.Map对象。Src/ iBATIS.xml:
 

 
  
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> <? xml version="1.0" encoding="UTF-8" ?> <! DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 1.0//EN" "http://iBATIS.apache.org/dtd/sql-map-2.dtd" > < sqlMap > < select id ="salesByListOfMapsSQL" resultClass ="java.util.HashMap" > SELECT E.EMPLOYEE_ID "ID", E.FIRST_NAME "FIRST", E.LAST_NAME "LAST", MS.TOTAL_SALES "TOTAL", MS.LATEST_SALE FROM EMPLOYEE E, MONTHLY_SALES MS WHERE E.EMPLOYEE_ID = MS.EMPLOYEE_ID AND MS.MONTH = #value# </ select > < resultMap id ="searchResultList" class ="MonthlySalesBean" > < result property ="employeeID" column ="ID" /> < result property ="first" column ="FIRST" /> < result property ="last" column ="LAST" /> < result property ="total" column ="TOTAL" /> < result property ="latestSale.amount" column ="LATEST_SALE" /> </ resultMap > < select id ="salesByJavaBeansSQL" resultMap ="searchResultList" > SELECT E.EMPLOYEE_ID "ID", E.FIRST_NAME "FIRST", E.LAST_NAME "LAST", MS.TOTAL_SALES "TOTAL", MS.LATEST_SALE FROM EMPLOYEE E, MONTHLY_SALES MS WHERE E.EMPLOYEE_ID = MS.EMPLOYEE_ID AND MS.MONTH = #value# </ select > </ sqlMap >

    上面的代码返回的对象即为map对象。请注意,map对象中的Key值直接来自于select语句,因此,像TO_CHAR(MS.TOTAL_SALES)这样的表达式在报表中不提倡使用。因此,比较人性化的为字段命名,是一件很值得的事情。因为map的key值是作为java.lang.Object类型来进行存储的,因此有必要对字段返回类型进行一下整理。

    真正的数据填充类应该是ServiceLocatorBean.java类,其代码如下所示:

 

 

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import javax.servlet.ServletContext;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
public class ServiceLocatorBean implements ServiceLocatorIF {
private static final long serialVersionUID = -7166271873610635886L;
//the Spring application context
    private ApplicationContext appContext;
DAO dao = null;
public ServiceLocatorBean() {
try {
// get the spring context
            ServletContext context = FacesUtils.getServletContext();
this.appContext = WebApplicationContextUtils.
getRequiredWebApplicationContext(context);
// create instance of the business object
            this.dao = (DAO) this.lookupService("dao");
Connection conn = this.dao.getSqlMapClient().getDataSource().getConnection();
conn.setAutoCommit(false);
/*
Creating a statement lets us issue commands against
the connection.
*/
Statement s = conn.createStatement();
// just in case old tables from prior run (after first run which
// will create the USER1 schema)
            try {
s.execute("drop table employee");
s.execute("drop table monthly_sales");
} catch (Exception ex) {
// not to be concerned (at least in this example
            }
/*
We create a table, add a few rows, and update one.
*/
s.execute("create table employee (employee_id int, 
first_name varchar(40), last_name varchar(40))");
s.execute("insert into employee values (1,'sterning', 'chen')");
s.execute("insert into employee values (2,'yuxuan', 'Wand')");
s.execute("insert into employee values (3,'Mickey', 'Li')");
s.execute("create table monthly_sales (employee_id int, total_sales numeric(16,
2), latest_sale numeric(8, 2), month int)");
s.execute("insert into monthly_sales values (1, 1600.50, 32.50, 1)");
s.execute("insert into monthly_sales values (2, 1544.20, 12.50, 1)");
s.execute("insert into monthly_sales values (3, 18814.80, 78.65, 1)");
s.execute("insert into monthly_sales values (1, 1450.50, 10.65, 2)");
s.execute("insert into monthly_sales values (2, 2004.25, 52.10, 2)");
s.execute("insert into monthly_sales values (3, 9819.00, 40.65, 2)");
s.close();
conn.commit();
} catch (SQLException sqle) {
// just means the tables already exist
            sqle.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public DAO getDao() {
return this.dao;
}
public Object lookupService(String serviceBeanName) {
return appContext.getBean(serviceBeanName);
}
}

 

 

    四、        将iBATIS数据填入JasperReport中
  
  就通常而言,采用Java Bean作为iBATIS的返回对象,相比起java.util.Map对象来说,更加的方便与可行。很多的开发人员采用iBATIS的这种方式来进行数据的映射,同时,此方法还可以无缝的将iBATIS与JapserReport集成起来。
  
  在JasperReport中,提供了一个JRDataSource的实现,从而开发人员可以通过此类来传递iBATIS的list对象给JasperReport模板。而JRBeanCollectionDataSource类使用JavaBean来构造,从而可以通过循环查找collection并获得相应的bean属性。如下的代码示例说明了如何在调用JasperReport引擎时实例化JRBeanCollectionDataSource对象。

 

import java.io.File;
import java.util.HashMap;
import java.util.List;
import net.sf.jasperreports.engine.JRRuntimeException;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.util.JRLoader;
public class
SearchBean {
private final static String JAVA_BEAN_REPORT = "monthly_sales_java_beans.jasper"
;
private final static String LIST_OF_MAP_REPORT = "monthly_sales_list_of_maps.jasper"
;
public
String generateFromJavaBeans () {
try
{
ServiceLocatorIF sl
=
(ServiceLocatorIF) FacesUtils
.getManagedBean(
"serviceLocatorBean"
);
List list
= sl.getDao().getSqlMapClient().queryForList("salesByJavaBeansSQL"
, month);
FacesUtils.setSessionAttribute(
"JASPER_PRINT"
, generateReport (list, JAVA_BEAN_REPORT));
viewReport
= "true"
;
}
catch
(Exception ex) {
ex.printStackTrace();
}
return null
;
}
public
String generateFromListOfMaps () {
try
{
ServiceLocatorIF sl
=
(ServiceLocatorIF) FacesUtils
.getManagedBean(
"serviceLocatorBean"
);
List list
= sl.getDao().getSqlMapClient().queryForList("salesByListOfMapsSQL"
, month);
FacesUtils.setSessionAttribute(
"JASPER_PRINT"
, generateReport (list, LIST_OF_MAP_REPORT));
viewReport
= "true"
;
}
catch
(Exception ex) {
ex.printStackTrace();
}
return null
;
}
private
JasperPrint generateReport (List dataList, String reportName) {
JasperPrint jasperPrint
= null
;
try
{
String localPath
= FacesUtils.getServletContext().getRealPath("/"
);
File reportFile
= new File(localPath + "WEB-INF" + File.separator +
reportName);
if (!
reportFile.exists())
throw new JRRuntimeException(".jasper file not found. The report design must be compiled first."
);
JasperReport jasperReport
=
(JasperReport)JRLoader.loadObject(reportFile.getPath());
if
(reportName.equals(JAVA_BEAN_REPORT)) {
jasperPrint
=
JasperFillManager.fillReport(
jasperReport,
new
HashMap(),
new
JRBeanCollectionDataSource (dataList));
}
else
{
jasperPrint
=
JasperFillManager.fillReport(
jasperReport,
new
HashMap(),
new
CustomJRDS (dataList));
}
}
catch
(Exception ex) {
ex.printStackTrace();
}
return
jasperPrint;
}
public
String getMonth() {
return
month;
}
public void
setMonth(String month) {
this.month =
month;
}
public
String getViewReport() {
return
viewReport;
}
public void
setViewReport(String viewReport) {
this.viewReport =
viewReport;
}
private String month = null
;
private String viewReport = null
;
}
 

 

    在上面的代码中,定义的参数map,是在运行时传递相关的参数值给JasperReport。例如,可以在报表模板中定义一个名为REPORT_TITLE的参数,然后在运行时传递这一参数的值给它,传递的方式一般是健/值对的形式。例如Key=REPORT_TITLE,Value=Sale Report。当然,参数是传递给fillReport方法。然后,JasperReport会加载已经编译好的Jasper模板文件(.jasper)。最后调用静态的fillReport方法。

    而JasperPrint对象是在数据展示或显示时需要用到的。而在本例中,采用了JRPdfExporter来作为输出的格式,即输出为PDF格式文件,请参考PdfServlet.java文件,代码如下所示:

 

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.export.JRPdfExporter;
public class
PdfServlet extends HttpServlet {
public void
service(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
JasperPrint jasperPrint
=
(JasperPrint) request.getSession()
.getAttribute(
"JASPER_PRINT"
);
List jasperPrintList
= new
ArrayList();
jasperPrintList.add(jasperPrint);
JRPdfExporter exporter
= new
JRPdfExporter();
exporter.setParameter(JRExporterParameter.JASPER_PRINT_LIST,
jasperPrintList);
ByteArrayOutputStream baos
= new
ByteArrayOutputStream();
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);
try
{
exporter.exportReport();
}
catch
(JRException e) {
throw new
ServletException(e);
}
byte[] bytes =
baos.toByteArray();
if (bytes != null && bytes.length > 0
) {
response.setContentType(
"application/pdf"
);
response.setContentLength(bytes.length);
ServletOutputStream ouputStream
=
response.getOutputStream();
try
{
ouputStream.write(bytes,
0
, bytes.length);
ouputStream.flush();
}
finally
{
if (ouputStream != null
) {
try
{
ouputStream.close();
}
catch
(IOException ex) {
}
}
}
}
}
    
    尽管上面的JasperReport机制可以将iBATIS连接起来,但应该根据项目报表的需要对JavaBean进行修改与调整。而JasperReport字段对象可以很好的与普通的JDBC字段进行匹配。例如,JasperReport将Oracle的numeric字段类型对应的转成java.math.BigDecimal对象类型。而在iBATIS的Bean属性应该与JasperReport中定义的字段类型进行很好的匹配。需要对字段的类型进行认真仔细的选择,因为不同类型或是不同表达式对数据的展示有不同的效果。例如,BigDecimal类型比String类型更加适合货币格式。

五、        代码运行效果

    1.系统主界面

 

   

图3.报表运行主界面
 

   
    2.采用JavaBean生成报表


图4.采用JavaBean生成报表

    六、        小结

    在本文中,笔者展示了如何使用比较成熟的iBATIS数据框架来对JasperReport进行数据填充。iBATIS最大的特点是简单,而iBATIS所拥有的易维护及易配置特性,在JasperReport中充分的体现出来了。这种简单与灵活性,正好弥补了JasperReport在这方面的不足,从而达到灵活开发Web报表的目的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值