實戰(zhàn)案例:使用ADO和三層架構完成登錄實例課案_第1頁
實戰(zhàn)案例:使用ADO和三層架構完成登錄實例課案_第2頁
實戰(zhàn)案例:使用ADO和三層架構完成登錄實例課案_第3頁
實戰(zhàn)案例:使用ADO和三層架構完成登錄實例課案_第4頁
實戰(zhàn)案例:使用ADO和三層架構完成登錄實例課案_第5頁
已閱讀5頁,還剩18頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、實戰(zhàn)案例:使用 ADO技術和三層架構實現用戶登錄案例【案例描述】現在我們將會通過一個簡單的登錄案例體會三層架構的開發(fā)。登錄是大部分的軟件都會擁有的重要功能之一,雖然它不是在軟件設計的功能用例之內, 但它 卻是軟件不可缺少的一部分,通過登錄功能我們可以有效的阻止非授權的用戶訪 問軟件中保存的信息。首先用戶通過軟件的提示輸入用戶名和密碼,接下來軟件將會通過ADO在數據庫中使用select語句查詢對應的信息,檢測數據表中是否有滿足用戶輸入的 用戶名和密碼,并將檢測出來的結果返回到記錄集中, 軟件通過讀取記錄集中保 存的信息,檢測用戶是否可以登錄,如果可以登錄則顯示“允許登錄”的提示, 否則顯示“不允

2、許登錄”的提示。運行效果如下:【三層架構的描述】清楚了上面的需求之后我們可以使用三層架構來描述一下這個簡單的功能。首先我們從表示層出發(fā)。表示層負責提示用戶輸入用戶名和密碼, 并且接收用戶 輸入的用戶名和密碼。接下來通過調用事務層的函數 Login,通過Login的形參 將用戶名和密碼傳遞到事務層進行處理。接下來事務層將傳遞的用戶名和密碼整理到SQL語句中,并調用數據庫訪問層的函數ExcuteSelect函數將這條SQL語句傳遞到數據庫訪問層。數據庫訪問層通過ADO技術和數據庫建立連接并且執(zhí)行該 SQL語句,將數 據庫執(zhí)行出的結果通過 RecordSe對象保存起來并且返回RecordSetM象的

3、指針, 通過該指針將RecordSet對象傳遞到事務層。接下來事務層通過對該RecordSet對象進行“拆包”獲取記錄集中保存的結 果,并判斷該結果是否可以滿足允許用戶登錄的條件,如果允許則返回true,否則返回false。表示層中通過事務層的Login函數的返回值判斷用戶是否可以登錄, 如果可 以則提示“允許登錄”,否則提示“不允許登錄”在Visual Studio中生成的關系依賴圖如下:0住Uwr? aetUsi*F,4*ie KerrrPl色Ul% Kernel(具體可見工程中的體系結構圖)I PrirrtLogiH【數據結構的設計】該案例是一個非常簡單的使用用戶名和密碼設計的案例,因此

4、我們可以設計 一個用于保存某個用戶的用戶名和密碼的數據結構, 在C+中,用戶自定義的數 據結構有很多種描述方案,我們此處選擇面向對象的描述方法,使用類進行描述, 例如User類,其類圖如下:農User日特性* password : Stringusername : String-操作+ getPassWord() : String+ getUserName(): String亠 setPassWordfpassword : String)+ setUserNamefusename : String)【數據庫設計】接下來我們可以進行該項目的數據庫設計了。該數據庫我們可以命名為Test,而數據庫中

5、只有一張數據表 Loginnf。這張數據表中僅僅記錄了可以登錄軟件的用戶名和密碼。為了防止用戶名有重復,我們規(guī)定用戶名作為主鍵(作為 主鍵的列不能為空,且值要唯一)。同時為了防止非授權的用戶登錄軟件(例如 盜用密碼或者清除密碼),我們規(guī)定每個用戶的密碼文件不能夠為空。表格效果 如下圖:UserNamePasswordKeyji 呂 n gh 呂 nxinjiang_1994221NULL建立數據庫和數據表的代碼如下:create database Test - 創(chuàng)建名稱為Test的數據庫gouse Test -使用該數據庫gocreate table Loginn f -創(chuàng)建登錄信息表(Use

6、rName varchar(20) primary key,-創(chuàng)建用戶名列,為主鍵PasswordKey varchar(20) not null,-創(chuàng)建密碼列,要求該列單元格添加數據不能為空值)goin sert into Loginn f values(jia ngha nxin ,jia ng_1994221)-添加一個元組運行之后在SQL Server Management Studio的 “對象資源管理器”中可以查 看到我們所建立的數據庫Test和數據表Loginnf。如下圖:B J Test曰口表1 dbo.Login_inf 視圖田LJ同義詞S 口可編程性| |_i Servic

7、e Brokeri I存赭B LJ安鋰【第一步:從數據庫訪問層開始】接下來我們設計完成數據庫之后我們可以開始對 C+代碼的設計。首先我們 從最基本的也是最底層的數據庫訪問層開始。 由于我們所有的操作都是要通過數 據庫訪問層執(zhí)行SQL語句完成的,因此數據庫訪問層我們可以這樣描述。數據庫訪問層用于和數據庫打交道,用于將應用程序和 SQL Server數據庫 建立連接,并且執(zhí)行相應的數據操作。如果有類似于查詢的返回結果,則返回帶 有查詢結果的記錄集。在完成數據庫操作之后我們可以關閉數據庫連接。小提示:每次執(zhí)行數據庫操作都必須要先打開數據庫連接,完成操作之后,再將數據庫連接關閉。否則程序將會報錯。在了

8、解了上述的功能描述后我們可以建立一個類描述數據庫訪問層,例如DataBase聲明的代碼如下:#pragma once#ifndef DATABASE#defi ne DATABASE_H#i nclude #i nclude #in clude #in clude vconi o.h#importC:ProgramFilesCom monFilesSystemadomsado15.dllno_namespace rename(EOF,adoEOF) using n amespace std;class DataBasepublic:DataBase(_bstr_t DataBaseName);

9、DataBase(void);int Excute(_bstr_t co nst & Comma ndStri ng);/執(zhí)行非查詢的數據庫命令_RecordsetPtr & ExcuteSelect(_bstr_t co nst & Comma ndStri ng);/執(zhí)行查詢的數據庫命令void Ope n(); 打開數據庫連接void Close();/關閉數據庫連接private:_Co nn ectio nPtr MyCo nn ectio n;數據庫連接指針_RecordsetPtr Records;/數據庫記錄集指針_bstr_t Co nn ectio nStri ng;/連接

10、字符串; 一一#en difDataBase 函數:DataBase函數是該類的構造函數,通常構造函數負責一些初始化的工作。為 了能夠減少后期我們工作的麻煩,例如每次調用 DataBase類都需要獲取數據庫 字符串。為了大家能夠更好的理解數據庫的連接字符串,我們在這里不妨對數據庫的連接字符串進行一些分析。有如下的連接字符串:Provider=SQLOLEDB.1;l ntegratedSecurity=SSPI;PersistSecurityIn fo=False;I nitial Catalog=Test;Data Source=(local)其中Provider參數說明連接數據庫所使用的驅

11、動引擎,由于我們使用的是ADO技術,故此我們使用的SQLOLEDB.1驅動。我們可以通過打開.udl文件, 并且點擊“提供程序”選項卡進行選擇。如下圖:提供程序連挨高級所有選擇您蒂望連接的姒據:Mi croEoft OLH DEMi crosoft OLE DBMicrcsoft OLE DEMi croEoft OLE DEMi crosoft OLE EBPrcvi der Provi derFrovi der Prcvi derProvi tierfor Analysie Sarvi c?s 10.0 for iRdexing Servi cs for ODBC Driversfor S

12、tarchfor SQL ServerMicrcsoft OLE DE Simple FrcviderHSDataShpeOLE DB Fravidar far Microsoft Directory ServicesSQL Native ClientQL Sarwr Fativw Cli ent 10.0SQL Sarver Kative Cli ent 11.0此處我們可以看到所選擇的是“Micorosoft OLE DB Provider for SQLServer”,其含義相信大家都能夠明白吧!當然,此處我需要再次解釋一下ADO其實是對OLE DB訪問技術的又一次封裝,使得我們訪問數據

13、庫變得更加的簡 單,因此說到底ADO技術的本質其實還是OLE DB。因此我們在選擇提供程序 時應該選擇 Micorosoft OLE DB Provider,由于我們使用的數據庫為 SQL Server,因此我們需要選擇的是for SQL Server。接下來我們需要知道的是“ Initial Catalog”參數,該參數用于描述應用程序 究竟應該訪問哪一個數據庫,其后的等于號跟的是應用程序需要訪問的數據庫的 名稱,即Test。另外我們還需要了解“ Data ScourcW參數,該參數用于描述數據源,即數 據庫服務器的地址,由于我們的電腦上已經安裝了SQL Server 2008,此時我們的電

