線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:2424
推到 Plurk!
推到 Facebook!

用FASTREPORT實現WEB應用中自定義報表

 
jackkcg
站務副站長


發表:891
回覆:1050
積分:848
註冊:2002-03-23

發送簡訊給我
#1 引用回覆 回覆 發表時間:2003-09-14 00:37:11 IP:61.64.xxx.xxx 未訂閱
用FASTREPORT實現WEB應用中自定義報表 http://www.ccw.com.cn/applic/prog/htm2003/20030313_13X20.asp -------------------------------------------------------------------------------- 開發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文件後,先解壓出包中文件,再進行處理。 用FASTREPORT實現WEB應用中自定義報表 小學 2003-3-13 13:49:34 -------------------------------------------------------------------------------- 二、 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方式取得。 用FASTREPORT實現WEB應用中自定義報表 小學 2003-3-13 13:49:34 -------------------------------------------------------------------------------- 三、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應用中也可實現任意複雜的報表設計和列印,以及對列印效果進行精確控制。 ********************************************************* 哈哈&兵燹 最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好 Delphi K.Top的K.Top分兩個字解釋Top代表尖端的意思,希望本討論區能提供Delphi的尖端新知 K.表Knowlege 知識,就是本站的標語:Open our mind to make knowledge together! 希望能大家敞開心胸,將知識寶庫結合一起
------
**********************************************************
哈哈&兵燹
最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好

Delphi K.Top的K.Top分兩個字解釋Top代表尖端的意思,希望本討論區能提供Delphi的尖端新知
K.表Knowlege 知識,就是本站的標語:Open our mind
系統時間:2024-05-16 15:44:35
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!