如鵬網 大學生計算機學習社區

          CowNew開源團隊

          http://www.cownew.com 郵件請聯系 about521 at 163.com

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            363 隨筆 :: 2 文章 :: 808 評論 :: 0 Trackbacks
           

            近日(呵呵,這篇文章是去年寫的)用了兩個月開發了一個物流信息系統,這個系統是兩層、三層相結合,C/SB/S相結合的系統。雖然限于時間的緊張和人手的原因,系統規模不是很大,但是其中涉及的技術卻很全面。在這個《開發技術篇》中我們將講解我在開發系統中遇到的技術問題及解決方案,希望對大家有幫助。對于物流信息系統的分析設計問題,我將在另一篇文章《物流信息系統開發手記――系統構架篇》中講解。

           

          一、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的數據包,可以將其附給ClientDatSetData屬性。

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

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

          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)、新建一個應用程序,通過DCOMConnectionSocketConnection等連接到MTS組件,然后就可以調用MTS的相應的方法實現客戶端功能了。

          放入cdsStockInListMastercdsStockInListSlave兩個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控件的名稱開頭一般為cdsTsocketConnection控件的名稱開頭一般為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;

          posted on 2005-10-22 00:51 CowNew開源團隊 閱讀(2263) 評論(1)  編輯  收藏

          評論

          # re: 物流信息系統開發手記-Delphi的三層開發 2009-12-12 15:43 hello
          想請教下Midas的安全問題,我認為,

          如果有一個軟件的正常用戶用LoginMTS()登錄之后,DataSetProvider和DataSet就關聯起來了。

          之后其它非法用戶再連接上此端口時,即使不需要LoginMTS(),DataSetProvider和DataSet也已經關聯,非法用戶也就可以訪問應用層的DataSet了。  回復  更多評論
            


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 临海市| 朝阳市| 台安县| 运城市| 察哈| 剑川县| 红安县| 育儿| 乐业县| 屯留县| 贡嘎县| 辽阳县| 瑞金市| 桂东县| 吴堡县| 永登县| 东城区| 河西区| 唐山市| 齐齐哈尔市| 章丘市| 淮南市| 庄河市| 屏东市| 大理市| 浏阳市| 社旗县| 敦化市| 西贡区| 阿坝县| 木兰县| 沐川县| 常山县| 西林县| 玛纳斯县| 郑州市| 合江县| 萨迦县| 石景山区| 瓦房店市| 时尚|