程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> Delphi 三層 實例(2)

Delphi 三層 實例(2)

編輯:Delphi

一、Midas的安全問題。

    Midas技術是Delphi中進行三層開發的首選技術,它不僅有純DCOM/COM+(COM+技術是.NET技術的基礎)的優點,而且也結合了Delphi的快速開發特性,可以快速開發出想要的系統,其開發速度是用VC,PB等開發DCOM的數十倍,把程序員從煩雜的代碼中解脫出來,從而將更多的精力投入到業務邏輯的設計中去。

    但是Midas技術的一個最令人擔憂的就是它的安全問題:

遠端只要知道應用服務器的端口號即可訪問到應用服務器,而一旦訪問到應用服務器,TClientDataSet即可獲得ProviderNames列表。一旦知道了ProviderNames列表,這就相當於將數據庫暴露在外了。

關於可輕易獲得ProviderNames列表的問題,我使用下面的方法解決:

在服務器端定義一個

LoginMTS(const AUserId, APassword: WideString): WordBool;

方法。初始狀態下,所有的DataSetProvider和數據集的連接斷開。用戶必須調用LoginMTS並傳遞用戶名和密碼,登陸成功才將DataSetProvider和數據集的連接打開。這樣如果用戶驗證沒有通過,即使它獲得了ProviderNames列表也沒法調用接口中的方法對數據庫進行操作。

二、Midas中主從表的實現

主從表的應用在信息系統中應用很廣。在兩層開發中我們可以通過直接建立兩個數據集之間為主從關系來實現主從表;

在三層中雖然我們仍然可以通過直接建立兩個數據集之間為主從關系來實現主從表,但是這樣就要求把數據庫中所有相關的數據行都下載到本地,喪失了三層開發的優勢。我在實際中使用下面的方法實現。這裡我以實現入庫單查詢、添加、修改、刪除(CRUD)為例來講解:

(1)新建一個MTS Data Module,命名為TmtsStockInListBiz,增加如下方法:

    function QueryStockInListMasterById(const AId: WideString;var ADatas: OleVariant): WordBool; safecall;

    function QueryStockInListSlaveByMasterId(const AId: WideString;var ADatas: OleVariant): WordBool; safecall;

    procedure UpdataStockInListMaster(var ADatas: OleVariant); safecall;

    procedure UpdataStockInListSlave(var ADatas: OleVariant); safecall;

    function GenerateStockInListId: WideString; safecall;


QueryStockInListMasterById作用是根據入庫單單號查詢入庫單的基本信息(入庫日期、負責人等),Aid為入庫單單號,Adatas為返回值,其格式就是Midas的數據包,可以將其附給ClientDatSet的Data屬性。

QueryStockInListSlaveByMasterId作用是根據入庫單單號查詢入庫單的詳細信息(商品條碼,數量)

UpdataStockInListMaster是對入庫單主表進行刪除、添加、修改操作。只要將ClientDataSet的Delta屬性做為傳遞即可。

UpdataStockInListSlave是對入庫單從表進行刪除、添加、修改操作。

GenerateStockInListId是產生一個唯一的入庫單號。

下面是幾個方法的代碼,都很簡單,就不多解釋了,可以查看Delphi的幫助。

function TmtsStockInListBiz.QueryStockInListMasterById(

const AId: WideString; var ADatas: OleVariant): WordBool;

begin

result := false;

ADatas := null;

try

    cdsQuery.Close;

    cdsQuery.CommandText := 'select * from t_StockInListMaster where Id=:Id';

    cdsQuery.Params.ParamByName('Id').AsString := AId;

    cdsQuery.Open;

    if cdsQuery.RecordCount > 0 then

    begin

      result := true;

      ADatas := cdsQuery.Data;

    end;

finally

    cdsQuery.Close;

end;

end;


procedure TmtsStockInListBiz.UpdataStockInListMaster(

var ADatas: OleVariant);

var

eCount: Integer;

OwnerData: OleVariant;

begin

