天天看點

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應用伺服器可采用資料庫連接配接池來提高通路效率;