| 導購 | 订阅 | 在线投稿
分享
 
 
 

用FASTREPORT实现WEB应用中自定义报表

2006-12-17 07:43:48  編輯來源:互聯網  简体版  手機版  評論  字體: ||
 
 
  用FASTREPORT实现WEB应用中自定义报表

  

  用FASTREPORT实现WEB应用中自定义报表 开发WEB应用系统通常都会遇到报表打印问题。简单应用可利用IE的页面打印功能,利用HTML标签控制格式来实现。但复杂的业务型应用系统,报表不仅是组成应用的重要部分,还常常是相当复杂的。现在很多应用系统都要求提供自定义报表的功能——即客户可以自行设计、修改报表。

  在C/S结构系统中,报表问题有很多成熟的解决方法。如DELPHI开发工具不仅自带有报表控件,还可以利用第三方控件来实现快速灵活的报表制作和打印,其中有名的控件是FR-Software & A.Tzyganenko 的FastReport。FastReport提供了能与DELPHI无缝集成的从设计到打印的完整控件包,提供的设计界面友好灵活,对于开发可让用户自定义报表的C/S应用来说,是一种很好的解决方式。

  在B/S结构应用中,Crystal Report是一种大型报表系统常用和推荐的解决方案。但Crystal Report目前价格昂贵,而且该系统相当庞大。它的可定制性及精确控制打印效果方面尚不够完善。当然,在目前市场上,它仍是一种首选的WEB应用的报表解决方案。

  如果能将C/S应用中成熟的报表解决方案搬到B/S应用中,相信对于大部分开发人员来说,都是非常欢迎的。本文将讲述一个在JAVA环境中利用FastReport实现B/S应用中用户可自定义的报表解决方案。因为笔者近段时间正用DELPHI、JAVA做一些项目,所以样例代码就以DELPHI、JAVA编写。

  本解决方案样例的基本环境是:WINDOWS 2000 SERVER+SQL SERVER 2000+TOMCAT 4.0。开发工具:IntelliJ IDEA 3.0,DELPHI 5.0。客户端为IE 5.0浏览器。

  方案共要求用DELPHI编写两个程序,一个是将被包含在网页中并在浏览器中运行的ACTIVEX(.ocx),一个是运行在服务器端的报表处理程序,中间通过JAVA程序连接——或任何其他WEB语言都可以,如ASP、PHP等。方案的基本原理图如下:

  报表设计过程

  

  报表打印过程

  

  REPORT SERVER:可以做成一个普通的WINDOWS程序,也可以做成一个COM程序(Automation Object)。在报表设计过程中,用户端(ACTIVEX)向WEB SERVER发送报表设计请求,请求中包含要设计报表的名称;WEB SERVER 收到该请求后,调用REPORT SERVER请求设计的报表文件;REPORT SERVER收到请求后,先装载报表的数据环境,然后将报表设计文件(.frf)和该报表的数据环境文件压缩成一个包文件(.zip),将该包文件的完整路径名返回给WEB SERVER调用程序;WEB SERVER将包文件回送给用户端(ACTIVEX),用户端将接收到的包文件保存到本地硬盘上,并解压缩,从数据环境文件中恢复数据环境,通过FASTREPORT的相应控件打开报表文件给用户提供可视化设计。用户在ACTIVEX中设计报表时,虽然不能和数据库连接,但因数据环境已存在,所以用户仿如在通常的C/S应用结构下设计报表,能正常地看到报表的数据字典信息。在报表打印过程中,用户端(ACTIVEX)向WEB SERVER发送报表打印/预览请求,请求中包含要打印/预览的报表名称;WEB SERVER 收到该请求后,调用REPORT SERVER请求打印或预览的报表文件;REPORT SERVER收到请求后,先装载报表的数据环境,然后装载报表文件(.frf),接着在无界面状态下运行报表,最后将生成的已准备的报表文件(.frp)压缩成一个包文件(.zip),将该包文件的完整路径名返回给WEB SERVER调用程序;WEB SERVER将包文件回送给用户端(ACTIVEX),用户端将接收到的包文件保存到本地硬盘上,并解压缩,通过FASTREPORT的相应控件打开报表文件(.frp)给用户预览或打印或重新调整格式或输出为其他格式文件。用户在ACTIVEX中预览报表,仿如在通常的C/S应用结构下预览报表。

  WEB SERVER:提供通常的WEB服务功能。

  ACTIVEX:ActiveX是Microsoft提出的一组使用COM(Component Object Model,部件对象模型)使得软件部件可在网络环境中进行交互的技术集。它与具体的编程语言无关。作为针对Internet应用开发的技术,ActiveX被广泛应用于WEB服务器以及客户端的各个方面。本方案中的ACTIVEX控件主要做两方面的事情,一是利用FASTREPORT控件进行报表处理,包括报表设计(.frf文件)和报表打印(.frp文件)。一是与WEB SERVER进行通信,请求和接收包文件。本文样例的ACTIVEX采用DELPHI 5.0编写。

  下面分述各部分的一例具体实现(因为仅为说明方案的实现,所以很多代码细节都进行了简省)。

  一、 REPORT SERVER

  REPORT SERVER既可以做成一个普通的WINDOWS程序,也可以做成一个COM程序(Automation Object)。本例中为简化见,采用普通的WINDOWS程序实现。

  在DELPHI中NEW一个应用程序。在FORM中加入TfrReport、TfrDBDataSet、ADOConnection、TADOQuery等控件——为了使用FASTREPORT的控件,需要安装该控件包,可从站点http://www.fast-report.com 下载,国内很多软件站点都提供该控件包的下载。其中TfrDBDataSet、TADOQuery控件视应用需要可加入多个,另外为了压缩文件,还要加入一个压缩控件,本例使用VCLZip。在Form1中加入三个函数:preDesignReport(rpFileName:String),prePrintReport(rpFileName:String),zipReportFiles(rpFileName:String),分别用于准备报表设计文件、准备报表打印文件、压缩报表文件 。Form1.Create方法为:

  procedure TForm1.FormCreate(Sender: TObject);

  var

   rpFileName,mode:String;

  begin

   if paramCount>1 then

   begin

   mode:=paramStr(1);

   rpFileName:=paramStr(2);

   if mode='d' then //设计报表

   if preDesignReport(rpFileName) then

   zipReportFiles(rpFileName);

   if mode='r' then //打印报表

   if prePrintReport(rpFileName) then

   zipReportFiles(rpFileName);

   end;

   Application.Terminate;

  end;

  程序根据调用参数判断是准备报表设计文件还是准备报表打印文件,接着调用相应的过程来实现。最后的Application.Terminate 是让程序执行功能后即退出——因为这是服务端程序,是不能与用户交互的。

  preDesignReport(rpFileName:String)方法:

  function TForm1.preDesignReport(rpFileName:String):boolean;

  var

  …… //其他变量

   dtfFileName:String;

  begin

   ……

  dtfFileName:=StringReplace(rpFileName, ExtractFileExt(rpFileName),'.dtf',

  [rfReplaceAll, rfIgnoreCase]);

   try

  rpAdoquery.SQL.Add('…');

   rpAdoquery.open;//打开报表的数据环境

   rpAdoquery.FieldList.SaveToFile(dtfFileName);

   result:=true;

   except

   on Exception do

   result:=false;

   end;

  end;

  函数preDesignReport的作用是准备报表设计文件。报表中可以引用多个DataSet,本例假设报表只引用一个名为rpAdoquery的DataSet。rpFileName 为报表文件名(.frf),DtfFileName为保存数据环境的文件名(.dtf)。因为用户端不能连接数据库,所以将DataSet中的Fileds通过rpAdoquery.FieldList.SaveToFile(dtfFileName)保存到文件,和报表文件一起传送给用户端的ACTIVEX,ACTIVEX利用.dtf文件复现报表的数据环境。

  prePrintReport(rpFileName:String)方法:

  function TForm1.prePrintReport(rpFileName:String):boolean;

  var

  ……

   repFileName:String;

  begin

   ……

   repFileName:=StringReplace(rpFileName, ExtractFileExt(rpFileName),'.frp',

  [rfReplaceAll, rfIgnoreCase]);

   try

  rpAdoquery.SQL.Add('…');

   rpAdoquery.open;//打开报表的数据环境

   frReport1.ShowProgress:=False;

   frReport1.Clear;

   frReport1.LoadFromFile(rpFileName);

   frDBDataSet1.DataSet :=rpAdoquery;

   frReport1.Dataset :=frDBDataSet1;

   frReport1.PrepareReport;

   frReport1.SavePreparedReport(repFileName);

   result:=true;

   except

   on Exception do

   result:=false;

   end;

  end;

  函数prePrintReport的作用是准备打印的报表文件,即先在服务器端装载报表并运行,将运行好的报表保存为文件,用于传送到用户端进行预览或打印。RepFileName是已准备好的报表文件名(.frp)。同样假设报表只引用一个名为rpAdoquery的DataSet。frReport1.ShowProgress:=False 使报表运行过程中不显示进度窗口(服务器端不能显示与用户交互的界面);接下来frReport1.Clear;…装载报表文件及设置相关数据属性;frReport1.PrepareReport 是在不显示预览窗口的情况下运行报表;frReport1.SavePreparedReport(repFileName) 将运行好的报表保存到文件,该文件传送给用户端的ACTIVEX,ACTIVEX可以直接预览或显示该报表。

  zipReportFiles(rpFileName:String)方法:

  function TForm1.zipReportFiles(rpFileName:String):boolean;

  var

  ……

   zipFileName,fileName:String;

   zipCount:Integer;

  begin

   ……

   zipFileName:=StringReplace(rpFileName, ExtractFileExt(rpFileName),'.zip',

  [rfReplaceAll, rfIgnoreCase]);

   fileName:= ExtractFileName(rpFileName);

   fileName:= ChangeFileExt(fileName,'.*');

   try

   VCLZip1.ZipName:= zipFileName;

   VCLZip1.RootDir:= '.\';

   VCLZip1.FilesList.Add(fileName);

   zipCount:= VCLZip1.Zip;

   if zipCount = 0 then

   result:=false

   else

   result:=true;

   except

   on Exception do

   result:=false;

   end;

  end;

  函数zipReportFiles的作用是把要传送给用户端的报表文件压缩为一个.zip文件,简化文件传送过程,而且压缩了数据量。ACTIVEX接收到.zip文件后,先解压出包中文件,再进行处理。

  

  二、 WEB SERVER

  方案中WEB SERVER的作用主要是根据ACTIVEX的请求调用REPORT SERVER,并将REPORT SERVER生成的.zip文件发送给ACTIVEX。样例通过一个report.jsp文件来处理:ACTIVEX通过get请求report.jsp文件,report.jsp文件调用REPORT SERVER处理后,将.zip文件发送给ACTIVEX。

  Report.jsp文件:

  <%@ page import='…'%>

  <%@page contentType=' APPLICATION/OCTET-STREAM' %>

  <%

   try

   {

   String reqFileName = request.getParameter('rpFileName');

  String reqMode = request.getParameter('mode');//d为设计报表,r为打印报表

  String rpFileName = xxxx.getRpFileName(reqFileName); //根据请求的报表名获得实际的报表文件名,如请求订单报表,而订单报表实际对应的报表文件为order.frf。

   String l_cmd='reportserver.exe '+reqMode+' '+ reqFileName;

   Process l_ps=java.lang.Runtime.getRuntime().exec(l_cmd,null);

   byte[] l_b=new byte[100];

   while(l_ps.getInputStream().read(l_b,0,100)!=-1){

   ;

   }

  

  //发送文件

  String zipFileName = xxxx.getZipFileName(reqFileName); //获得压缩文件名

  response.setHeader('Content-Disposition','attachment; filename=\'' +

  zipFileName + '\'');

   java.io.FileInputStream fileInputStream =

  new java.io.FileInputStream(zipFileName);

   int i;

   while ((i=fileInputStream.read()) != -1) {

   out.write(i);

   }

   fileInputStream.close();

   out.close();

   }

   catch(Exception e)

   {

   ……

   }

  %>

  String l_cmd='reportserver.exe '+reqMode+' '+ reqFileName; 组成调用REPORT SERVER的命令串。while(l_ps.getInputStream().read(l_b,0,100)!=-1){ ; } 等待REPORT SERVER执行完成,否则,程序在启动REPORT SERVER后即执行下一行语句。发送文件的方式有多种,比如也可以由ACTIVEX通过ftp方式取得。

  

  三、ACTIVEX

  方案中的ACTIVEX控件主要做两方面的事情,一是报表利用FASTREPORT控件进行报表处理,包括报表设计(.frf文件)和报表打印(.frp文件)。一是与WEB SERVER进行通信,请求和接收包文件。

  在DELPHI中NEW一个ActiveForm 应用,取名为reportAForm。在form中加入Combox、button、edit、label等与用户交互的控件;为了处理报表,加入FASTREPORT的多个frSpeedButton用于处理报表事件,如设计、预览、打印、翻页、保存等;加入frReport、frDBDataSet、frDesigner等用于在运行时设计报表;如果设计报表时要使用图形、复选框等内容,也要加入相应的控件;加入frPreview、frTextExport、frRTFExport等控件使可以预览报表并可以将报表输出为text、rtf等格式文件;加入ADOQuery(根据实际需要可加入多个)为报表设计提供数据环境,ADOQuery不OPEN,不与数据库连接;加入NMHTTP用于与WEB SERVER联系。加入四个函数:DesignReport(rpFileName:String),PrintReport(rpFileName:String),unzipReportFiles(rpFileName:String),getReportFile(rpFileName,mode:String)分别用于设计报表、打印报表、解压缩报表和向WEB SERVER发送请求以取得报表文件 。

  getReportFile(rpFileName,mode:String)方法:

  function TreportAForm.getReportFile(rpFileName,mode:String):boolean;

  var

  ……

   zipFileName:String;

  begin

   ……

  zipFileName:=StringReplace(rpFileName, ExtractFileExt(rpFileName),'.zip',

  [rfReplaceAll, rfIgnoreCase]);

  try

   NMHTTP1.inputFileMode := TRUE;

   NMHTTP1.body:='.\ '+ zipFileName;

  NMHTTP1.Get('http://www…./../report.jsp?rpFileName='+

  rpFileName+'&mode='+mode);

  Result:=true;

  except

   on Exception do

   Result:=false;

   end;

  end;

  函数getReportFile的作用是向WEB SERVER发送报表请求(通过NMHTTP的Get方法),并将返回的压缩包文件保存到本地硬盘(zipFileName)。

  unzipReportFiles(rpFileName:String)方法:

  function TreportAForm.unzipReportFiles(rpFileName:String) :boolean;

  var

  ……

   zipFileName,fileName:String;

   zipCount:Integer;

  begin

   ……

   zipFileName:=StringReplace(rpFileName, ExtractFileExt(rpFileName),'.zip',

  [rfReplaceAll, rfIgnoreCase]);

   fileName:= ExtractFileName(rpFileName);

   fileName:= ChangeFileExt(fileName,'.*');

   try

   VCLUnZip1.ZipName:= '.\'+ zipFileName;

   VCLUnZip1.DestDir:= '.\';

   VCLUnZip1.OverwriteMode:= Always;

   VCLUnZip1.ReadZip;

   VCLUnZip1.FilesList.Add(fileName);

   zipCount:= VCLUnZip1.UnZip;

   if zipCount = 0 then

   result:=false

   else

   result:=true;

   except

   on Exception do

   result:=false;

   end;

  end;

  函数unzipReportFiles的作用是将压缩包中的文件解压出来,供ACTIVEX使用。它与REPORT SERVER程序中的zipReportFiles刚好是个相反的过程。

  DesignReport(rpFileName:String)方法:

  function TreportAForm. DesignReport (rpFileName:String) :boolean;

  var

   dtfFileName,rpFileName:String;

   fldlist:TStringList;

   T: TStringField;

   i:Integer;

  begin

   ……

   dtfFileName:=StringReplace(rpFileName, ExtractFileExt(rpFileName),'.dtf',

  [rfReplaceAll, rfIgnoreCase]);//获得数据环境文件名

   fldlist:=TStringList.Create;

   fldlist.LoadFromFile(dtfFileName);

   rpAdoquery.Fields.Clear;

   for i := 0 to fldlist.Count - 1 do

   begin

   T := TStringField.Create(nil);

   T.FieldName := fldlist[i];

   T.Name := rpAdoquery.Name + T.FieldName;

   rpAdoquery.Fields.add(T);

   end;

   FrReport1.LoadFromFile(rpFileName);

   FrReport1.DesignReport;

  end;

  函数DesignReport先从.dtf(由REPORT SERVER生成)文件中恢复报表的数据环境,接着使用FASTREPORT的FrReport控件设计报表。在FASTREPORT中,对DataSet中的Field只关心名称(全部通过Variant类型处理),而并不关心数据类型,所以恢复报表的数据环境时,所有字段都当作String类型加入。样例假设报表只有一个名为rpAdoquery的DataSet。报表设计运行时窗口在ACTIVEX进程空间运行。

  用户端设计好报表并保存后,需要将保存的报表文件(.frf)回送给服务器存储。文件上传对于大部分开发人员来说应该都是熟悉而简单的,该部分程序本文就省略了。

  PrintReport(rpFileName:String)方法:

  function TreportAForm. PrintReport (rpFileName:String) :boolean;

  var

   repFileName:String;

  begin

   ……

   repFileName:=StringReplace(rpFileName, ExtractFileExt(rpFileName),'.frp',

   [rfReplaceAll, rfIgnoreCase]);//获得已准备的报表文件名

   try

   frPreview1.clear;

   FrReport1.Preview:=nil;

   FrReport1.clear;

   FrReport1.LoadPreparedReport(repFileName);

   FrReport1.Preview :=frPreview1;

   FrReport1.ShowPreparedReport;

   result:=true;

   except

   on Exception do

   result:=false;

   end;

  end;

  函数PrintReport装入由REPORT SERVER运行好的报表.frp文件,通过调用FrReport的ShowPreparedReport方法在ACTIVEX端预览和打印。

  方案实现方法的介绍结束。本方案具有的优点为:保持应用的结构形式不变(B/S),将C/S应用结构下已非常成熟的报表方案移植过来,使得在WEB应用中也可实现任意复杂的报表设计和打印,以及对打印效果进行精确控制。
 
 
 