DCOMConStockInList.GetServer.AS_ApplyUpdates('dspStockInListMaster',

    ADatas, -1, eCount, OwnerData);

end;


function TmtsStockInListBiz.GenerateStockInListId: WideString;

var

LPrior: string;

i: Integer;

begin

cdsQuery.Close;

cdsQuery.CommandText := 'select top 1 id from t_StockInListMaster order by id desc';

cdsQuery.Open;

LPrior := cdsQuery.FieldByName('Id').AsString;

i := StrToIntDef(RightStr(LPrior,8),0);

Inc(i);

result := 'RK' + FormatFloat('00000000',i);

cdsQuery.Close;

end;


(2)、新建一個應用程序,通過DCOMConnection、SocketConnection等連接到MTS組件,然後就可以調用MTS的相應的方法實現客戶端功能了。

放入cdsStockInListMaster、cdsStockInListSlave兩個ClientDataSet控件,在控件上點擊右鍵,選擇“FieldsEditor”新建於服務器中的字段同樣的字段,然後再次在控件上單擊右鍵,選擇“CreateDataSet”,建立一個本地數據庫。

(3)根據入庫單號查詢入庫單的方法實現:

procedure TFormStockInList.BtnFindClick(Sender: TObject);

var

v,vs: OleVariant;

begin

if SocketConStockInList.AppServer.QueryStockInListMasterById(Trim(LEdtId.Text), v) then

begin

    cdsStockInListMaster.Data := v;//顯示入庫單主表(主要信息)


    if SocketConStockInList.AppServer.QueryStockInListSlaveByMasterId(Trim(LEdtId.Text), vs) then

      cdsStockInListSlave.Data := vs; ;//顯示入庫單從表(明細信息)

end

else

    ShowMessage('此單不存在!');

end;

(4)新建入庫單的實現

procedure TFormStockInList.BtnNewClick(Sender: TObject);

var

LId: string;

begin

ClearCDSRecord;

cdsStockInListMaster.Open;

cdsStockInListMaster.Insert;

LId := SocketConStockInList.AppServer.GenerateStockInListId;

LEdtId.Text := LId;

cdsStockInListMaster.FieldByName('Id').AsString := LId;

cdsStockInListMaster.FieldByName('GenerateDate').AsDateTime := Now();

end;

(5)提交功能的實現

procedure TFormStockInList.BtnPostClick(Sender: TObject);

var

LQuerymts: ImtsQueryObjDisp;

LBar: string;

begin

SetSocketConnectionConnect(SocketConQuery);

LQuerymts := ImtsQueryObjDisp(SocketConQuery.GetServer);


SocketConQuery.Close;


if cdsStockInListMaster.RecordCount > 0 then

    SocketConStockInList.AppServer.UpdataStockInListMaster(cdsStockInListMaster.Delta);

if cdsStockInListSlave.RecordCount > 0 then

SocketConStockInList.AppServer.UpdataStockInListSlave(cdsStockInListSlave.Delta);

end;

注:本文中ClientDataSet控件的名稱開頭一般為cds、TsocketConnection控件的名稱開頭一般為SocketCon。

三、動態設置TsimpleObjectBroker的服務器列表

procedure SetSocketConnectionConnect(AValue: TSocketConnection);

procedure FillAppServerList(ABroker: TSimpleObjectBroker);

var

    sl: TStringList;

   i, n: Integer;

begin

    sl := TStringList.Create;

    從配置文件中讀取服務器列表,並保存到sl中;

    n := sl.Count - 1;

    ABroker.ServerData := null;

    for i := 0 to n do

    begin

      ABroker.Servers.Add;

      ABroker.Servers[i].ComputerName := sl.Strings[i]

   end;

    sl.Free;

end;

var

LBroker: TSimpleObjectBroker;

begin

LBroker := TSimpleObjectBroker.Create(nil);

    FillAppServerList(LBroker);

    AValue.ObjectBroker := LBroker;

    try

      AValue.Connected := true;

    except

      raise Exception.Create('應用服務器連接錯誤!');

    end;

    LBroker.Free;

end;

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved