• <sub id="h4knl"><ol id="h4knl"></ol></sub>
    <sup id="h4knl"></sup>
      <sub id="h4knl"></sub>

      <sub id="h4knl"><ol id="h4knl"><em id="h4knl"></em></ol></sub><s id="h4knl"></s>
      1. <strong id="h4knl"></strong>

      2. 分布式多層數據庫系統的應用(一)

        時間:2024-06-27 18:51:54 計算機畢業論文 我要投稿
        • 相關推薦

        分布式多層數據庫系統的應用(一)

        摘要
         
        本次畢業設計任務是通過開發一個分布式多層數據庫圖書管理系統,學習用delphi開發分布式多層數據庫系統。采用Delphi6.0和MS Server2000等軟件為開發工具;通過對計算機硬件和軟件解決方案的論證;對應用領域進行調查分析;參考各種資料和進行數據庫編程實踐。在指導老師的幫助下,已經基本上成功地實現了設計任務書的要求。使得設計的數據庫系統能夠實現一般數據庫的管理。我們研究了數據庫的查詢優化問題。

         第一部分  引 言
         
        1.1任務或問題:
         開發一個分布式多層圖書管理系統,可以實現動態的連接應用程序服務器,只要對配置文件進行配置,就可以像網上鄰居一樣選擇所要連接的應用程序服務器。并提供借書還書,圖書和期刊檢索等查詢功能。
        1.2實際背景:
         隨著社會發展,人類的生產、生活越來越離不開信息。誰擁有了更多更有效的信息,誰就將在競爭中處于有利地位。信息產業正在成為一個國家的支柱。數據作為信息的載體,其管理工具數據庫對于信息技術的重要性,正日益得到人們的重視。只有擁有了先進的數據庫技術,才能有效地管理好浩如煙海的數據,并從中提取出對自己有用的信息來加以利用。
         90年代,人們開發MIS系統大都采用客戶機/服務器結構,客戶機/服務器結構既是硬件結構又是軟件結構。即數據放在服務器上,程序在客戶機上。進行數據訪問時,由客戶機提出請求(一般是SQL語句),服務器執行并給出結果。客戶機/服務器對于優化了網絡,提高了系統的利用率。客戶機/服務器體系結構的發展經歷了從二級體系結構模式到三級體系結構模式。
        1.3我的工作
            設計系統框架,設計數據庫,編寫代碼,測試數據等。
        1.4特色(創新)
         可以像網上鄰居一樣選擇所要連接的應用程序服務器。
         
         第二部分 畢業設計課題
         
        設計課題
         漳大圖書館管理系統
        設計時間
         二○○四年10月至二○○四年12月
        設計人員及任務
         王東凱  動態連接服務器模塊的實現及幫助件功能模塊的實現
         王開斌  分布式多層數據模塊的實現
         王杰林  圖書管理功能模塊的實現
         陳慶輝  sqlserver 2000數據庫的分析及表的設計
        指導老師
         蘇綠園
        設計內容
         利用Delphi6.0和MS Server2000為主要開發工具,以WindowsXP為開發平臺。設計出分布式多層應用的圖書館管理系統。可以實現動態的連接應用程序服務器,只要對配置文件進行配置,就可以像網上鄰居一樣選擇所要連接的應用程序服務器。實現與應用程序服務器快速而準確的連接。
         
         第三部分 系統方案論證
         
        3.1軟件定義 
            數據庫設計所要的解決的問題是:對于一個給定的應用領域,設計優化的數據庫邏輯和物理結構,使之滿足用戶的信息管理要求和數據操作要求,有效地支持各種應用系統的開發和運行。數據庫設計的目標是為用戶和各種應用系統提供一個高效的運行環境。而數據庫的設計可以視為如下的優化問題。
        計算機的軟硬件環境;
        數據庫管理系統的能力;
        用戶的操作要求與信息要求;
        完整性和安全性約束。
        3.2 體系結構規劃
         本次設計的系統采用 三層″客戶/服務器″體系,為了便于理解,我們先從二層″客戶/服務器″體系結構來闡述:
         客戶/服務器是在網絡基礎上,以數據庫管理為后援,以計算機為網上工作站的一種系統結構。該結構的關鍵在把網絡環境上的數據庫存取和應用程序一分為二,分別由網上的數據庫服務器和網上客戶來執行。雖然本系統客戶/服務器是建立在LAN的基礎上,但它比以往的文件服務系統有了很大的改進。首先,它消除了不必要的網絡傳輸負擔;其次,它可以使作為數據庫服務器的計算機被高度優化,以適應數據處理的需要。客戶/服務器已經能夠應用于復雜的網絡上,并使之能夠更有效地進行選擇、檢索、索引排序等數據處理。作為一種高級的分布式計算機環境、客戶/服務器有足夠的能力把處理后的結果(不是整個文件)通過網絡傳輸出去,并根據用戶需求靈活地配置各種大、中、小型計算機系統。
        3.3 系統設計
        數據流圖
                     
                     管理要求                           查詢要求

                      管理結果                          查詢結果


                                            (頂層數據流圖)
        數據庫設計過程
         數據庫的設計過程如下圖所示。在數據庫設計過程中,需求分析和概念設計可以獨立于任何數據庫管理系統進行。邏輯設計和物理設計與具體的數據庫管理系統密切相關。由于需求分析比較重要。我們在設計的時候,花了比較多的時間。在獲得這些資料之后,進行分析。從中提取有用的部分。分析各種用戶的權限。
                                  需求分析說明書
             圖:數據庫設計過程
         
         第四部分 畢業設計內容
         
        4.1分布式多層數據庫開發簡介
         Delphi提出的MIDAS(Multi-Tier distributed Application Services Suite多層分布式應用服務器組),是把原來Two- Tier數據連接放到了服務器端的COM組件上,客戶端只剩下了執行文件和MIDAS.DLL,前臺和服務器上的COM組件,通過DCOM機制互相溝通。
         這個多的一層,稱為應用程序服務器(Application Server),或者稱為中間件。整個工作機制見下圖:
         
         這種多層分布式工作機制,主要基于這樣幾點考慮:
        減少客戶機的維護量,因為前臺程序比較簡單;
         把企業邏輯封裝在通用的中間件應用服務器中,不同的客戶都可以共享同一個中間層(包括Web),而不必每個客戶都單獨實現企業規則,避免了重復開發和維護的麻煩。由于客戶程序相當瘦(這就是現在流行的瘦客戶機概念),無論是開發還是發布,都變得簡單了。
        便于升級,當中間件升級的時候,客戶程序可能不需要變化;
        實現了分布式數據處理,把一個應用程序分布在幾臺機器上運行,可以提高應用程序的性能,也可以把敏感部分封裝在中間件,為不同的用戶設置不同的訪問權限,增強了安全性。
        減少直接連接數據庫的用戶數目,減少費用。
         在Delphi 6.0上,在原來的MIDAS基礎上,發展了DataSnap技術,在很多細節方面,它提供了原來MIDAS所沒有的許多功能,使用上更加方便了。
         DataSnap主要提供客戶端和中間件之間的通信,不但支持COM+技術也支持TCP/IP或者CORBA,它們使用類似的界面和方法,其結果由程序自動完成,這就大大擴充了它的應用范圍。
         必須要提醒的是,前臺機器上除了應用程序以外,還必須把一個MIDAS.DLL文件復值到前臺機器上,這個文件在服務器的WINNT\System32目錄下。
         
        4.2 服務器端程序的建立

            服務器端程序實際上是個COM 工程,它本身連接數據源,再通過接口與客戶端聯系,這個COM 工程必須注冊在服務器上。
         首先建立一個空白的工程,在工程里放置一個Adoconnection組件。然后再建一個遠程數據模塊file -> New -> Other -> Multitier -> Remote Data Module(遠程數據模塊)。   Coclass Name : libserver ,Instancing  :執行模式,大部分用Multiple Instance(多重實例),Threading Model:線程模式,建議用Apartment(單元),產生一個窗口,在這個窗口里,可以放入數據控件。
            在Viwe -> Type Libray 中,我們可以看到這個COM 的一些特性。我們也可以記下系統提供的GUID,以備后來使用。加入一個ADOTable,并設置其指向一個數據庫。再設置一個DataSetProvider(在DataAccess頁)指向ADOTable,這就完成了服務器端的程序設計。
        保存,編譯,注冊(注意,只要運行就自動在本機注冊了)。

        4.3 客戶端程序的建立

            在Two-Tier模式中,客戶端(Client)程序是直接和服務器的數據源相連的,而Multi-Tier模式,多個客戶端連接的是一個應用程序服務器,因為收費是按客戶端數計算的,所以,數據庫的使用費用比較低。
            1)建立一個普通的工程。   
         2)放置一個TDCOMConnrction控件(在Datasnap頁),屬性:在本機注冊時,可直接設置以下屬性:ServerName:應用程序服務器注冊名(server.libserver)   ,Connected=true。這時你可以看到服務器端的COM 程序被激活了。如果在網絡上調試,需要給出服務器名:ComputerName:服務器名(自動給出網上鄰居)注意: ServerGUID的GUID值是自動給出的。
         3)放置一個TClientDataSet控件(在Data Access頁),屬性RemoteServer= DCOMConnrction1,ProviderName:=DataSetProvider1(服務器端將被激活),Active=true (激活后將能正常連接)
            4)放置TDataSource,屬性:Dataset:指向cdsCustomer。
         這樣一個客戶端程序就建立好了,其余猶如普通的數據庫設計。
         
        4.4  客戶端實現SQL 查詢

            由于在客戶端不存在TQuery控件,似乎客戶服務器模式是無法做SQL查詢的。但是,Delphi很好的解決了這個問題。事實上,只要客戶端連接上服務端應用程序,客戶端的TClientDataSet就包含了一個名字為Provider的屬性,對應到服務器端DataSetProvider的所有默認屬性和方法,其中DataSetProvider有一個Options屬性,只要讓其中的poAllowCommandText=true, 那么,DataSetProvider的poAllowCommandText就可以接受前臺來的SQL 命令,并傳送給TQuery。
            可以看出,真正傳遞數據的是DataSetProvider的接口,所以,用這個接口搭建傳遞SQL 的橋梁是必需的。客戶端進行SQL 查詢的方法是:
              ClientDataSet.Close;
              ClientDataSet.CommandText := 'SQL語句';
         ClientDataSet.Open;
         
        4.5 動態連接應用程序服務器的實現
         
          客戶端程序在運行時,需要連接應用服務器程序以取得服務。但是,在系統實際應用的時候,運行應用服務器程序的計算機是經常改變的,因此在客戶端程序啟動時,應該先找到運行應用服務器程序的計算機的設置。動態連接應用服務器的流程類似于12.3節的動態數據庫連接,動態連接應用服務器程序的流程圖14-1所示。
         掌握了動態連接應用服務器的流程,就可以具體實現它。下面就將分步驟介紹動態連接應用服務器的實現過程。
        在Delphi中新建一個窗體,將單元文件保存為connect.pas窗體的Name屬性設為fm_serconfig,Caption屬性設為”服務器配置”,運行后窗體如下圖所示。
         
         (2) 在“連接設置”窗體中,需要輸入應用服務器主機名(或者應用服務器IP地址)和應用服務器的端口號,這些配置信息將用來連接應用服務器。如果連接成功,輸入的配置信息將被寫入到注冊表中,以后程序啟動時,讀取注冊表配置信息,就可而已連接應用服務器程序了。程序的具體實現部分如程序清單如下所示。
        procedure BitBtn1Click(Sender: TObject);
        procedure Button1Click(Sender: TObject);
        private
        procedure WriteToReg(const bappHost,bappIp,aPort:string);
        { Private declarations }
        public
        { Public declarations }
        end;
        var
           fm_SerConfig: Tfm_SerConfig;  Connected: boolean= false;   //代表是否連接成功
         implementation
         uses netlist, data;
         {$R *.dfm}
         procedure Tfm_SerConfig.BitBtn1Click(Sender: TObject);
         begin
            if ((Edt_host.Text='') or (Edt_host.Text=null))
               and((Edt_ip.Text='') or (Edt_host.Text=null)) then
            begin
            application.MessageBox('請輸入服務器和IP','輸入錯誤',
                              mb_iconinformation + mb_defbutton1);
            exit;
            end;
            try
              strtoint(edt_Port.text);
            except
               Application.MessageBox('請輸入正確的端口號', '輸入錯誤..', mb_iconinformation + mb_defbutton1);
              exit;
            end;
            statusbar1.Panels[0].Text:='正在連接服務器,pleale wait';
            statusbar1.Refresh;
            screen.Cursor:=crHourGlass;
            fm_data.Socket.Connected:=false;
            fm_data.Socket.Host:=edt_host.Text;
            fm_data.Socket.Address:=edt_ip.Text;
            fm_data.Socket.Port:=strtoint(edt_port.Text);
            try
              screen.Cursor:=crdefault;
              fm_data.Socket.Connected:=true;
              application.MessageBox('連接成功','圖書管理系統', mb_iconinformation + mb_defbutton1);
              connected:=true;
            except
              screen.Cursor:=crdefault;
              application.MessageBox('連接失敗','圖書管理系統',mb_iconinformation+mb_defbutton1);
              connected:=false;
            end;
         //連接成功向注冊表里寫入應用服務器配置信息
           WriteToReg(edt_Host.Text, edt_IP.Text, edt_Port.Text);
           close;
         end;
         //利用可視化窗體來選擇計算機
         procedure Tfm_SerConfig.Button1Click(Sender: TObject);
         begin
         edt_ip.Clear;
         edt_host.Text:=   NetExecute(TFm_NetList);
         end;
         //把信息寫入注冊表
         procedure Tfm_SerConfig.WriteToReg(const bappHost,bappIp,aPort:string);
         var
         reg:Tregistry;
         begin
           reg:=Tregistry.Create;
           reg.RootKey:=HKEY_LOCAL_MACHINE;
           if not reg.OpenKey('\Software\pz',false) then //如果可以創建目錄
           begin
           reg.CreateKey('\Software\pz');
           reg.OpenKey('\Software\pz',false);
           end;
           reg.WriteString('host',bapphost);
           reg.WriteString('ip',bappip);
           reg.WriteString('port',aport);
           reg.Free;
         end;
         end.
         打開“連接設置”配置窗口,在打開窗體之前,函數已經將布爾變量Connected設為False,而在窗體被關閉之后,將返回Connected變量的值,根據布爾變量Connected的值可以判斷是否已經連接上應用服務器。
         (3) 在連接設置主窗口中,我們為應用服務器名提供了輔助錄入的方法,點擊應用服務器名編輯框右邊的省略號按鈕(Button1),將彈出一個瀏覽局域網計算機的對話框,以方便用戶選擇應用服務器所在的計算機。在此我們調用了一個NetExecute方法,它將返回用戶選中的計算機的主機名。這個方法是如何實現的呢?下面將介紹NetExecute方法的實現過程。
         在Delphi中新建一個窗體,將窗體單元文件保存為netlist .pas,窗體的Name屬性設為Fm_netlist。運行后窗體如下圖所示。
         
         在列舉網絡資源窗體中,將按照工作組以樹型目錄的形式顯示局域網中的計算機。程序的具體實現部分如下所示。
        procedure FormActivate(Sender: TObject);
        procedure TreeView1Click(Sender: TObject);
        procedure BitBtn1Click(Sender: TObject);
        private
          procedure getcomputername;
          procedure getgroupname;
          { Private declarations }
        public
          { Public declarations }
        end;
        function NetExecute(aFormClass: TFormClass): string;
        var
          fm_NetList: Tfm_NetList;
          node: Ttreenode;
          aComputerName : string;//全局變量,存儲選中的主機名
        implementation
        {$R *.dfm}
        //打開窗體,并返回選定的計算機
        function NetExecute(aFormClass: TFormClass): string;
        begin
          aComputerName := '';
          with aFormClass.Create(Application) do
          begin
            try
              showModal;
            finally
              free;
            end;
            result := aComputerName;
          end;
        end;

        procedure TFm_netlist.FormActivate(Sender: TObject);
        begin
        node:=treeview1.items.add(Treeview1.topitem, '整個網絡');
        node.imageindex:=0;
        treeview1.setfocus;
        end;

        procedure TFm_netlist.TreeView1Click(Sender: TObject);
        begin
          if treeview1.Selected.Level=0 then
          begin
            if treeview1.Selected.Count=0 then
            //添加工作組名
            getgroupname();
          end;
          if treeview1.Selected.Level=1 then
          begin
            if treeview1.Selected.Count=0 then
            //添加計算機名
            getcomputername;
          end;
          if treeview1.Selected.Level=2 then
          bitbtn1.Enabled:=true
          else
          bitbtn1.Enabled:=false;
        end;
        //取得計算機名
        procedure Tfm_netlist.getcomputername;
        var
          NetResource: TNetResource;
          Buf: Pointer;
          Count, BufSize, Res: DWord;
          Ind: Integer;
          lphEnum: THandle;
          Temp: TNetResourceArray;
          groupname: string;
          my_node: Ttreenode;
          my_node_2: Ttreenode;
        begin
          screen.Cursor := crHourGlass;
          statusbar.panels[0].text := '正在列舉組名...,請稍侯';
          statusbar.refresh;
          my_node := treeview1.Selected;
          groupname := treeview1.Selected.Text;
          FillChar(NetResource, SizeOf(NetResource), 0); //初始化網絡層次信息
          NetResource.lpRemoteName := @GroupName[1]; //指定工作組名稱
          NetResource.dwDisplayType := RESOURCEDISPLAYTYPE_SERVER; //類型為服務器(工作組)
          NetResource.dwUsage := RESOURCEUSAGE_CONTAINER;
          NetResource.dwScope := RESOURCETYPE_DISK; //列舉文件資源信息
          //獲取指定工作組的網絡資源句柄
          Res := WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
            RESOURCEUSAGE_CONTAINER, @NetResource, lphEnum);
          if Res <> NO_ERROR then Exit; //執行失敗
          while True do //列舉指定工作組的網絡資源
          begin
            Count := $FFFFFFFF; //不限資源數目
            BufSize := 8192; //緩沖區大小設置為8K
            GetMem(Buf, BufSize); //申請內存,用于獲取工作組信息
           //獲取計算機名稱
            Res := WNetEnumResource(lphEnum, Count, Pointer(Buf), BufSize);
            if Res = ERROR_NO_MORE_ITEMS then break; //資源列舉完畢
            if (Res <> NO_ERROR) then Exit; //執行失敗
            Temp := TNetResourceArray(Buf);
            for Ind := 0 to Count - 1 do //列舉工作組的計算機名稱
            begin
              //獲取工作組的計算機名稱,+2表示刪除"\\",如
              my_node_2 := treeview1.Items.AddChild(my_node, Temp^.lpRemoteName + 2);
              my_node_2.imageindex := 2;
              Inc(Temp);
            end;
          end;
          Res := WNetCloseEnum(lphEnum); //關閉一次列舉
          if Res <> NO_ERROR then exit; //執行失敗
          FreeMem(Buf);
          screen.Cursor := crDefault;
          statusbar.panels[0].text := '';
          statusbar.refresh;
        end;

        //獲取組名
        procedure Tfm_NetList.GetGroupName;
        var
          NetResource: TNetResource;
          Buf: Pointer;
          Count, BufSize, Res: DWORD;
          lphEnum: THandle;
          p: TNetResourceArray;
          i, j: SmallInt;
          NetworkTypeList: TList;
          my_node_1: Ttreenode;
        begin
          statusbar.panels[0].text := '正在列舉域名...,請稍侯';
          statusbar.refresh;
          screen.Cursor := crHourGlass;
          NetworkTypeList := TList.Create;
          //獲取整個網絡中的文件資源的句柄,lphEnum為返回名柄
          Res := WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
            RESOURCEUSAGE_CONTAINER, nil, lphEnum);
          if Res <> NO_ERROR then exit; //執行失敗
          //獲取整個網絡中的網絡類型信息
          Count := $FFFFFFFF; //不限資源數目
          BufSize := 8192; //緩沖區大小設置為8K
          GetMem(Buf, BufSize); //申請內存,用于獲取工作組信息
          Res := WNetEnumResource(lphEnum, Count, Pointer(Buf), BufSize);
          if (Res = ERROR_NO_MORE_ITEMS) //資源列舉完畢
            or (Res <> NO_ERROR) //執行失敗
            then Exit;
          P := TNetResourceArray(Buf);
          for I := 0 to Count - 1 do //記錄各個網絡類型的信息
          begin
            NetworkTypeList.Add(p);
            Inc(P);
          end;
          //WNetCloseEnum關閉一個列舉句柄
          Res := WNetCloseEnum(lphEnum); //關閉一次列舉
          if Res <> NO_ERROR then exit;
          for J := 0 to NetworkTypeList.Count - 1 do //列出各個網絡類型中的所有工作組名稱
          begin //列出一個網絡類型中的所有工作組名稱
            NetResource := TNetResource(NetworkTypeList.Items[J]^); //網絡類型信息
          //獲取某個網絡類型的文件資源的句柄,NetResource為網絡類型信息,lphEnum為返回名柄
            Res := WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
              RESOURCEUSAGE_CONTAINER, @NetResource, lphEnum);
            if Res <> NO_ERROR then break; //執行失敗

            while true do //列舉一個網絡類型的所有工作組的信息
            begin
              Count := $FFFFFFFF; //不限資源數目
              BufSize :=8192; //緩沖區大小設置為8K
              GetMem(Buf, BufSize); //申請內存,用于獲取工作組信息
                      //獲取一個網絡類型的文件資源信息,
              Res := WNetEnumResource(lphEnum, Count, Pointer(Buf), BufSize);
              if (Res = ERROR_NO_MORE_ITEMS) //資源列舉完畢
                or (Res <> NO_ERROR) //執行失敗
                then break;
              P := TNetResourceArray(Buf);
              for I := 0 to Count - 1 do //列舉各個工作組的信息
              begin
                my_node_1 := treeview1.Items.addchild(node, StrPAS(P^.lpRemoteName)); //取得一個工作組的名稱
                my_node_1.imageindex := 1;
                Inc(P);
              end;
            end;
            Res := WNetCloseEnum(lphEnum); //關閉一次列舉
            if Res <> NO_ERROR then break; //執行失敗
          end;
          FreeMem(Buf);
          NetworkTypeList.Destroy;
          screen.Cursor := crDefault;
          statusbar.panels[0].text := '';
          statusbar.refresh;
        end;
        procedure TFm_netlist.BitBtn1Click(Sender: TObject);
        begin
          aComputerName := treeview1.Selected.Text;
          close;
        end;
        end.
         在上面的程序清單中,首先定義了NetExecute方法,它根據傳遞進來的TFormClass參數值TformNet,打開“列舉網絡資源”窗口,用戶可以在此窗口中選擇想要連接的運行應用服務器程序的計算機。NetExecute方法將返回選中的計算機主機名。
         在程序清單中,還自定義了GetGroupName和GetComputerName這兩個非常重要的過程,其中GetGroupName方法用于獲取網絡中所有的工作組名稱,并將工作組名添加到目錄樹的第二級目錄中;GetComputerName方法則根據工作組的名稱窮舉工作組下的計算機,并將這些計算機添加到目錄樹的第三級目錄中。
         選擇好計算機后,單擊“確定”按鈕,系統將把選定的計算機主機名賦給aComputerName全局變量,此時在NetExecute方法中,便返回此值。
         (4) 在data單元(data.pas)中定義connect_app方法。connect_app方法用語讀取注冊表中配置應用服務器的信息并測試連接,如果沒有連接上應用程序服務器將從新彈出配置窗口。這個接口方法在程序主窗體創建時被調用,用以嘗試連接應用服務器。
         ConnectAppServ方法在interface中的具體定義為:
        function TFm_data.connect_app: boolean; //判斷是否連接上了應用服務器
        var
          vs_Host, vs_Address, vs_Port: string;
          reg: TRegistry;
        begin
          Result := True;
          reg := Tregistry.create;
          Reg.RootKey := HKEY_LOCAL_MACHINE;
          socket.Connected := false;
          //讀取注冊表配置的應用服務器信息
          if Reg.OpenKey('\Software\pz', False) then  //如果注冊表有信息
          begin
            vs_Host := reg.ReadString('Host');
            vs_Address := reg.ReadString('ip');
            vs_Port := reg.readstring('Port');
            try
              //測試連接
                socket.Address := vs_Address;
                socket.Host := vs_Host;
                socket.Port := strtoint(vs_Port);
                socket.Connected := true;
              reg.closekey;
            except //未連接上,彈出配置窗口
              reg.closekey;
                try
                    fm_SerConfig := Tfm_serconfig.create(self);
                    fm_SerConfig.showmodal;
                finally
                    fm_SerConfig.free;
                end;
            end;
          end
          else      //如果沒有信息 彈出配置窗口
          begin
             try
                    fm_SerConfig := Tfm_SerConfig.create(self);
                    fm_SerConfig.showmodal;
                finally
                    fm_SerConfig.free;
                end;
          end;
        end;
         在此過程里,將主要讀取鍵為“HKEY_LOCAL_MACHINE\SOFTWARE\PZ”目錄下的應用服務器主機名,應用服務器IP地址和端口號的值,然后將這些值賦給主窗體的SocketConnection組件以測試連接。如果連接成功就返回True值,如果連接失敗,將彈出“連接設置“窗口,用戶需要從新輸入應用服務器主機名,應用服務器IP地址和端口號。如果仍然連接失敗,就返回False值,表示連接失敗。
         (5) 動態連接設置的最后一個步驟就是在主窗體被創建時,調用第4步中自定義的Imyserver_autho方法,判斷應用程序是否連接上了應用服務器。如果連接成功,將進入應用程序;如果連接失敗,將退出應用程序。
         至此,動態連接應用服務器就做完了。

        4.6  圖書管理功能的實現

         圖書管理系統需要滿足來自三方面的需求,這三個方面分別是圖書借閱者、圖書館工作人員和圖書館管理人員。圖書借閱者的需求是查詢圖書館所存的圖書、個人借閱情況及個人信息的修改;圖書館工作人員對圖書借閱者的借閱及還書要求進行操作,同時形成借書或還書報表給借閱者查看確認;圖書館管理人員的功能最為復雜,包括對工作人員、圖書借閱者、圖書進行管理和維護,及系統狀態的查看、維護并生成催還圖書報表。    圖書借閱者可直接查看圖書館圖書情況,如果圖書借閱者根據本人借書證號和密碼登錄系統,還可以進行本人借書情況的查詢和維護部分個人信息。一般情況下,圖書借閱者只應該查詢和維護本人的借書情況和個人信息,若查詢和維護其他借閱者的借書情況和個人信息,就要知道其他圖書借閱者的借書證號和密碼。這些是很難得到的,特別是密碼,所以不但滿足了圖書借閱者的要求,還保護了圖書借閱者的個人隱私。    圖書館工作人員有修改圖書借閱者借書和還書記錄的權限,所以需對工作人員登陸本模塊進行更多的考慮。在此模塊中,圖書館工作人員可以為圖書借閱者加入借書記錄或是還書記錄,并打印生成相應的報表給用戶查看和確認。    在本系統中由于沒有打印機設備供試驗,所以沒有制作打印模塊。本系統提供的功能有    1. 設計不同用戶的操作權限和登陸方法    2. 對所有用戶開放的圖書查詢    3. 借閱者維護借閱者個人部分信息    4. 借閱者查看個人借閱情況信息    5. 維護借閱者個人密碼     6. 查詢及統計各種信息    7 . 維護圖書信息     8. 維護借閱者信息     9. 對借閱過期的圖書進行通知
         
         第五部分 畢業設計心得體會及結論
         
         在蘇綠園老師的指導下。本次畢業設計,就要畫上一個句號了。可是,對我來說,這次設計的本身所產生的影響,還遠遠沒有結束,我從本次畢業設計中學到了許多課本上沒有的知識。從設計任務書的下達到今天基本實現任務書中的設計要求,時間已整整過去了兩個月。在這兩個月中。通過自己的學習和努力;通過各位老師的指導和教育,使我不僅僅在知識水平和解決實際問題的能力上有了很大的提高。還從思想的深處體會到,要把自己的所學變成現實時所將面對的種種難題。
         由于我平時的課程理論知識學的還可以,我總是認為自己的知識水平已經能處理許多的現實問題了。而當自己真正的深入到設計實踐當中,深入到問題當中時。我竟然發現自己無從下手,我開始懷疑我是否真正的學到了知識。也只有到了那個時候,我才真正體會到學會運用自己的能力與知識是何等的重要,知識是在課堂上,老師教授的,在書本中學到的,實踐則是要自己動手,自己去做才能掌握。
         在老師們的關心和幫助下,我漸漸的開始了設計。根據老師的建議,我找來了數據庫設計與建設的相關書籍和資料,從最基本的問題入手開始一個個的解決我心中的疑惑。 這是一個漫長的學習過程。隨著時間的推移,我開始慢慢的掌握了設計時所需要的知識。我也終于明白了大學三年學習的意義和作用。扎實的基本功和良好的學習習慣,能使自己在學習新知識有更深刻的認識力和更快的領會力。
         同時老師對畢業設計的重視也是我能完成設計的一個重要條件。為了保證我們畢業設計的正常進行,學院抽調了優秀的老師指導我們進行畢業設計,提供良好的設備給我們,在軟硬件上支持我們進行畢業設計,并且不時地詢問我們畢業設計的進展情況。為我們這次設計的正常開展提供了必要的物質基礎。
        關于本次設計的命題,我的設計只能提供其基本的功能。還有許多的設想由于時間和自身和因素無法得以實現,這不能不說是本次設計的遺憾之處。不過,至少它已經啟發了自己的思維,提高了我的動手能力,這是我在課本中學不到的。它為我們在以后的工作崗位上發揮自己的才能奠定了堅實的基礎。
                      第六部分 附錄
        6.1參考資料
        《軟件工程》     陸惠恩 陸培恩 主編        電子工業出版社  2004年
        《delphi高級程序員認證教材》  北京科海培訓中心       Delphi主講教師:謝新華
        《SQL Server2000數據庫及應用基礎》徐人鳳 曾建華 主編  高等教育現版社 2004年
        《Delphi 6深度編程及其應用開發》  李存斌 汪兵 編著  中國水利水電出版社   2002年

        《&.doc》
        将本文的Word文档下载到电脑,方便收藏和打印
        推荐度:
        点击下载文档

        【分布式多層數據庫系統的應用(一)】相關文章:

        分布式發電系統的應用及前景03-18

        關于分布式發電系統的應用及前景11-23

        分布式對象技術及其在Web上的應用03-18

        PowerBuilder的分布式計算技術及其應用03-18

        用RMI開發基于Java的企業分布式應用03-19

        談分布式防火墻技術及其應用03-18

        多層螺旋CT不同成像方法在腦血管成像中的應用03-16

        多層螺旋CT灌注成像在腦腫瘤中的應用研究03-18

        分布式網絡化研究中心及其在靈敏制造中的應用03-22

        在线咨询
        国产高潮无套免费视频_久久九九兔免费精品6_99精品热6080YY久久_国产91久久久久久无码
      3. <sub id="h4knl"><ol id="h4knl"></ol></sub>
        <sup id="h4knl"></sup>
          <sub id="h4knl"></sub>

          <sub id="h4knl"><ol id="h4knl"><em id="h4knl"></em></ol></sub><s id="h4knl"></s>
          1. <strong id="h4knl"></strong>

          2. 曰韩国产精品久久久久久 | 日韩AV不卡一区二区 | 亚洲特级免费观看中文字幕 | 中文字幕乱码免费视频 | 五月丁香伊人青青草原网 | 亚洲欧美日韩αv在线电影 亚洲欧美日韩国产一区二区三区精品 |

            分布式多層數據庫系統的應用(一)

            摘要
             
            本次畢業設計任務是通過開發一個分布式多層數據庫圖書管理系統,學習用delphi開發分布式多層數據庫系統。采用Delphi6.0和MS Server2000等軟件為開發工具;通過對計算機硬件和軟件解決方案的論證;對應用領域進行調查分析;參考各種資料和進行數據庫編程實踐。在指導老師的幫助下,已經基本上成功地實現了設計任務書的要求。使得設計的數據庫系統能夠實現一般數據庫的管理。我們研究了數據庫的查詢優化問題。

             第一部分  引 言
             
            1.1任務或問題:
             開發一個分布式多層圖書管理系統,可以實現動態的連接應用程序服務器,只要對配置文件進行配置,就可以像網上鄰居一樣選擇所要連接的應用程序服務器。并提供借書還書,圖書和期刊檢索等查詢功能。
            1.2實際背景:
             隨著社會發展,人類的生產、生活越來越離不開信息。誰擁有了更多更有效的信息,誰就將在競爭中處于有利地位。信息產業正在成為一個國家的支柱。數據作為信息的載體,其管理工具數據庫對于信息技術的重要性,正日益得到人們的重視。只有擁有了先進的數據庫技術,才能有效地管理好浩如煙海的數據,并從中提取出對自己有用的信息來加以利用。
             90年代,人們開發MIS系統大都采用客戶機/服務器結構,客戶機/服務器結構既是硬件結構又是軟件結構。即數據放在服務器上,程序在客戶機上。進行數據訪問時,由客戶機提出請求(一般是SQL語句),服務器執行并給出結果。客戶機/服務器對于優化了網絡,提高了系統的利用率。客戶機/服務器體系結構的發展經歷了從二級體系結構模式到三級體系結構模式。
            1.3我的工作
                設計系統框架,設計數據庫,編寫代碼,測試數據等。
            1.4特色(創新)
             可以像網上鄰居一樣選擇所要連接的應用程序服務器。
             
             第二部分 畢業設計課題
             
            設計課題
             漳大圖書館管理系統
            設計時間
             二○○四年10月至二○○四年12月
            設計人員及任務
             王東凱  動態連接服務器模塊的實現及幫助件功能模塊的實現
             王開斌  分布式多層數據模塊的實現
             王杰林  圖書管理功能模塊的實現
             陳慶輝  sqlserver 2000數據庫的分析及表的設計
            指導老師
             蘇綠園
            設計內容
             利用Delphi6.0和MS Server2000為主要開發工具,以WindowsXP為開發平臺。設計出分布式多層應用的圖書館管理系統。可以實現動態的連接應用程序服務器,只要對配置文件進行配置,就可以像網上鄰居一樣選擇所要連接的應用程序服務器。實現與應用程序服務器快速而準確的連接。
             
             第三部分 系統方案論證
             
            3.1軟件定義 
                數據庫設計所要的解決的問題是:對于一個給定的應用領域,設計優化的數據庫邏輯和物理結構,使之滿足用戶的信息管理要求和數據操作要求,有效地支持各種應用系統的開發和運行。數據庫設計的目標是為用戶和各種應用系統提供一個高效的運行環境。而數據庫的設計可以視為如下的優化問題。
            計算機的軟硬件環境;
            數據庫管理系統的能力;
            用戶的操作要求與信息要求;
            完整性和安全性約束。
            3.2 體系結構規劃
             本次設計的系統采用 三層″客戶/服務器″體系,為了便于理解,我們先從二層″客戶/服務器″體系結構來闡述:
             客戶/服務器是在網絡基礎上,以數據庫管理為后援,以計算機為網上工作站的一種系統結構。該結構的關鍵在把網絡環境上的數據庫存取和應用程序一分為二,分別由網上的數據庫服務器和網上客戶來執行。雖然本系統客戶/服務器是建立在LAN的基礎上,但它比以往的文件服務系統有了很大的改進。首先,它消除了不必要的網絡傳輸負擔;其次,它可以使作為數據庫服務器的計算機被高度優化,以適應數據處理的需要。客戶/服務器已經能夠應用于復雜的網絡上,并使之能夠更有效地進行選擇、檢索、索引排序等數據處理。作為一種高級的分布式計算機環境、客戶/服務器有足夠的能力把處理后的結果(不是整個文件)通過網絡傳輸出去,并根據用戶需求靈活地配置各種大、中、小型計算機系統。
            3.3 系統設計
            數據流圖
                         
                         管理要求                           查詢要求

                          管理結果                          查詢結果


                                                (頂層數據流圖)
            數據庫設計過程
             數據庫的設計過程如下圖所示。在數據庫設計過程中,需求分析和概念設計可以獨立于任何數據庫管理系統進行。邏輯設計和物理設計與具體的數據庫管理系統密切相關。由于需求分析比較重要。我們在設計的時候,花了比較多的時間。在獲得這些資料之后,進行分析。從中提取有用的部分。分析各種用戶的權限。
                                      需求分析說明書
                 圖:數據庫設計過程
             
             第四部分 畢業設計內容
             
            4.1分布式多層數據庫開發簡介
             Delphi提出的MIDAS(Multi-Tier distributed Application Services Suite多層分布式應用服務器組),是把原來Two- Tier數據連接放到了服務器端的COM組件上,客戶端只剩下了執行文件和MIDAS.DLL,前臺和服務器上的COM組件,通過DCOM機制互相溝通。
             這個多的一層,稱為應用程序服務器(Application Server),或者稱為中間件。整個工作機制見下圖:
             
             這種多層分布式工作機制,主要基于這樣幾點考慮:
            減少客戶機的維護量,因為前臺程序比較簡單;
             把企業邏輯封裝在通用的中間件應用服務器中,不同的客戶都可以共享同一個中間層(包括Web),而不必每個客戶都單獨實現企業規則,避免了重復開發和維護的麻煩。由于客戶程序相當瘦(這就是現在流行的瘦客戶機概念),無論是開發還是發布,都變得簡單了。
            便于升級,當中間件升級的時候,客戶程序可能不需要變化;
            實現了分布式數據處理,把一個應用程序分布在幾臺機器上運行,可以提高應用程序的性能,也可以把敏感部分封裝在中間件,為不同的用戶設置不同的訪問權限,增強了安全性。
            減少直接連接數據庫的用戶數目,減少費用。
             在Delphi 6.0上,在原來的MIDAS基礎上,發展了DataSnap技術,在很多細節方面,它提供了原來MIDAS所沒有的許多功能,使用上更加方便了。
             DataSnap主要提供客戶端和中間件之間的通信,不但支持COM+技術也支持TCP/IP或者CORBA,它們使用類似的界面和方法,其結果由程序自動完成,這就大大擴充了它的應用范圍。
             必須要提醒的是,前臺機器上除了應用程序以外,還必須把一個MIDAS.DLL文件復值到前臺機器上,這個文件在服務器的WINNT\System32目錄下。
             
            4.2 服務器端程序的建立

                服務器端程序實際上是個COM 工程,它本身連接數據源,再通過接口與客戶端聯系,這個COM 工程必須注冊在服務器上。
             首先建立一個空白的工程,在工程里放置一個Adoconnection組件。然后再建一個遠程數據模塊file -> New -> Other -> Multitier -> Remote Data Module(遠程數據模塊)。   Coclass Name : libserver ,Instancing  :執行模式,大部分用Multiple Instance(多重實例),Threading Model:線程模式,建議用Apartment(單元),產生一個窗口,在這個窗口里,可以放入數據控件。
                在Viwe -> Type Libray 中,我們可以看到這個COM 的一些特性。我們也可以記下系統提供的GUID,以備后來使用。加入一個ADOTable,并設置其指向一個數據庫。再設置一個DataSetProvider(在DataAccess頁)指向ADOTable,這就完成了服務器端的程序設計。
            保存,編譯,注冊(注意,只要運行就自動在本機注冊了)。

            4.3 客戶端程序的建立

                在Two-Tier模式中,客戶端(Client)程序是直接和服務器的數據源相連的,而Multi-Tier模式,多個客戶端連接的是一個應用程序服務器,因為收費是按客戶端數計算的,所以,數據庫的使用費用比較低。
                1)建立一個普通的工程。   
             2)放置一個TDCOMConnrction控件(在Datasnap頁),屬性:在本機注冊時,可直接設置以下屬性:ServerName:應用程序服務器注冊名(server.libserver)   ,Connected=true。這時你可以看到服務器端的COM 程序被激活了。如果在網絡上調試,需要給出服務器名:ComputerName:服務器名(自動給出網上鄰居)注意: ServerGUID的GUID值是自動給出的。
             3)放置一個TClientDataSet控件(在Data Access頁),屬性RemoteServer= DCOMConnrction1,ProviderName:=DataSetProvider1(服務器端將被激活),Active=true (激活后將能正常連接)
                4)放置TDataSource,屬性:Dataset:指向cdsCustomer。
             這樣一個客戶端程序就建立好了,其余猶如普通的數據庫設計。
             
            4.4  客戶端實現SQL 查詢

                由于在客戶端不存在TQuery控件,似乎客戶服務器模式是無法做SQL查詢的。但是,Delphi很好的解決了這個問題。事實上,只要客戶端連接上服務端應用程序,客戶端的TClientDataSet就包含了一個名字為Provider的屬性,對應到服務器端DataSetProvider的所有默認屬性和方法,其中DataSetProvider有一個Options屬性,只要讓其中的poAllowCommandText=true, 那么,DataSetProvider的poAllowCommandText就可以接受前臺來的SQL 命令,并傳送給TQuery。
                可以看出,真正傳遞數據的是DataSetProvider的接口,所以,用這個接口搭建傳遞SQL 的橋梁是必需的。客戶端進行SQL 查詢的方法是:
                  ClientDataSet.Close;
                  ClientDataSet.CommandText := 'SQL語句';
             ClientDataSet.Open;
             
            4.5 動態連接應用程序服務器的實現
             
              客戶端程序在運行時,需要連接應用服務器程序以取得服務。但是,在系統實際應用的時候,運行應用服務器程序的計算機是經常改變的,因此在客戶端程序啟動時,應該先找到運行應用服務器程序的計算機的設置。動態連接應用服務器的流程類似于12.3節的動態數據庫連接,動態連接應用服務器程序的流程圖14-1所示。
             掌握了動態連接應用服務器的流程,就可以具體實現它。下面就將分步驟介紹動態連接應用服務器的實現過程。
            在Delphi中新建一個窗體,將單元文件保存為connect.pas窗體的Name屬性設為fm_serconfig,Caption屬性設為”服務器配置”,運行后窗體如下圖所示。
             
             (2) 在“連接設置”窗體中,需要輸入應用服務器主機名(或者應用服務器IP地址)和應用服務器的端口號,這些配置信息將用來連接應用服務器。如果連接成功,輸入的配置信息將被寫入到注冊表中,以后程序啟動時,讀取注冊表配置信息,就可而已連接應用服務器程序了。程序的具體實現部分如程序清單如下所示。
            procedure BitBtn1Click(Sender: TObject);
            procedure Button1Click(Sender: TObject);
            private
            procedure WriteToReg(const bappHost,bappIp,aPort:string);
            { Private declarations }
            public
            { Public declarations }
            end;
            var
               fm_SerConfig: Tfm_SerConfig;  Connected: boolean= false;   //代表是否連接成功
             implementation
             uses netlist, data;
             {$R *.dfm}
             procedure Tfm_SerConfig.BitBtn1Click(Sender: TObject);
             begin
                if ((Edt_host.Text='') or (Edt_host.Text=null))
                   and((Edt_ip.Text='') or (Edt_host.Text=null)) then
                begin
                application.MessageBox('請輸入服務器和IP','輸入錯誤',
                                  mb_iconinformation + mb_defbutton1);
                exit;
                end;
                try
                  strtoint(edt_Port.text);
                except
                   Application.MessageBox('請輸入正確的端口號', '輸入錯誤..', mb_iconinformation + mb_defbutton1);
                  exit;
                end;
                statusbar1.Panels[0].Text:='正在連接服務器,pleale wait';
                statusbar1.Refresh;
                screen.Cursor:=crHourGlass;
                fm_data.Socket.Connected:=false;
                fm_data.Socket.Host:=edt_host.Text;
                fm_data.Socket.Address:=edt_ip.Text;
                fm_data.Socket.Port:=strtoint(edt_port.Text);
                try
                  screen.Cursor:=crdefault;
                  fm_data.Socket.Connected:=true;
                  application.MessageBox('連接成功','圖書管理系統', mb_iconinformation + mb_defbutton1);
                  connected:=true;
                except
                  screen.Cursor:=crdefault;
                  application.MessageBox('連接失敗','圖書管理系統',mb_iconinformation+mb_defbutton1);
                  connected:=false;
                end;
             //連接成功向注冊表里寫入應用服務器配置信息
               WriteToReg(edt_Host.Text, edt_IP.Text, edt_Port.Text);
               close;
             end;
             //利用可視化窗體來選擇計算機
             procedure Tfm_SerConfig.Button1Click(Sender: TObject);
             begin
             edt_ip.Clear;
             edt_host.Text:=   NetExecute(TFm_NetList);
             end;
             //把信息寫入注冊表
             procedure Tfm_SerConfig.WriteToReg(const bappHost,bappIp,aPort:string);
             var
             reg:Tregistry;
             begin
               reg:=Tregistry.Create;
               reg.RootKey:=HKEY_LOCAL_MACHINE;
               if not reg.OpenKey('\Software\pz',false) then //如果可以創建目錄
               begin
               reg.CreateKey('\Software\pz');
               reg.OpenKey('\Software\pz',false);
               end;
               reg.WriteString('host',bapphost);
               reg.WriteString('ip',bappip);
               reg.WriteString('port',aport);
               reg.Free;
             end;
             end.
             打開“連接設置”配置窗口,在打開窗體之前,函數已經將布爾變量Connected設為False,而在窗體被關閉之后,將返回Connected變量的值,根據布爾變量Connected的值可以判斷是否已經連接上應用服務器。
             (3) 在連接設置主窗口中,我們為應用服務器名提供了輔助錄入的方法,點擊應用服務器名編輯框右邊的省略號按鈕(Button1),將彈出一個瀏覽局域網計算機的對話框,以方便用戶選擇應用服務器所在的計算機。在此我們調用了一個NetExecute方法,它將返回用戶選中的計算機的主機名。這個方法是如何實現的呢?下面將介紹NetExecute方法的實現過程。
             在Delphi中新建一個窗體,將窗體單元文件保存為netlist .pas,窗體的Name屬性設為Fm_netlist。運行后窗體如下圖所示。
             
             在列舉網絡資源窗體中,將按照工作組以樹型目錄的形式顯示局域網中的計算機。程序的具體實現部分如下所示。
            procedure FormActivate(Sender: TObject);
            procedure TreeView1Click(Sender: TObject);
            procedure BitBtn1Click(Sender: TObject);
            private
              procedure getcomputername;
              procedure getgroupname;
              { Private declarations }
            public
              { Public declarations }
            end;
            function NetExecute(aFormClass: TFormClass): string;
            var
              fm_NetList: Tfm_NetList;
              node: Ttreenode;
              aComputerName : string;//全局變量,存儲選中的主機名
            implementation
            {$R *.dfm}
            //打開窗體,并返回選定的計算機
            function NetExecute(aFormClass: TFormClass): string;
            begin
              aComputerName := '';
              with aFormClass.Create(Application) do
              begin
                try
                  showModal;
                finally
                  free;
                end;
                result := aComputerName;
              end;
            end;

            procedure TFm_netlist.FormActivate(Sender: TObject);
            begin
            node:=treeview1.items.add(Treeview1.topitem, '整個網絡');
            node.imageindex:=0;
            treeview1.setfocus;
            end;

            procedure TFm_netlist.TreeView1Click(Sender: TObject);
            begin
              if treeview1.Selected.Level=0 then
              begin
                if treeview1.Selected.Count=0 then
                //添加工作組名
                getgroupname();
              end;
              if treeview1.Selected.Level=1 then
              begin
                if treeview1.Selected.Count=0 then
                //添加計算機名
                getcomputername;
              end;
              if treeview1.Selected.Level=2 then
              bitbtn1.Enabled:=true
              else
              bitbtn1.Enabled:=false;
            end;
            //取得計算機名
            procedure Tfm_netlist.getcomputername;
            var
              NetResource: TNetResource;
              Buf: Pointer;
              Count, BufSize, Res: DWord;
              Ind: Integer;
              lphEnum: THandle;
              Temp: TNetResourceArray;
              groupname: string;
              my_node: Ttreenode;
              my_node_2: Ttreenode;
            begin
              screen.Cursor := crHourGlass;
              statusbar.panels[0].text := '正在列舉組名...,請稍侯';
              statusbar.refresh;
              my_node := treeview1.Selected;
              groupname := treeview1.Selected.Text;
              FillChar(NetResource, SizeOf(NetResource), 0); //初始化網絡層次信息
              NetResource.lpRemoteName := @GroupName[1]; //指定工作組名稱
              NetResource.dwDisplayType := RESOURCEDISPLAYTYPE_SERVER; //類型為服務器(工作組)
              NetResource.dwUsage := RESOURCEUSAGE_CONTAINER;
              NetResource.dwScope := RESOURCETYPE_DISK; //列舉文件資源信息
              //獲取指定工作組的網絡資源句柄
              Res := WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
                RESOURCEUSAGE_CONTAINER, @NetResource, lphEnum);
              if Res <> NO_ERROR then Exit; //執行失敗
              while True do //列舉指定工作組的網絡資源
              begin
                Count := $FFFFFFFF; //不限資源數目
                BufSize := 8192; //緩沖區大小設置為8K
                GetMem(Buf, BufSize); //申請內存,用于獲取工作組信息
               //獲取計算機名稱
                Res := WNetEnumResource(lphEnum, Count, Pointer(Buf), BufSize);
                if Res = ERROR_NO_MORE_ITEMS then break; //資源列舉完畢
                if (Res <> NO_ERROR) then Exit; //執行失敗
                Temp := TNetResourceArray(Buf);
                for Ind := 0 to Count - 1 do //列舉工作組的計算機名稱
                begin
                  //獲取工作組的計算機名稱,+2表示刪除"\\",如
                  my_node_2 := treeview1.Items.AddChild(my_node, Temp^.lpRemoteName + 2);
                  my_node_2.imageindex := 2;
                  Inc(Temp);
                end;
              end;
              Res := WNetCloseEnum(lphEnum); //關閉一次列舉
              if Res <> NO_ERROR then exit; //執行失敗
              FreeMem(Buf);
              screen.Cursor := crDefault;
              statusbar.panels[0].text := '';
              statusbar.refresh;
            end;

            //獲取組名
            procedure Tfm_NetList.GetGroupName;
            var
              NetResource: TNetResource;
              Buf: Pointer;
              Count, BufSize, Res: DWORD;
              lphEnum: THandle;
              p: TNetResourceArray;
              i, j: SmallInt;
              NetworkTypeList: TList;
              my_node_1: Ttreenode;
            begin
              statusbar.panels[0].text := '正在列舉域名...,請稍侯';
              statusbar.refresh;
              screen.Cursor := crHourGlass;
              NetworkTypeList := TList.Create;
              //獲取整個網絡中的文件資源的句柄,lphEnum為返回名柄
              Res := WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
                RESOURCEUSAGE_CONTAINER, nil, lphEnum);
              if Res <> NO_ERROR then exit; //執行失敗
              //獲取整個網絡中的網絡類型信息
              Count := $FFFFFFFF; //不限資源數目
              BufSize := 8192; //緩沖區大小設置為8K
              GetMem(Buf, BufSize); //申請內存,用于獲取工作組信息
              Res := WNetEnumResource(lphEnum, Count, Pointer(Buf), BufSize);
              if (Res = ERROR_NO_MORE_ITEMS) //資源列舉完畢
                or (Res <> NO_ERROR) //執行失敗
                then Exit;
              P := TNetResourceArray(Buf);
              for I := 0 to Count - 1 do //記錄各個網絡類型的信息
              begin
                NetworkTypeList.Add(p);
                Inc(P);
              end;
              //WNetCloseEnum關閉一個列舉句柄
              Res := WNetCloseEnum(lphEnum); //關閉一次列舉
              if Res <> NO_ERROR then exit;
              for J := 0 to NetworkTypeList.Count - 1 do //列出各個網絡類型中的所有工作組名稱
              begin //列出一個網絡類型中的所有工作組名稱
                NetResource := TNetResource(NetworkTypeList.Items[J]^); //網絡類型信息
              //獲取某個網絡類型的文件資源的句柄,NetResource為網絡類型信息,lphEnum為返回名柄
                Res := WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
                  RESOURCEUSAGE_CONTAINER, @NetResource, lphEnum);
                if Res <> NO_ERROR then break; //執行失敗

                while true do //列舉一個網絡類型的所有工作組的信息
                begin
                  Count := $FFFFFFFF; //不限資源數目
                  BufSize :=8192; //緩沖區大小設置為8K
                  GetMem(Buf, BufSize); //申請內存,用于獲取工作組信息
                          //獲取一個網絡類型的文件資源信息,
                  Res := WNetEnumResource(lphEnum, Count, Pointer(Buf), BufSize);
                  if (Res = ERROR_NO_MORE_ITEMS) //資源列舉完畢
                    or (Res <> NO_ERROR) //執行失敗
                    then break;
                  P := TNetResourceArray(Buf);
                  for I := 0 to Count - 1 do //列舉各個工作組的信息
                  begin
                    my_node_1 := treeview1.Items.addchild(node, StrPAS(P^.lpRemoteName)); //取得一個工作組的名稱
                    my_node_1.imageindex := 1;
                    Inc(P);
                  end;
                end;
                Res := WNetCloseEnum(lphEnum); //關閉一次列舉
                if Res <> NO_ERROR then break; //執行失敗
              end;
              FreeMem(Buf);
              NetworkTypeList.Destroy;
              screen.Cursor := crDefault;
              statusbar.panels[0].text := '';
              statusbar.refresh;
            end;
            procedure TFm_netlist.BitBtn1Click(Sender: TObject);
            begin
              aComputerName := treeview1.Selected.Text;
              close;
            end;
            end.
             在上面的程序清單中,首先定義了NetExecute方法,它根據傳遞進來的TFormClass參數值TformNet,打開“列舉網絡資源”窗口,用戶可以在此窗口中選擇想要連接的運行應用服務器程序的計算機。NetExecute方法將返回選中的計算機主機名。
             在程序清單中,還自定義了GetGroupName和GetComputerName這兩個非常重要的過程,其中GetGroupName方法用于獲取網絡中所有的工作組名稱,并將工作組名添加到目錄樹的第二級目錄中;GetComputerName方法則根據工作組的名稱窮舉工作組下的計算機,并將這些計算機添加到目錄樹的第三級目錄中。
             選擇好計算機后,單擊“確定”按鈕,系統將把選定的計算機主機名賦給aComputerName全局變量,此時在NetExecute方法中,便返回此值。
             (4) 在data單元(data.pas)中定義connect_app方法。connect_app方法用語讀取注冊表中配置應用服務器的信息并測試連接,如果沒有連接上應用程序服務器將從新彈出配置窗口。這個接口方法在程序主窗體創建時被調用,用以嘗試連接應用服務器。
             ConnectAppServ方法在interface中的具體定義為:
            function TFm_data.connect_app: boolean; //判斷是否連接上了應用服務器
            var
              vs_Host, vs_Address, vs_Port: string;
              reg: TRegistry;
            begin
              Result := True;
              reg := Tregistry.create;
              Reg.RootKey := HKEY_LOCAL_MACHINE;
              socket.Connected := false;
              //讀取注冊表配置的應用服務器信息
              if Reg.OpenKey('\Software\pz', False) then  //如果注冊表有信息
              begin
                vs_Host := reg.ReadString('Host');
                vs_Address := reg.ReadString('ip');
                vs_Port := reg.readstring('Port');
                try
                  //測試連接
                    socket.Address := vs_Address;
                    socket.Host := vs_Host;
                    socket.Port := strtoint(vs_Port);
                    socket.Connected := true;
                  reg.closekey;
                except //未連接上,彈出配置窗口
                  reg.closekey;
                    try
                        fm_SerConfig := Tfm_serconfig.create(self);
                        fm_SerConfig.showmodal;
                    finally
                        fm_SerConfig.free;
                    end;
                end;
              end
              else      //如果沒有信息 彈出配置窗口
              begin
                 try
                        fm_SerConfig := Tfm_SerConfig.create(self);
                        fm_SerConfig.showmodal;
                    finally
                        fm_SerConfig.free;
                    end;
              end;
            end;
             在此過程里,將主要讀取鍵為“HKEY_LOCAL_MACHINE\SOFTWARE\PZ”目錄下的應用服務器主機名,應用服務器IP地址和端口號的值,然后將這些值賦給主窗體的SocketConnection組件以測試連接。如果連接成功就返回True值,如果連接失敗,將彈出“連接設置“窗口,用戶需要從新輸入應用服務器主機名,應用服務器IP地址和端口號。如果仍然連接失敗,就返回False值,表示連接失敗。
             (5) 動態連接設置的最后一個步驟就是在主窗體被創建時,調用第4步中自定義的Imyserver_autho方法,判斷應用程序是否連接上了應用服務器。如果連接成功,將進入應用程序;如果連接失敗,將退出應用程序。
             至此,動態連接應用服務器就做完了。

            4.6  圖書管理功能的實現

             圖書管理系統需要滿足來自三方面的需求,這三個方面分別是圖書借閱者、圖書館工作人員和圖書館管理人員。圖書借閱者的需求是查詢圖書館所存的圖書、個人借閱情況及個人信息的修改;圖書館工作人員對圖書借閱者的借閱及還書要求進行操作,同時形成借書或還書報表給借閱者查看確認;圖書館管理人員的功能最為復雜,包括對工作人員、圖書借閱者、圖書進行管理和維護,及系統狀態的查看、維護并生成催還圖書報表。    圖書借閱者可直接查看圖書館圖書情況,如果圖書借閱者根據本人借書證號和密碼登錄系統,還可以進行本人借書情況的查詢和維護部分個人信息。一般情況下,圖書借閱者只應該查詢和維護本人的借書情況和個人信息,若查詢和維護其他借閱者的借書情況和個人信息,就要知道其他圖書借閱者的借書證號和密碼。這些是很難得到的,特別是密碼,所以不但滿足了圖書借閱者的要求,還保護了圖書借閱者的個人隱私。    圖書館工作人員有修改圖書借閱者借書和還書記錄的權限,所以需對工作人員登陸本模塊進行更多的考慮。在此模塊中,圖書館工作人員可以為圖書借閱者加入借書記錄或是還書記錄,并打印生成相應的報表給用戶查看和確認。    在本系統中由于沒有打印機設備供試驗,所以沒有制作打印模塊。本系統提供的功能有    1. 設計不同用戶的操作權限和登陸方法    2. 對所有用戶開放的圖書查詢    3. 借閱者維護借閱者個人部分信息    4. 借閱者查看個人借閱情況信息    5. 維護借閱者個人密碼     6. 查詢及統計各種信息    7 . 維護圖書信息     8. 維護借閱者信息     9. 對借閱過期的圖書進行通知
             
             第五部分 畢業設計心得體會及結論
             
             在蘇綠園老師的指導下。本次畢業設計,就要畫上一個句號了。可是,對我來說,這次設計的本身所產生的影響,還遠遠沒有結束,我從本次畢業設計中學到了許多課本上沒有的知識。從設計任務書的下達到今天基本實現任務書中的設計要求,時間已整整過去了兩個月。在這兩個月中。通過自己的學習和努力;通過各位老師的指導和教育,使我不僅僅在知識水平和解決實際問題的能力上有了很大的提高。還從思想的深處體會到,要把自己的所學變成現實時所將面對的種種難題。
             由于我平時的課程理論知識學的還可以,我總是認為自己的知識水平已經能處理許多的現實問題了。而當自己真正的深入到設計實踐當中,深入到問題當中時。我竟然發現自己無從下手,我開始懷疑我是否真正的學到了知識。也只有到了那個時候,我才真正體會到學會運用自己的能力與知識是何等的重要,知識是在課堂上,老師教授的,在書本中學到的,實踐則是要自己動手,自己去做才能掌握。
             在老師們的關心和幫助下,我漸漸的開始了設計。根據老師的建議,我找來了數據庫設計與建設的相關書籍和資料,從最基本的問題入手開始一個個的解決我心中的疑惑。 這是一個漫長的學習過程。隨著時間的推移,我開始慢慢的掌握了設計時所需要的知識。我也終于明白了大學三年學習的意義和作用。扎實的基本功和良好的學習習慣,能使自己在學習新知識有更深刻的認識力和更快的領會力。
             同時老師對畢業設計的重視也是我能完成設計的一個重要條件。為了保證我們畢業設計的正常進行,學院抽調了優秀的老師指導我們進行畢業設計,提供良好的設備給我們,在軟硬件上支持我們進行畢業設計,并且不時地詢問我們畢業設計的進展情況。為我們這次設計的正常開展提供了必要的物質基礎。
            關于本次設計的命題,我的設計只能提供其基本的功能。還有許多的設想由于時間和自身和因素無法得以實現,這不能不說是本次設計的遺憾之處。不過,至少它已經啟發了自己的思維,提高了我的動手能力,這是我在課本中學不到的。它為我們在以后的工作崗位上發揮自己的才能奠定了堅實的基礎。
                          第六部分 附錄
            6.1參考資料
            《軟件工程》     陸惠恩 陸培恩 主編        電子工業出版社  2004年
            《delphi高級程序員認證教材》  北京科海培訓中心       Delphi主講教師:謝新華
            《SQL Server2000數據庫及應用基礎》徐人鳳 曾建華 主編  高等教育現版社 2004年
            《Delphi 6深度編程及其應用開發》  李存斌 汪兵 編著  中國水利水電出版社   2002年