用FASTREPORT实现WEB应用中自定义报表 用FASTREPORT实现WEB应用中自定义报表 开发WEB应用系统通常都会遇到报表打印问题。简单应用可利用IE的页面打印功能,利用HTML标签控制格式来实现。但复杂的业务型应用系统,报表不仅是组成应用的重要部分,还常常是相当复杂的。现在很多应用系统都要求提供自定义报表的功能——即客户可以自行设计、修改报表。 在C/S结构系统中,报表问题有很多成熟的解决方法。如DELPHI开发工具不仅自带有报表控件,还可以利用第三方控件来实现快速灵活的报表制作和打印,其中有名的控件是FR-Software & A.Tzyganenko 的FastReport。FastReport提供了能与DELPHI无缝集成的从设计到打印的完整控件包,提供的设计界面友好灵活,对于开发可让用户自定义报表的C/S应用来说,是一种很好的解决方式。 在B/S结构应用中,Crystal Report是一种大型报表系统常用和推荐的解决方案。但Crystal Report目前价格昂贵,而且该系统相当庞大。它的可定制性及精确控制打印效果方面尚不够完善。当然,在目前市场上,它仍是一种首选的WEB应用的报表解决方案。 如果能将C/S应用中成熟的报表解决方案搬到B/S应用中,相信对于大部分开发人员来说,都是非常欢迎的。本文将讲述一个在JAVA环境中利用FastReport实现B/S应用中用户可自定义的报表解决方案。因为笔者近段时间正用DELPHI、JAVA做一些项目,所以样例代码就以DELPHI、JAVA编写。 本解决方案样例的基本环境是:WINDOWS 2000 SERVER+SQL SERVER 2000+TOMCAT 4.0。开发工具:IntelliJ IDEA 3.0,DELPHI 5.0。客户端为IE 5.0浏览器。 方案共要求用DELPHI编写两个程序,一个是将被包含在网页中并在浏览器中运行的ACTIVEX(.ocx),一个是运行在服务器端的报表处理程序,中间通过JAVA程序连接——或任何其他WEB语言都可以,如ASP、PHP等。方案的基本原理图如下: 报表设计过程 报表打印过程 REPORT SERVER:可以做成一个普通的WINDOWS程序,也可以做成一个COM程序(Automation Object)。在报表设计过程中,用户端(ACTIVEX)向WEB SERVER发送报表设计请求,请求中包含要设计报表的名称;WEB SERVER 收到该请求后,调用REPORT SERVER请求设计的报表文件;REPORT SERVER收到请求后,先装载报表的数据环境,然后将报表设计文件(.frf)和该报表的数据环境文件压缩成一个包文件(.zip),将该包文件的完整路径名返回给WEB SERVER调用程序;WEB SERVER将包文件回送给用户端(ACTIVEX),用户端将接收到的包文件保存到本地硬盘上,并解压缩,从数据环境文件中恢复数据环境,通过FASTREPORT的相应控件打开报表文件给用户提供可视化设计。用户在ACTIVEX中设计报表时,虽然不能和数据库连接,但因数据环境已存在,所以用户仿如在通常的C/S应用结构下设计报表,能正常地看到报表的数据字典信息。在报表打印过程中,用户端(ACTIVEX)向WEB SERVER发送报表打印/预览请求,请求中包含要打印/预览的报表名称;WEB SERVER 收到该请求后,调用REPORT SERVER请求打印或预览的报表文件;REPORT SERVER收到请求后,先装载报表的数据环境,然后装载报表文件(.frf),接着在无界面状态下运行报表,最后将生成的已准备的报表文件(.frp)压缩成一个包文件(.zip),将该包文件的完整路径名返回给WEB SERVER调用程序;WEB SERVER将包文件回送给用户端(ACTIVEX),用户端将接收到的包文件保存到本地硬盘上,并解压缩,通过FASTREPORT的相应控件打开报表文件(.frp)给用户预览或打印或重新调整格式或输出为其他格式文件。用户在ACTIVEX中预览报表,仿如在通常的C/S应用结构下预览报表。 WEB SERVER:提供通常的WEB服务功能。 ACTIVEX:ActiveX是Microsoft提出的一组使用COM(Component Object Model,部件对象模型)使得软件部件可在网络环境中进行交互的技术集。它与具体的编程语言无关。作为针对Internet应用开发的技术,ActiveX被广泛应用于WEB服务器以及客户端的各个方面。本方案中的ACTIVEX控件主要做两方面的事情,一是利用FASTREPORT控件进行报表处理,包括报表设计(.frf文件)和报表打印(.frp文件)。一是与WEB SERVER进行通信,请求和接收包文件。本文样例的ACTIVEX采用DELPHI 5.0编写。 下面分述各部分的一例具体实现(因为仅为说明方案的实现,所以很多代码细节都进行了简省)。 一、 REPORT SERVER REPORT SERVER既可以做成一个普通的WINDOWS程序,也可以做成一个COM程序(Automation Object)。本例中为简化见,采用普通的WINDOWS程序实现。 在DELPHI中NEW一个应用程序。在FORM中加入TfrReport、TfrDBDataSet、ADOConnection、TADOQuery等控件——为了使用FASTREPORT的控件,需要安装该控件包,可从站点http://www.fast-report.com 下载,国内很多软件站点都提供该控件包的下载。其中TfrDBDataSet、TADOQuery控件视应用需要可加入多个,另外为了压缩文件,还要加入一个压缩控件,本例使用VCLZip。在Form1中加入三个函数:preDesignReport(rpFileName:String),prePrintReport(rpFileName:String),zipReportFiles(rpFileName:String),分别用于准备报表设计文件、准备报表打印文件、压缩报表文件 。Form1.Create方法为: procedure TForm1.FormCreate(Sender: TObject); var rpFileName,mode:String; begin if paramCount>1 then begin mode:=paramStr(1); rpFileName:=paramStr(2); if mode='d' then //设计报表 if preDesignReport(rpFileName) then zipReportFiles(rpFileName); if mode='r' then //打印报表 if prePrintReport(rpFileName) then zipReportFiles(rpFileName); end; Application.Terminate; end; 程序根据调用参数判断是准备报表设计文件还是准备报表打印文件,接着调用相应的过程来实现。最后的Application.Terminate 是让程序执行功能后即退出——因为这是服务端程序,是不能与用户交互的。 preDesignReport(rpFileName:String)方法: function TForm1.preDesignReport(rpFileName:String):boolean; var …… //其他变量 dtfFileName:String; begin …… dtfFileName:=StringReplace(rpFileName, ExtractFileExt(rpFileName),'.dtf', [rfReplaceAll, rfIgnoreCase]); try rpAdoquery.SQL.Add('…'); rpAdoquery.open;//打开报表的数据环境 rpAdoquery.FieldList.SaveToFile(dtfFileName); result:=true; except on Exception do result:=false; end; end; 函数preDesignReport的作用是准备报表设计文件。报表中可以引用多个DataSet,本例假设报表只引用一个名为rpAdoquery的DataSet。rpFileName 为报表文件名(.frf),DtfFileName为保存数据环境的文件名(.dtf)。因为用户端不能连接数据库,所以将DataSet中的Fileds通过rpAdoquery.FieldList.SaveToFile(dtfFileName)保存到文件,和报表文件一起传送给用户端的ACTIVEX,ACTIVEX利用.dtf文件复现报表的数据环境。 prePrintReport(rpFileName:String)方法: function TForm1.prePrintReport(rpFileName:String):boolean; var …… repFileName:String; begin …… repFileName:=StringReplace(rpFileName, ExtractFileExt(rpFileName),'.frp', [rfReplaceAll, rfIgnoreCase]); try rpAdoquery.SQL.Add('…'); rpAdoquery.open;//打开报表的数据环境 frReport1.ShowProgress:=False; frReport1.Clear; frReport1.LoadFromFile(rpFileName); frDBDataSet1.DataSet :=rpAdoquery; frReport1.Dataset :=frDBDataSet1; frReport1.PrepareReport; frReport1.SavePreparedReport(repFileName); result:=true; except on Exception do result:=false; end; end; 函数prePrintReport的作用是准备打印的报表文件,即先在服务器端装载报表并运行,将运行好的报表保存为文件,用于传送到用户端进行预览或打印。RepFileName是已准备好的报表文件名(.frp)。同样假设报表只引用一个名为rpAdoquery的DataSet。frReport1.ShowProgress:=False 使报表运行过程中不显示进度窗口(服务器端不能显示与用户交互的界面);接下来frReport1.Clear;…装载报表文件及设置相关数据属性;frReport1.PrepareReport 是在不显示预览窗口的情况下运行报表;frReport1.SavePreparedReport(repFileName) 将运行好的报表保存到文件,该文件传送给用户端的ACTIVEX,ACTIVEX可以直接预览或显示该报表。 zipReportFiles(rpFileName:String)方法: function TForm1.zipReportFiles(rpFileName:String):boolean; var …… zipFileName,fileName:String; zipCount:Integer; begin …… zipFileName:=StringReplace(rpFileName, ExtractFileExt(rpFileName),'.zip', [rfReplaceAll, rfIgnoreCase]); fileName:= ExtractFileName(rpFileName); fileName:= ChangeFileExt(fileName,'.*'); try VCLZip1.ZipName:= zipFileName; VCLZip1.RootDir:= '.\'; VCLZip1.FilesList.Add(fileName); zipCount:= VCLZip1.Zip; if zipCount = 0 then result:=false else result:=true; except on Exception do result:=false; end; end; 函数zipReportFiles的作用是把要传送给用户端的报表文件压缩为一个.zip文件,简化文件传送过程,而且压缩了数据量。ACTIVEX接收到.zip文件后,先解压出包中文件,再进行处理。 二、 WEB SERVER 方案中WEB SERVER的作用主要是根据ACTIVEX的请求调用REPORT SERVER,并将REPORT SERVER生成的.zip文件发送给ACTIVEX。样例通过一个report.jsp文件来处理:ACTIVEX通过get请求report.jsp文件,report.jsp文件调用REPORT SERVER处理后,将.zip文件发送给ACTIVEX。 Report.jsp文件: <%@ page import='…'%> <%@page contentType=' APPLICATION/OCTET-STREAM' %> <% try { String reqFileName = request.getParameter('rpFileName'); String reqMode = request.getParameter('mode');//d为设计报表,r为打印报表 String rpFileName = xxxx.getRpFileName(reqFileName); //根据请求的报表名获得实际的报表文件名,如请求订单报表,而订单报表实际对应的报表文件为order.frf。 String l_cmd='reportserver.exe '+reqMode+' '+ reqFileName; Process l_ps=java.lang.Runtime.getRuntime().exec(l_cmd,null); byte[] l_b=new byte[100]; while(l_ps.getInputStream().read(l_b,0,100)!=-1){ ; } //发送文件 String zipFileName = xxxx.getZipFileName(reqFileName); //获得压缩文件名 response.setHeader('Content-Disposition','attachment; filename=\'' + zipFileName + '\''); java.io.FileInputStream fileInputStream = new java.io.FileInputStream(zipFileName); int i; while ((i=fileInputStream.read()) != -1) { out.write(i); } fileInputStream.close(); out.close(); } catch(Exception e) { …… } %> String l_cmd='reportserver.exe '+reqMode+' '+ reqFileName; 组成调用REPORT SERVER的命令串。while(l_ps.getInputStream().read(l_b,0,100)!=-1){ ; } 等待REPORT SERVER执行完成,否则,程序在启动REPORT SERVER后即执行下一行语句。发送文件的方式有多种,比如也可以由ACTIVEX通过ftp方式取得。 三、ACTIVEX 方案中的ACTIVEX控件主要做两方面的事情,一是报表利用FASTREPORT控件进行报表处理,包括报表设计(.frf文件)和报表打印(.frp文件)。一是与WEB SERVER进行通信,请求和接收包文件。 在DELPHI中NEW一个ActiveForm 应用,取名为reportAForm。在form中加入Combox、button、edit、label等与用户交互的控件;为了处理报表,加入FASTREPORT的多个frSpeedButton用于处理报表事件,如设计、预览、打印、翻页、保存等;加入frReport、frDBDataSet、frDesigner等用于在运行时设计报表;如果设计报表时要使用图形、复选框等内容,也要加入相应的控件;加入frPreview、frTextExport、frRTFExport等控件使可以预览报表并可以将报表输出为text、rtf等格式文件;加入ADOQuery(根据实际需要可加入多个)为报表设计提供数据环境,ADOQuery不OPEN,不与数据库连接;加入NMHTTP用于与WEB SERVER联系。加入四个函数:DesignReport(rpFileName:String),PrintReport(rpFileName:String),unzipReportFiles(rpFileName:String),getReportFile(rpFileName,mode:String)分别用于设计报表、打印报表、解压缩报表和向WEB SERVER发送请求以取得报表文件 。 getReportFile(rpFileName,mode:String)方法: function TreportAForm.getReportFile(rpFileName,mode:String):boolean; var …… zipFileName:String; begin …… zipFileName:=StringReplace(rpFileName, ExtractFileExt(rpFileName),'.zip', [rfReplaceAll, rfIgnoreCase]); try NMHTTP1.inputFileMode := TRUE; NMHTTP1.body:='.\ '+ zipFileName; NMHTTP1.Get('http://www…./../report.jsp?rpFileName='+ rpFileName+'&mode='+mode); Result:=true; except on Exception do Result:=false; end; end; 函数getReportFile的作用是向WEB SERVER发送报表请求(通过NMHTTP的Get方法),并将返回的压缩包文件保存到本地硬盘(zipFileName)。 unzipReportFiles(rpFileName:String)方法: function TreportAForm.unzipReportFiles(rpFileName:String) :boolean; var …… zipFileName,fileName:String; zipCount:Integer; begin …… zipFileName:=StringReplace(rpFileName, ExtractFileExt(rpFileName),'.zip', [rfReplaceAll, rfIgnoreCase]); fileName:= ExtractFileName(rpFileName); fileName:= ChangeFileExt(fileName,'.*'); try VCLUnZip1.ZipName:= '.\'+ zipFileName; VCLUnZip1.DestDir:= '.\'; VCLUnZip1.OverwriteMode:= Always; VCLUnZip1.ReadZip; VCLUnZip1.FilesList.Add(fileName); zipCount:= VCLUnZip1.UnZip; if zipCount = 0 then result:=false else result:=true; except on Exception do result:=false; end; end; 函数unzipReportFiles的作用是将压缩包中的文件解压出来,供ACTIVEX使用。它与REPORT SERVER程序中的zipReportFiles刚好是个相反的过程。 DesignReport(rpFileName:String)方法: function TreportAForm. DesignReport (rpFileName:String) :boolean; var dtfFileName,rpFileName:String; fldlist:TStringList; T: TStringField; i:Integer; begin …… dtfFileName:=StringReplace(rpFileName, ExtractFileExt(rpFileName),'.dtf', [rfReplaceAll, rfIgnoreCase]);//获得数据环境文件名 fldlist:=TStringList.Create; fldlist.LoadFromFile(dtfFileName); rpAdoquery.Fields.Clear; for i := 0 to fldlist.Count - 1 do begin T := TStringField.Create(nil); T.FieldName := fldlist[i]; T.Name := rpAdoquery.Name + T.FieldName; rpAdoquery.Fields.add(T); end; FrReport1.LoadFromFile(rpFileName); FrReport1.DesignReport; end; 函数DesignReport先从.dtf(由REPORT SERVER生成)文件中恢复报表的数据环境,接着使用FASTREPORT的FrReport控件设计报表。在FASTREPORT中,对DataSet中的Field只关心名称(全部通过Variant类型处理),而并不关心数据类型,所以恢复报表的数据环境时,所有字段都当作String类型加入。样例假设报表只有一个名为rpAdoquery的DataSet。报表设计运行时窗口在ACTIVEX进程空间运行。 用户端设计好报表并保存后,需要将保存的报表文件(.frf)回送给服务器存储。文件上传对于大部分开发人员来说应该都是熟悉而简单的,该部分程序本文就省略了。 PrintReport(rpFileName:String)方法: function TreportAForm. PrintReport (rpFileName:String) :boolean; var repFileName:String; begin …… repFileName:=StringReplace(rpFileName, ExtractFileExt(rpFileName),'.frp', [rfReplaceAll, rfIgnoreCase]);//获得已准备的报表文件名 try frPreview1.clear; FrReport1.Preview:=nil; FrReport1.clear; FrReport1.LoadPreparedReport(repFileName); FrReport1.Preview :=frPreview1; FrReport1.ShowPreparedReport; result:=true; except on Exception do result:=false; end; end; 函数PrintReport装入由REPORT SERVER运行好的报表.frp文件,通过调用FrReport的ShowPreparedReport方法在ACTIVEX端预览和打印。 方案实现方法的介绍结束。本方案具有的优点为:保持应用的结构形式不变(B/S),将C/S应用结构下已非常成熟的报表方案移植过来,使得在WEB应用中也可实现任意复杂的报表设计和打印,以及对打印效果进行精确控制。
󰈣󰈤
日版宠物情人插曲《Winding Road》歌词

日版宠物情人2017的插曲,很带节奏感,日语的,女生唱的。 最后听见是在第8集的时候女主手割伤了,然后男主用嘴帮她吸了一下,插曲就出来了。 歌手:Def...

兄弟共妻,我成了他们夜里的美食

老钟家的两个儿子很特别,就是跟其他的人不太一样,魔一般的执着。兄弟俩都到了要结婚的年龄了,不管自家老爹怎么磨破嘴皮子,兄弟俩说不娶就不娶,老父母为兄弟两操碎了心...

 
 
>>返回首頁<<
 
 
 
 
 熱帖排行
 
 
王朝网络微信公众号
微信扫码关注本站公众号 wangchaonetcn
 
  免责声明:本文仅代表作者个人观点,与王朝网络无关。王朝网络登载此文出于传递更多信息之目的,并不意味著赞同其观点或证实其描述,其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有