14、腦也可以作為一個單獨的數據庫服務器,名稱為(local)或者localhost。上述的兩個參數我們可以打開udl文件在“連接”選項卡中查看。如下圖:提洪程序連接一1高級丨所有指定下列設蠱以連接到SQL Server數扌民選擇或輸入朋務器名稱i;(local)2.3.輸入登錄朋務器的信息:0使用Windowz NT隼戚安全設置 使用指走的用戶名稱和密碼(V): 用戶名稱3);密碼(F):二空白密碼0在朋務器上選擇數擁庫6上允許保存癱用程序標作Test1.為了我們每次編程的時候不需要去通過udl文件獲取連接字符串,我們可以通過字符串的連接將連接字符串進行相應的處理。由于我們此時需要操作的信息基本固

15、定,除了每次所訪問的數據庫不同,因此我們只需要修改“Initial Catalog 參數后的值就可以了。代碼如下:this-Co nn ectio nStri ng= Provider=SQLOLEDB.1;l ntegrated Security=SSPI;PersistSecurity Info=False;User ID=sa;Initial Catalog=;this-Co nn ectio nStri ng += DataBaseName;/將該變量的參數與In itial Catalog連接this-C onnection Stri ng += ;Data Source=(loca

16、l);接下來我們還需要在構造函數中完成一件很重要的事情初始化 COM環(huán) 境。由于ADO也是COM組件,因此我們使用ADO之前都需要初始化COM組 件,為了能夠完成自動初始化環(huán)境,我們可以將初始化的代碼放置到構造函數中(構造函數在創(chuàng)建對象時自動執(zhí)行)。初始化COM組件的代碼如下:/初始化COMS程環(huán)境if(FAILED(:Col ni tialize(NULL)cout初始化 COM境失敗! MyCo nn ection = NULL;/設置連接指針為空,防止野指針this-Records = NULL;/設置記錄集指針為空,防止野指針/設定連接字符串,需要連接的數據庫通過構造函數的形參指定th

17、is-Co nn ectio nStri ng=Provider=SQLOLEDB.1;l ntegratedSecurity=SSPI;this-C onn ectio nStri ng+= Persist SecurityIn fo=False;UserID=sa;I nitial Catalog=;this-C onn ectio nStri ng += DataBaseName;this-C onn ecti on Stri ng += ;Data Source=(local);/初始化COMS程環(huán)境if(FAILED(:CoI ni tialize(NULL)coutvv初始化COM

18、環(huán)境失敗! Co nn ectio nStri ng = this-C onn ectio nStri ng;/指定連接字符串MyCo nn ectio n-Co nn ectio nTimeout = 10;/指定連接超時為 10sdoMyCo nn ectio n-Ope n( ,adCo nn ectU nspecified);/打開連接while(MyCo nn ectio n-State != adStateOpe n);catch(_com_error e) 其中trycatch(_com_error e)用于檢測該代碼是否會產生異常情況使得程序崩潰。這一步是很有必要的。當然我們在

19、此設定只要連接狀態(tài)處于關閉狀態(tài),就不斷地向數據庫使用MyConnection-Open函數不斷的對數據庫進行連接,直 到連接上數據庫為止。Close函數:Close函數負責關閉數據庫連接,為了能夠提高數據庫訪問層的效率,我們 可以先判斷MyConnection中的State屬性,如果處于打開狀態(tài)(adStateOpe則 調用Close函數,關閉數據庫連接。代碼如下:void DataBase:Close()tryif(MyCo nn ectio n-State = adStateOpe n)如果連接處于打開狀態(tài)MyCo nn ectio n-Close(); 關閉數據庫連接 catch(_co

20、m_error e) Excute 函數:對數據庫的操作通常分為查詢操作和非查詢操作,非查詢操作包括INSERT(插入)、UPDATE (更新)、DELETE (刪除),Excute函數用于執(zhí)行非查詢操 作的SQL語句,由于SQL語句的變數還是很多的,因此我們可以將 SQL語句 作為Excute函數的形參。為了能夠檢測 SQL語句是否執(zhí)行成功,我們可以通過 返回一個int類型的值(其含義為影響多少行)。整體結構如下:int DataBase:Excute(_bstr_t const &Comma ndStri ng) _此處我們將形參設定為con st,防止程序員在使用Comma ndStri

21、 ng參數時不 小心改動了這個參數,而使用引用的目的則是為了節(jié)省該函數所占用的計算機內 存。如果我們直接使用值傳遞,則函數會在實參之外另外建立一個內存空間保存 CommandString的值?!袄速M空間”這種事情對于一些配置較老的電腦來說是萬 萬不能做的。畢竟內存的容量還是有限的,不可能所有的內存都給你使用。Excute函數的代碼如下所示:int DataBase:Excute(_bstr_t const &Comma ndStri ng)try_varia nt_t RecordsAffected;/記錄影響的行數this-Ope n();打開數據庫連接this-MyCo nn ectio

22、n-Comma ndTimeout = 10;/設置命令失敗延時為10sthis-MyC onn ectio n-Execute(Comma ndStri ng,&RecordsAffected,adCmdT ext);/執(zhí)行數據庫命令this-Close();關閉數據庫連接return (in t)RecordsAffected;/返回影響行數catch(_com_error e) 在此我們使用了剛剛已經在類中定義好的 Open函數和Close函數負責打開 和關閉數據庫連接。這樣我們可以通過函數將代碼封裝起來,避免了重復寫代碼 的麻煩。ExcuteSelect函數:ExcuteSelect函

23、數用于執(zhí)行查詢的操作,通常查詢的過程是通過 MyConnection中的Excute函數執(zhí)行SQL語句,并且接收該函數返回的記錄集指 針(類型為_RecordSetPt)。接收完成之后我們可以將該記錄集的指針作為返回 值返回。代碼如下:_RecordsetPtr & DataBase:ExcuteSelect(_bstr_t const &Comma ndStri ng)try_varia nt_t RecordsAffected;this-Records.Create In sta nce(_uuidof(Recordset);倉 U建數據集this-Ope n();打開數據庫連接this-

24、Records=MyCo nn ectio n-Execute(Comma ndStri ng,&RecordsAffected,adCmdText);執(zhí)行數據庫命令if(this-Records!=NULL)return Records; catch(_com_error e)忽略異常至此,數據庫訪問的構建結束,最底層的工作也已經做好了。讓我們來看看完整的DataBase類的代碼吧!DataBase.h的內容如下:#pragma once#ifndef DATABASE#defi ne DATABASE_H#i nclude #i nclude #in clude #in clude vco

25、ni o.h#importC:ProgramFilesCom monFilesSystemadomsado15.dllno_namespace rename(EOF,adoEOF) using n amespace std;class DataBasepublic:DataBase(_bstr_t DataBaseName);DataBase(void);int Excute(_bstr_t co nst & Comma ndStri ng);/執(zhí)行非查詢的數據庫命令_RecordsetPtr & ExcuteSelect(_bstr_t co nst & Comma ndStri ng);/

26、執(zhí)行查詢的數據庫命令void Ope n(); 打開數據庫連接void Close();/關閉數據庫連接private:_Co nn ectio nPtr MyCo nn ectio n;數據庫連接指針_RecordsetPtr Records;/數據庫記錄集指針_bstr_t Co nn ectio nStri ng;/連接字符串; 一一#en difDataBase.cpp的內容如下:#include DataBase.hDataBase:DataBase(_bstr_t DataBaseName) this-MyCo nn ection = NULL; this-Records = NU

27、LL;this-Co nn ectio nStri ng=Provider=SQLOLEDB.1;l ntegratedSecurity=SSPI;Persist Security In fo=False;User ID=sa;I nitialCatalog=;this-C onn ectio nStri ng += DataBaseName;this-C onn ecti on Stri ng += ;Data Source=(local);/初始化COMS程環(huán)境if(FAILED(:Col ni tialize(NULL)coutvv初始化COM環(huán)境失??! Co nn ectio nStr

28、i ng = this-C onn ectio nStri ng;/扌旨定連接字符串MyCo nn ectio n-Co nn ectio nTimeout = 10;/指定連接超時為 10sdoMyCo nn ectio n-Ope n( ,adCo nn ectU nspecified);/打開連接while(MyCo nn ectio n-State != adStateOpe n); catch(_com_error e) _void DataBase:Close()tryif(MyC onnection-State = adStateOpe n)女口果連接處于打開狀態(tài)MyCo nn

29、ectio n-Close();關閉數據庫連接catch(_com_error e) _int DataBase:Excute(_bstr_t const &Comma ndStri ng) _try_varia nt_t RecordsAffected;this-Ope n();打開數據庫連接this-MyC onn ectio n-Comma ndTimeout = 10;this-MyC onn ectio n-Execute(Comma ndStri ng,&RecordsAffected,adCmdT ext);/執(zhí)行數據庫命令this-Close();關閉數據庫連接return (

30、in t)RecordsAffected;返回影響行數catch(_com_error e)_RecordsetPtr & DataBase:ExcuteSelect(_bstr_t const &Comma ndStri ng)try_varia nt_t RecordsAffected;this-Records.Create In sta nce(_uuidof(Recordset);倉 U建數據集this-Ope n();打開數據庫連接this-Records=MyCo nn ectio n-Execute(Comma ndStri ng,&RecordsAffected,adCmdTe

31、xt);執(zhí)行數據庫命令if(this-Records!=NULL)return Records;catch(_com_error e) _coutvv錯誤原因:e.ErrorMessage()endl;【第二步:借助數據庫訪問層完成任務的事務層】接下來我們需要構造的是事務層,事務層我們也使用一個類進行描述,例如“ Kernel”。事務層的函數通過調用數據庫訪問層中的函數對數據庫進行訪問, 而數據庫訪問層如何具體訪問數據庫的細節(jié),事務層并不需要理會。本案例中的事務層只有一個功能,就是通過數據庫訪問層的 ExcuteSelect函數查找數據庫中 是否有符合條件的記錄,然后將所得到的結果通過記錄集返

32、回到事務層,事務層再通過對記錄集的“拆包”,取出返回的數據,并通過該數據判斷是否可以登錄。用于判斷用戶是否存在于數據表中,我們可以使用Select語句以及SQL語句中的聚合函數COUNT(*)完成。SQL語句如下:select COUNT(*) from Loginnfwhere UserName = USERNAME and PasswordKey = PASSWORD其中USERNAME指示需要查找的用戶名,PASSWORD指示用戶的密碼。 例如:selectCOUNT(*)-符合條件的記錄數fromLoginn f - 查找的數據表whereUserName = jian gha nxi

33、 n and PasswordKey = jia ng_1994221-查找條件接下來我們可以先在 SQL Server Management Studio中執(zhí)行一下,看一下返回的記錄的樣子。執(zhí)行的結果如下圖所示:二結果占消息1氏列名)工二我們可以看到上圖中所寫的列的名稱是“(無列名)”,那對于這種沒有列名的表格的記錄集我們又應該怎么訪問呢?其實這些沒有列名的表格默認從0開 始升序排序。因此我們可以使用該編號進行訪問。 上圖中只有一個單元格,也就 是第0列。好了,話題扯得有些遠了,我們現在來看一下Kernel類的聲明代碼吧!Kernel.h文件用于存放Kernel類的聲明,事實上,通常類的聲明

34、都放置在頭文件 中。代碼如下:#pragma once #ifndef KERNEL #defi ne KERNEL_H #include DataBase.h #include User.h #in clude #i nclude using n amespace std; class Kernel public:Kernel(); Kernel(); bool Log in( User &user); private:DataBase *db;第三層指針 ;#en dif其中db是DataBase類的指針,也就是指向數據庫訪問層的指針,接下來我們將會通過這個指針調用數據庫訪問層的函數,進而

35、完成訪問數據庫的操作。接下來我們還是解析一下Kernel類的函數吧!Kernel 函數:Kernel函數是Kernel類的構造函數,用于初始化私有對象,也就是db。由于db只是一個指針,因此我們需要使用new關鍵字調用DataBase類的構造函數 創(chuàng)建對象。當然很多人有個疑問,為什么不能夠直接使用DataBase類建立對象呢?那是因為私有對象不能夠直接初始化,而且DataBase類沒有無參構造函數,但卻有有參構造函數,結果有參構造函數先入為主,就不能夠直接完成初始化的 操作了。Kernel類的代碼如下:Kernel:Kernel()this-db = new DataBase(Test);創(chuàng)建

36、數據庫訪問層的對象Kernel 函數:Kernel函數是Kernel類的析構函數,用于使用 delete關鍵字釋放db所指 向的數據庫訪問層對象。代碼如下:Kernel:Kernel()delete db;/ 刪除數據庫對象Login函數:Login函數是程序員自定義的函數,用于判斷用戶是否登錄,代碼如下:bool Kern el:Log in( User &user)bool flag = false;/flag變量指示用戶是否能夠登錄int coun t = 0;/保存查詢的結果/設置需要執(zhí)行的SQL語句stri ng Comma ndStri ng = select COUNT(*)from Loginnf where UserName一川一 JComma ndStri ng += user.getUserName() + and PasswordKey =;Comma ndStri ng += use

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論