web开发最麻烦的是做报表,特别是交叉报表。要将查询得到的看起来平淡无奇的数据展开成复杂的报表不知要费煞多少周张。下次维护时看到冗长的SQL语句或长达数页的程序代码,都有种快要晕厥的感觉。
最近,这种好事又让我碰上。公司因为费用统计的需要,要开发一份各分公司之间调货量的统计表,如下图所示。表中坚向为分公司帐套名称(调出方),横向为帐套中的客户名称(调入方),这是一份典型的交叉报表。
制作这份报表有两个难点:
一、每一个分公司帐套对应数据库服务器上一个数据库,并分别存放在两台以上的数据库服务器中,因此报表数据必须跨服务器查询得到。
二、将查询得到的数据展开。
如果直接用SQL语句来完成这查询和数据展开显得太复杂,而且效率会很低。如果只通过SQL语句来查询数据则会简单很多,撇开安全问题不考虑,完全可以用SQL Server提供的Open系列函数来完成。展开数据如果通过代码来完成,实在是一件很痛苦的事情,每当这时候我就会想起C/S开发中的报表控件,遗憾的是公司并没有购买任何的WEB报表控件,只好自己来打制一个了。{========================================================================
DESIGN BY : 彭国辉
DATE: 2007-09-10
SITE: http://kacarton.yeah.net/
BLOG: http://blog.csdn.net/nhconch
EMAIL: kacarton[A T]sohu.com 文章为作者原创,转载请注明文章出处、保留作者信息,谢谢支持!
=========================================================================}
说话间,我就拿出了我的看家宝贝:Delphi+Fast Report2.5(很久没用了一直没更新),东西虽旧但好用。首先,创建一个ActiveX Library和Active Server Object。
然后在TLB是添加ShowCrossReport方法,参数如下,其中:ConStr为数据库的连接字符串,Command为SQL查询语句,ReportFile是FastReport报表模板,通过它生成最终报表。
接着编写ShowCrossReport的代码。
{========================================================================
DESIGN BY : 彭国辉
DATE: 2007-09-10
SITE: http://kacarton.yeah.net/
BLOG: http://blog.csdn.net/nhconch
EMAIL: kacarton[A T]sohu.com
文章为作者原创,转载请注明文章出处、保留作者信息,谢谢支持!
=========================================================================}
function TkktWebCrossReport.ShowCrossReport(const ConStr, Command,
ReportFile: WideString): Integer;
var
ADOQ: TADOQuery;
//frdb: TfrDBDataSet;
rpt: TfrReport;
st: TMemoryStream;
ex: TfrHTML2Export;
buf: String;
e: TComponent;
begin
e := TComponent.Create(nil);
try
ADOQ := TADOQuery.Create(e);
try try
//生成查询控件并查询数据
ADOQ.Name := 'ADOQ';
ADOQ.ConnectionString := ConStr;
ADOQ.SQL.Add(Command);
ADOQ.Open;
{frdb := TfrDBDataSet.Create(nil); //Fast Report 2.5的交叉报表控件可以直接读取ADODataSet数据
frdb.Name := 'frdb';
frdb.DataSet := ADOQ;}
st := TMemoryStream.Create; //报表生成后会导出到内在流中
//载入报表模板{========================================================================
DESIGN BY : 彭国辉
DATE: 2007-09-10
SITE: http://kacarton.yeah.net/
BLOG: http://blog.csdn.net/nhconch
EMAIL: kacarton[A T]sohu.com 文章为作者原创,转载请注明文章出处、保留作者信息,谢谢支持!
=========================================================================}
rpt := TfrReport.Create(e);
rpt.Name := 'frReport1';
//rpt.Dataset := frdb;
rpt.LoadFromFile(ReportFile);
rpt.ShowProgress := false;
rpt.PrepareReport;
st.Position := 0;
//创建导出控件,FastReport有TfrHTMExport和TfrHTML2Export两个导出到HTML格式的控件,TfrHTMExport以表格方式导出,默认没有表格线,且存在数据错位的问题,TfrHTML2Export以CSS格式导出,能完好的显示表格线,我采用后者。
ex := TfrHTML2Export.Create(e);
ex.Navigator.Align := haLeft;
ex.ShowDialog := false;
//这是重点,将结果导出到内存流并送到客户端
//导出到内存流的好处是不用在服务器生成中间文件,不用考虑权限和安全问题
//FastReport没有ExportToStream函数,是我加的,见后面说明
rpt.ExportToStream(ex, st);
st.Position := 0;
SetLength(buf, st.Size);
st.Read(buf[1], st.Size);
Response.Write(buf);
st.Clear;
except on E: Exception do
Response.Write('<font color=red><b><h2>'+E.Message+'</h2></b></font>');
end;
finally
if ex <> nil then FreeAndNil(ex);
if st <> nil then FreeAndNil(st);
if rpt <> nil then FreeAndNil(rpt);
//if frdb <> nil then frdb.Free;
FreeAndNil(ADOQ);
end;
finally
e.Free;
end;
end;
最后,翻译项目得到Dll文件,拷贝到服务器上并注册。服务器组件就完成了。
接着,来段演示代码。
先创建一个报表模板,并保存到服务器上,命名为rpt1.frf
。{========================================================================
DESIGN BY : 彭国辉
DATE: 2007-09-10
SITE: http://kacarton.yeah.net/
BLOG: http://blog.csdn.net/nhconch
EMAIL: kacarton[A T]sohu.com 文章为作者原创,转载请注明文章出处、保留作者信息,谢谢支持!
=========================================================================}
然后是调用代码(ASP.NET):
'通过ParseSQL生成SQL查询语句
Private Sub ShowReport()
Dim Cmd As String = ParseSQL()
If Cmd <> "" Then
Dim CrossReport = Server.CreateObject("CrossReport.kktWebCrossReport")
CrossReport.ShowCrossReport(clsSQL.DefaultConStr, Cmd, Page.MapPath(".") + "/rpt1.frf")
CrossReport = Nothing
End If
End Sub
下一篇:用服务器组件解决WEB交叉报表问题(2)——修改FastReport源码,支持内存流导出。