java delphi 三层_三层架构delphi+Java+Oracle模式的实现
【架構簡介】
*本架構以delphi作為客戶端,Java作為服務端,oracle作為后臺數據庫數據。其中delphi客戶端的封裝為了保持與原來的開發方式兼容都是基于TclientDataSet實現的;
*本架構選擇基于阻塞模式的Indy通信套件作為通信工具;以tcp/ip作為通信協議 ,直接以流的的形式與Java服務端進行交互;
*本架構的通信過程如下:
請求開始->打包壓縮請求數據->發送請求數據->delphi端阻塞等待->Java端多線程響應請求->解壓解包請求數據->處理請求->打包壓縮處理結果->發送處理結果->
delphi端停止阻塞接收處理結果->解壓解包處理結果->顯示結果
*本架構主要解決以下問題:
1.如何將Java從數據庫中讀出來的數據打包成TClientDataSet可以讀取的數據包;要解決這個問題就需要深入了解TclientDataSet的DataPackage的xml格式。
2.如何將新增-修改-刪除后的TClientDataSet數據通過Java保存到數據庫中;要解決這個問題就需要深入了解TclientDataSet的Delta屬性。
3.如何處理Oracle的大對象字段類型(clob或blob)。
4.delphi端如何調用Java端定義的對應的業務邏輯供。
5.Java端多用戶并發處理效率問題。
6.數據包的格式定義‘打包解包‘壓縮解壓’加密解密問題。
1.【TclientDataSet的DataPackage格式】
TclientDataSet的DataPackage格式一般如下:
-
-
-
-
2.【DataPackage的結構分析】
整個XML定義了一個DataPacket;DataPacket包括兩個部分:MetaData和RowData。MetaData包括Fields和Params,即包括數據字段定義和數據集參數。
RowData為具體記錄。 下面詳細分析數據字段定義的方法。
Field節點的定義主要包括:
1>attrname指FieldName
2>fieldtype指字段類型
3>width指需要寬度的字段類型的寬度或數字的有效位數;
4>decimals指小數點右邊的位數;
Oracle主要字段類型具體的對應信息如下表:
_____________________________________________________________________
OracleType?| fieldtype? ?| WIDHT?| SUBTYPE???? ?| DECIMALS?| READONLY
---------------------------------------------------------------------
Char??????????? ??| string????? ?|???? 1??????????? FixedChar
---------------------------------------------------------------------
Char(n)??????? ?| string???? ? |??? ?n??????????? FixedChar
---------------------------------------------------------------------
Varchar(n)?? ?| string?????? |???? ?n
---------------------------------------------------------------------
Varchar2(n)? | string?????? |??? ? n
---------------------------------------------------------------------
data????????????? | dateTime?|
---------------------------------------------------------------------
Number(s,p)?| fixed?????? ?|??? ? s?????????????????????????????????????? p
---------------------------------------------------------------------
Number(*,p)?| fixed????? ?|???? ?38???????????????????????????????????? p
----------------------------------------------------------------------
Number(s)? ? | fixed????? ?|?????? ?s
----------------------------------------------------------------------
Number??????? | fixed????? ?|????? ? 38
----------------------------------------------------------------------
int????????????????| fixed??????? |?????? 38
----------------------------------------------------------------------
Smallint???????| fixed?????? ?|??????? 38
----------------------------------------------------------------------
Dec(s,p)????? | fixed?????? ?|???????? s?????????????????????????????????????p
----------------------------------------------------------------------
Float??????????? | R8???????? ??|
----------------------------------------------------------------------
Real?????????????| R8????? ??? ?|
----------------------------------------------------------------------
其中用SubType屬性來幫助決定類型。表中沒有值的單元格,表示該屬性沒有用到。
并且DataPakage中如果想包含中文的話,記得要在第一句的中間加上encoding=”GB2312”,否則用數據庫相關控件讀出來的只會是亂碼。
記住位置很重要的。你必須寫成下面的形式:
如果寫成下面的也是不滿足形式良好的規范的:
3.【XML的轉義字符】
在XML語言中,用實體對特殊字符進行轉義.
如果在XML文檔中使用類似"
所以不應該像下面那樣書寫代碼:
if salary < 1000 then
為了避免出現這種情況,必須將字符"
if salary < 1000 then
下面是五個在XML文檔中預定義好的實體:
---------------------
<? | < | 小于號
---------------------
>? | > | 大于號
---------------------
&? | & | 和
---------------------
' | ' | 單引號
---------------------
" | " | 雙引號
---------------------
實體必須以符號"&"開頭,以符號";"結尾。
注意: 只有"
4.【Oracle的大對象字段類型(clob和blob)】
因為TclientDataSet不支持clob和blob等大對象字段類型,所以我們要使用別的方法來實現相應的讀寫操作;
5.【關于TClientDataSet的Delta屬性】
TClientDataSet.Delta屬性表示當前操作的ClientDataSet中記錄變化的信息
Delta信息可以用另外的ClientDataSet來顯示;如myCDS.Data := OrgCDS.Delta
TclientDataSe的UpdateStatus屬性反映當前記錄的更新狀態; 根據更新數據的情況其可能的值分別為:
1.新增一條記錄時,在Delta中會有一條記錄,標記為usInserted;
2.修改記錄時,在Delta中對于同一條記錄會產生且僅產生兩條記錄:第一條為原始記錄,標記為usUnmodified,第二條只有修改過的字段才有值,標記為usModified
3.刪除記錄時,在Delta中會產生一條記錄,標記為usDeleted;
根據以上Delta屬性就可以生成相應的更新SQL語句;
6.【數據包的格式定義】
6.1.數據包采用變長字符串的方式組織,一般由數據節點和分隔符及結束符組成。具體結構如下圖:
|? 數據節點? |分隔符 |? 數據節點? |分隔符 |? 數據節點? |分隔符 | ... |結束符 |
6.2.數據節點一般由數據長度和數據值組成。
6.3.當數據值的長度小于等于999時數據節點的組成如下圖:
|數據長度 |? 數據值? |分隔符 |數據長度 |? 數據值??? |分隔符 | ... |結束符 |
6.4.當數據值的長度大于999時數據節點的組成如下圖:
|003? |數據長度的長度 |? /? ?|數據長度 |? 數據值??? |分隔符 | ... |結束符 |
6.5數據包格式定義說明:
#數據長度為數據值長度的長度字符串;
#數據長度的長度為數據值長度的長度字符串的長度字符串;
#分隔符一般為冒號;當數據值的長度大于999時分隔符為"/";
7.【JAVA應用服務器】
應用服務器最重要的就是穩定,支持高效的多用戶并發處理;所以應用服務器應該是無狀態的;然后是易于部署的;
java天生就是用來編寫服務器的;成熟的j2ee企業級應用;豐富的開源思想;于是java就成了實現應用服務器的不二選擇;
JAVA應用服務器具體實現以下功能:
1>使用一個ServerSocket監聽Delphi客戶端發送請求的命令;
2>針對每個Delphi客戶端發送的請求開啟線程解析處理請求;通過JAVA端的多線程來達到高效處理多用戶并發的情況。
3>通過反射和command設計模式來分派Delphi端請求的相應的業務邏輯對象進行處理;
3>通過JDBC與Oracle數據庫交互;
其實只要數據到了java端,那么只要你愿意你可以選擇任意的中間件技術:weblogic,websphere,jboss等等作為應用服務器,
而盡想其提供的豐富的管理功能;
8.【接口規劃】
*************************************************************************************************************************
函數功能: 發送操作命令和數據到應用服務器
函數聲明: function StreamCommand(ASendText:WideString;ASendStream:TStream=nil):TStream;stdcall;external Communication;
參數說明: -------------------------------------------------------
參數名稱????????????????????? 描述
-------------------------------------------------------
ASendText?????? 要發送的字節數據(一般應包括命令信息)
-------------------------------------------------------
ASendStream???? 要發送的內存流或文件流等數據(默認為nil)
-------------------------------------------------------
函數說明:正常返回字節流數據(可能返回空串);異常返回nil;此函數一般供DLL中的接口函數調用;
用例:Result:=StreamCommand('013SelectCommand:045SELECT * FROM CRM_CUSTOMER WHERE B_COMPANY=1 :');
這個語句的意思是發送一個查詢命令到AppServer,命令的內容為SELECT * FROM CRM_CUSTOMER WHERE B_COMPANY=1;
如果命令能正確執行,那么AppServer會把查詢的結果打包發送到客戶端,以字節流的形式返回.
**************************************************************************************************************************
函數功能: 查詢單個數據集
函數聲明: function SelectCommand(ACDS: TClientDataSet;const ASelectText: string):Boolean;stdcall;external Communication;
參數說明: -------------------------------------------------------
參數名稱????????????????????? 描述
-------------------------------------------------------
ACDS?????????? 存放查詢結果集的TClientDataSet
-------------------------------------------------------
ASelectText???? 要發送的單條查詢語句
-------------------------------------------------------
函數說明: 成功返回[true](包括只有數據元的空數據集);失敗返回[false]
用例: Result:=SelectCommand(cdsTemp,'SELECT * FROM CRM_CUSTOMER');這個語句的意思是:
發送一個查詢語句到AppServer,如果命令能正確執行,那么AppServer會把查詢的結果集打包發送到客戶端事先創建好的cdsTemp中.
*************************************************************************************************************************************
函數功能:同時查詢多個數據集
函數聲明:function SelectCommands(ACDS:Array of TClientDataSet;const ASelectText: TStringList):Boolean;stdcall;external Communication;
參數說明:-------------------------------------------------------
參數名稱????????????????????? 描述
-------------------------------------------------------
ACDS?????????? 存放查詢結果集的多個TClientDataSet列表
-------------------------------------------------------
ASelectText???? 要發送的多條查詢語句列表
-------------------------------------------------------
函數說明:成功返回[true](包括只有數據元的空數據集);失敗返回[false]
用例:
var
sSql:string;
sList:TStringList;
cdsTemp1,cdsTemp2,cdsTemp3:TClientDataSet;
begin
try
cdsTemp1:=TClientDataSet.Create(nil);
cdsTemp2:=TClientDataSet.Create(nil);
cdsTemp3:=TClientDataSet.Create(nil);
sList:=TStringList.Create;
try
sSql:='SELECT * FROM Table1';
sList.Add(sSql);
sSql:='SELECT * FROM Table2';
sList.Add(sSql);
sSql:='SELECT * FROM Table3';
sList.Add(sSql);
//把第一條查詢語句的結果集存放到cdsTemp1,把第二條查詢語句的結果集存放到cdsTemp2,依次類推存放順序
SelectCommands([cdsTemp1,cdsTemp2,cdsTemp3],sList);
finally
if Assigned(cdsTemp1) then FreeAndNil(cdsTemp1);
if Assigned(cdsTemp2) then FreeAndNil(cdsTemp2);
if Assigned(cdsTemp3) then FreeAndNil(cdsTemp3);
if Assigned(sList) then FreeAndNil(sList);
end;
except
end;
end;
**************************************************************************************************************************
函數功能: 發送一條或多條update or insert or delete類型的SQL語句到應用服務器執行
函數聲明: function ExecuteCommands(const AExecuteText: TStringList): integer;stdcall;external Communication;
參數說明: -------------------------------------------------------
參數名稱????????????????????? 描述
-------------------------------------------------------
AExecuteText???? AppServer能解析的SQL語句
-------------------------------------------------------
函數說明: 正常返回0;異常返回非0;本函數主要供ApplyUpdates函數調用;
用例:
**************************************************************************************************************************
函數功能: 發送一條update or insert or delete類型的SQL語句到應用服務器執行
函數聲明: function ExecuteCommand(const ACommandText:WideString):integer; stdcall;external Communication;
參數說明: -------------------------------------------------------
參數名稱????????????????????? 描述
-------------------------------------------------------
ACommandText???? 要執行的SQL語句
-------------------------------------------------------
函數說明: 正常返回0;異常返回非0;
用例:
**************************************************************************************************************************
函數功能: 根據數據集列表的修改信息自動生成相應的SQL語句
函數聲明: function CreateUpdates(const ATableNames: array of string ;ACDS:array of TClientDataSet;var sSqlList:string): Boolean;stdcall; external Communication;
參數說明: -------------------------------------------------------
參數名稱????????????????????? 描述
-------------------------------------------------------
ATableNames???? 數據集列表對應的表名列表
-------------------------------------------------------
ACDS??????????? 修改過的數據集列表
-------------------------------------------------------
sSqlList???????? 存放對應生成的SQL語句
-------------------------------------------------------
函數說明: 成功返回[true];失敗返回[false]
本函數根據數據集中的修改信息自動生成Insert,Update,Delete類型的多條SQL語句.
用例: 1>Result:=CreateStatement(['TableName1','TableName2','TableName3','TableName4'],[cds1,cds2,cds3,cds4]); 或者
2>Result:=CreateStatement(['TableName1'],[cds1]);
本用例會根據數據集列表中每個數據集的修改信息自動生成相應的SQL語句,這樣就完成了操作界面到SQL語句之間的直接映射.
**************************************************************************************************************************
函數功能: 更新多個數據集
函數聲明: function ApplyUpdates(const ATableNames: array of string ; ACDS:array of TClientDataSet): Boolean;stdcall; external Communication;
參數說明: -------------------------------------------------------
參數名稱?????????????? 描述
-------------------------------------------------------
ACDS?????????? 要更新的數據集列表
-------------------------------------------------------
ATableNames???? 要更新的表名列表
-------------------------------------------------------
函數說明: 成功返回[true];失敗返回[false]
表名列表與數據集列表應該一一對應
用例: Result:=ApplyUpdates(['TableName1','TableName2','TableName3','TableName4'],
[cds1,cds2,cds3,cds4]);
本用例會根據數據集列表中每個數據集的修改信息自動生成相應SQL語句,然后把所有的SQL語句一起發送到AppServer進行事務處理.
*****************************************************************************************************************
函數功能: 保存Oracle大對象字段類型(clob或blob)
函數聲明: function SaveBlob(SqlText:WideString;LobID:WideString;LobContent:TStream):integer;stdcall; external Communication;
參數說明: -------------------------------------------------------
參數名稱?????????????? 描述
-------------------------------------------------------
SqlText?????????? 保存前要執行的SQL語句
-------------------------------------------------------
LobID???????????? 包含Oracle大對象字段類型的記錄的ID
-------------------------------------------------------
LobContent??????? 要保存的Oracle大對象字段類型的內容
-------------------------------------------------------
函數說明: 成功返回[0];失敗返回[非0]
用例:
*****************************************************************************************************************
函數功能: 顯示Oracle大對象字段類型(clob或blob)
函數聲明: function SelectBlob(LobID:WideString):TStream;stdcall; external Communication;
參數說明: -------------------------------------------------------
參數名稱?????????????? 描述
-------------------------------------------------------
LobID???????? 包含Oracle大對象字段類型的記錄的ID
-------------------------------------------------------
函數說明: 成功返回Oracle大對象字段類型對應的流;失敗返回[nil];
用例:
9.【擴展功能】
1>客戶端數據緩存機制保證運行的高效性:客戶端可以緩存大量的客戶端數據,并提供了一定程度的離線操作功能;
這樣在提高戶交互效率的同時,減少網絡數據通訊量;還能降低服務器的負載。
2>客戶端自動更新機制:便于客戶端的部署和版本更新
3>權限管理:包括功能權限和數據權限;
4>客戶端采用模塊化(DLL)設計保證系統的可擴展性;
5>運行時自定義報表;
6>JAVA應用服務器可采用數據庫連接池來提高訪問效率;
總結
以上是生活随笔為你收集整理的java delphi 三层_三层架构delphi+Java+Oracle模式的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 云顶之弈S2黑切给谁用?最佳黑切使用英雄
- 下一篇: ASCII码表