課程設(shè)計:數(shù)據(jù)庫表結(jié)構(gòu)、登錄權(quán)限與常見坑)
簡介面向數(shù)據(jù)庫系統(tǒng)設(shè)計課程的學(xué)校圖書借閱管理系統(tǒng)課程設(shè)計報告適合計算機(jī)及相關(guān)專業(yè)學(xué)生完成圖書管理類項目時參考。報告覆蓋從需求分析到詳細(xì)設(shè)計的完整流程包含數(shù)據(jù)字典、數(shù)據(jù)流圖、結(jié)構(gòu)圖與E-R圖并給出歡迎界面、讀者/管理員登錄、圖書錄入與修改、讀者注冊與信息維護(hù)、圖書查詢、借還書、數(shù)據(jù)備份恢復(fù)、系統(tǒng)管理等功能模塊的設(shè)計說明與核心代碼實現(xiàn)可直接用于課程作業(yè)或畢業(yè)設(shè)計的方案借鑒。資源共1個doc文檔壓縮包大小4.16MB內(nèi)容組織清晰翻閱方便。目前已有11180人學(xué)習(xí)下載兼具實用性與參考價值。1. 學(xué)校圖書借閱管理系統(tǒng)課程設(shè)計數(shù)據(jù)庫系統(tǒng)設(shè)計如果只看界面截圖很多人會以為這門數(shù)據(jù)庫系統(tǒng)設(shè)計的難點在登錄表單和按鈕排版真正決定成品能用多久的是那幾張數(shù)據(jù)表的結(jié)構(gòu)。這份基于 VFP 的《學(xué)校圖書借閱管理系統(tǒng)》課程設(shè)計報告把圖書管理、讀者管理、圖書服務(wù)、數(shù)據(jù)安全、系統(tǒng)管理五個板塊串成完整閉環(huán)讀者登錄三次失敗自動退出管理員接管全部權(quán)限圖書查詢支持書名、作者、出版社三種方式。無論你是拿它交課程設(shè)計報告還是想把框架改造成醫(yī)院、超市、校園一卡通之類的小系統(tǒng)都可以從數(shù)據(jù)字典和 main.prg 入手。適合正在趕大學(xué)課程設(shè)計的人也適合剛摸 VFP 想搞清楚事件循環(huán)怎么起步的新手。2. 數(shù)據(jù)字典拆解從五張表的字段寬度看懂這套系統(tǒng)的庫表設(shè)計2.1 五張表字段逐一對照這份報告的數(shù)據(jù)字典一共給了五張表Booksinfo圖書信息、Dairy登錄日志、Lendinfo借閱記錄、passwordinfo管理員賬號、Readeruinfo讀者信息。在 VFP 里字符型用 C 表示數(shù)值型用 N日期型固定占 8 位邏輯型固定占 1 位備注型不需要指定寬度。很多大學(xué)課程設(shè)計的數(shù)據(jù)字典都是直接從報告模板里復(fù)制粘貼的這份整體保留得還算完整但字段清單里存在幾處明顯的復(fù)制殘留建庫之前務(wù)必先理清。圖書信息表 Booksinfo 的字段設(shè)計如下字段名類型寬度小數(shù)位設(shè)計說明編號C10-圖書內(nèi)部編號適合做主鍵書號C28-對應(yīng)真實圖書的 ISBN 或館藏書號書名C40-文本輸入框 MaxLength 必須同步設(shè) 40作者C20--出版社C15--定價N60原數(shù)據(jù)字典寫的是“60”按 N(6,0) 理解冊數(shù)N30庫存總量借出后扣減圖書種類C18-文學(xué)、科技、歷史等分類入庫日期D8--備注M--不需要指定寬度這里要提醒一句字段寬度不是隨便抄的。書名給 40 位意味著錄入表單的文本框必須設(shè)置 MaxLength40否則用戶在界面上輸入 50 個字的書名保存時要么被截斷要么直接報字段溢出。VFP 的老式 DBF 表結(jié)構(gòu)對長度非常敏感這就是為什么課程設(shè)計第一步永遠(yuǎn)是先對著數(shù)據(jù)字典建表而不是先畫表單。其余四張表的字段相對少但同樣有值得注意的地方表名關(guān)鍵字段類型 / 寬度注意點Dairy用戶名 C(10)、登錄時間 D(8)、離開時間 D(8)-只記錄一次登錄會話的起止時間Lendinfo讀者編號 C(6)、書號 C(28)、借閱日期 D、歸還日期 D借閱天數(shù) C(8)、是否延期 L讀者編號寬度與讀者表不一致見避坑章passwordinfo用戶名 C(8)、密碼 C(7)、冊數(shù) N(30)-“冊數(shù)”是從圖書表復(fù)制錯的殘留字段Readeruinfo讀者編號 C(10)、密碼 C(10)、姓名 C(6)、性別 C(6)、年齡 C(2)是否允許借 L是否允許借是借書總開關(guān)Lendinfo 是整張庫的核心。它的讀者編號、書號、借閱日期、歸還日期、借閱情況這五個字段支撐了“誰借了什么書、什么時候借的、還了沒有”所有查詢。借閱情況字段建議固定值域在借、已還、逾期不要允許自由填寫否則統(tǒng)計報表會變成一團(tuán)亂麻。passwordinfo 表里的“冊數(shù) N(30)”明顯是從 Booksinfo 復(fù)制過來的殘留字段如果直接照抄建表后面 Grid 綁定表時就會多出一列毫無意義的“冊數(shù)”。2.2 建表語句與主鍵設(shè)計我在復(fù)現(xiàn)時一般先把 library.dbc 建出來再按下面的 SQL 建表這樣做的好處是主鍵、索引可以在建表時一次完成不用后期用 ALTER TABLE 補(bǔ)丁式修改。下面是可直接運行的 VFP 建表語句OPEN DATABASE library.dbc CREATE TABLE bookinfo (; 編號 C(10) PRIMARY KEY, ; 書號 C(28), ; 書名 C(40), ; 作者 C(20), ; 出版社 C(15), ; 定價 N(6,0), ; 冊數(shù) N(3,0), ; 圖書種類 C(18), ; 入庫日期 D, ; 備注 M) CREATE TABLE readeruinfo (; 讀者編號 C(10) PRIMARY KEY, ; 密碼 C(10), ; 姓名 C(6), ; 性別 C(6), ; 年齡 C(2), ; 詳細(xì)住址 C(28), ; 聯(lián)系電話 C(11), ; 注冊日期 D, ; 是否允許借 L, ; 備注 M) CREATE TABLE passwordinfo (; 用戶名 C(8) PRIMARY KEY, ; 密碼 C(7), ; 備注 M)注意正文的表結(jié)構(gòu)中Lendinfo 的讀者編號只給了 C(6)而 Readeruinfo 的讀者編號是 C(10)這兩個字段在邏輯上必須能關(guān)聯(lián)長度不一致是隱患。為了忠實還原原始設(shè)計下面的建表語句先按原文寫 C(6)實際開發(fā)時請統(tǒng)一改成 C(10)。借閱天數(shù)原文是字符型 C(8)建議換成數(shù)值型 N(3,0)這樣統(tǒng)計逾期天數(shù)時可以直接做算術(shù)運算不用先 VAL() 轉(zhuǎn)換。是否延期是邏輯型 L(1)建表語句里直接寫 L 即可。CREATE TABLE lendinfo (; 借閱日期 D, ; 讀者編號 C(6), ; 書號 C(28), ; 預(yù)約日期 D, ; 借閱天數(shù) C(8), ; 歸還日期 D, ; 借閱情況 C(8), ; 是否延期 L, ; 備注 M) CREATE TABLE dairy (; 用戶名 C(10), ; 登錄時間 D, ; 離開時間 D, ; 備注 M)主鍵方面Booksinfo 的編號和 Readeruinfo 的讀者編號都建議設(shè)為主鍵。Lendinfo 沒有單一主鍵它靠“借閱日期 讀者編號 書號”共同決定一條記錄的唯一性若同一讀者同一天重復(fù)借同一本書這種設(shè)計會允許兩條重復(fù)數(shù)據(jù)更穩(wěn)妥的做法是給 Lendinfo 增加一個自增流水號字段或者在借閱時先查重。Dairy 表不用主鍵它是日志表只要保證追加順序即可。2.3 關(guān)鍵關(guān)系借閱記錄表就是讀者和圖書之間的連接表從 E-R 圖角度理解這套系統(tǒng)核心關(guān)系并不復(fù)雜Readeruinfo 和 Booksinfo 之間是多對多關(guān)系一個讀者可以借多本圖書一本圖書可以被多個讀者借閱多對多關(guān)系拆出來就是 Lendinfo 這張借閱記錄表。Lendinfo 只存讀者編號和書號不冗余存書名、作者、出版社需要展示完整信息時再去關(guān)聯(lián)兩張大表。Dairy 表的作用是登錄審計它只記錄用戶名、登錄時間、離開時間。它的缺點是沒區(qū)分讀者還是管理員查詢“誰在什么時候登錄過”時用戶名可能同時出現(xiàn)在兩張賬號表里。如果想讓審計更完整建議給 Dairy 增加一個“用戶類型”字段值為讀者或管理員。另外注意“是否允許借”這個邏輯字段放在 Readeruinfo 表里是控制讀者能不能借書的總開關(guān)。讀者有逾期未還的圖書時管理員可以將該字段設(shè)為 .F.借書按鈕再根據(jù)這個字段決定是否放行。這個字段在登錄代碼里沒被檢查但借書表單必須檢查否則就是個擺設(shè)。3. 主程序與登錄權(quán)限main.prg、封面、三次錯誤鎖定3.1 main.prg 啟動順序主程序 main.prg 是這套系統(tǒng)的入口也是課程設(shè)計報告里最值得逐行讀的代碼。它的執(zhí)行順序決定了整個程序從啟動到進(jìn)入主菜單的流程。原文代碼如下set talk off set safe off set sysmenu off close all * 系統(tǒng)環(huán)境設(shè)計 release windows 常用,項目管理器,表單控件,布局,命令 modify window screen title 迷你圖書管理系統(tǒng) zoom window screen max * 屏幕和標(biāo)題設(shè)置 set defa to left(sys(16),rat(\,sys(16))) * 設(shè)置路徑 set path to data;form;pic;class * 系統(tǒng)環(huán)境設(shè)計 open database library _screen.visible.f. _screen.icon.\icon_love_11.ico public cyonghu,cmima,jiage,checked checked1 cyonghu cmima do form start * 執(zhí)行表單開始進(jìn)入系統(tǒng) read events _screen.visible.t. _screen.picturelib.gif do form 入口 read events do menu_main.mpr read events quit第一段是環(huán)境清理set talk off 關(guān)閉命令回顯set safe off 關(guān)閉覆蓋確認(rèn)彈窗set sysmenu off 隱藏 VFP 自帶的系統(tǒng)菜單close all 關(guān)閉所有打開的表和數(shù)據(jù)庫。這些是 VFP 程序的標(biāo)準(zhǔn)開頭主要目的是避免調(diào)試界面彈出各種 VFP 原生對話框。最考驗新手的是set defa to left(sys(16),rat(\,sys(16)))這行。sys(16) 返回當(dāng)前正在執(zhí)行文件的完整路徑rat 從字符串右側(cè)找第一個反斜杠left 截取到該位置結(jié)果就是把默認(rèn)目錄切到程序所在的文件夾。這樣無論從哪個目錄啟動程序都不會出現(xiàn)“文件不存在”的報錯。緊接著的set path to data;form;pic;class告訴 VFP 到這四個子目錄去查找表單、圖標(biāo)和類庫。接下來open database library打開 library.dbc_screen.visible.f.隱藏 VFP 主窗口讓程序看起來像一個獨立軟件。public cyonghu,cmima,jiage,checked 聲明四個全局變量cyonghu 保存當(dāng)前登錄用戶的編號cmima 保存密碼jiage 用于記錄當(dāng)前選中的圖書價格checked 是權(quán)限標(biāo)志位。后面所有表單判斷“當(dāng)前是讀者還是管理員”時都會引用 checked 變量。3.2 封面與入口表單主程序執(zhí)行do form start進(jìn)入封面表單 start.scx。封面上的版權(quán)滾動文字一般由計時器控件驅(qū)動原文的計時器代碼是IF thisform.label5.left thisform.width thisform.label5.left thisform.label5.left 1 ELSE thisform.label5.left -110 ENDIF這段代碼的作用是讓 label5 每次計時器觸發(fā)向右移動 1 像素超出表單寬度后重置到 -110形成文字從左向右滾動再消失的循環(huán)。封面點擊后進(jìn)入入口表單入口表單只有兩個按鈕讀者入口執(zhí)行do form dzdl管理員入口執(zhí)行do form logo點擊按鈕后各自 release 當(dāng)前入口表單。入口本身不做權(quán)限校驗只是路由。這里要注意事件循環(huán)的配合。main.prg 里出現(xiàn)三段 read events每段 read events 都必須由對應(yīng)的 clear events 退出。登錄成功后的按鈕代碼通常是thisform.release加clear events這兩行缺一不可release 關(guān)閉當(dāng)前表單clear events 讓 VFP 退出當(dāng)前事件循環(huán)才能繼續(xù)執(zhí)行主程序下一行命令。如果只 release 不 clear events程序就會停在 read events 里表現(xiàn)出“點完按鈕沒反應(yīng)”的假死狀態(tài)。3.3 讀者登錄邏輯與三次鎖定讀者登錄表單的登錄按鈕 click 代碼是這套系統(tǒng)里邏輯最完整的部分原文如下sele readerinfo if n3 if allt(thisform.text1.value) thisform.text1.setfocus wait window at 17.5,65 用戶名為空請輸入 else if allt(thisform.text2.value) thisform.text2.setfocus wait window at 20,65 密碼為空請輸入 else locate for allt(讀者編號)allt(thisform.text1.value) if found() if allt(密碼)allt(thisform.text2.value) thisform.release clear events else thisform.text2.value thisform.text2.setfocus wait window at 20,65 密碼錯誤請重新輸入 nn1 endif else thisform.text1.value thisform.text2.value thisform.text1.setfocus wait window at 17.5,65 沒有此用戶,請重新輸入 nn1 endif endif endif else n1 thisform.text1.enabled.f. thisform.text2.enabled.f. thisform.command1.enabled.f. thisform.label1.caption登錄已錯誤三次系統(tǒng)即將自動退出 endif這段代碼的核心是 n 計數(shù)器。n 在表單的 init 事件里被初始化為 1每輸錯一次密碼或查無此人就 nn1。當(dāng) n 達(dá)到 3 時if n3 不成立進(jìn)入 else 分支禁用用戶名框、密碼框和登錄按鈕并把提示標(biāo)簽改成“登錄已錯誤三次系統(tǒng)即將自動退出”。這是一種針對暴力嘗試的簡單防護(hù)。幾個細(xì)節(jié)值得注意locate for 是全表順序查找不是索引查找當(dāng) readerinfo 表數(shù)據(jù)量超過幾千條時會有明顯卡頓更高效的寫法是SELECT * FROM readeruinfo WHERE 讀者編號ALLTRIM(thisform.text1.value) INTO CURSOR temp。allt() 函數(shù)的作用是去掉字符串兩端空格因為 VFP 的字符型字段保存后會用空格補(bǔ)齊寬度不 trim 就比對會失敗。密碼比對用的是精確比較如果把等號寫成單等號會變成賦值而不是比較結(jié)果就是無論密碼對不對都判斷成功。管理員登錄的表單代碼結(jié)構(gòu)和讀者登錄基本一致只是把查詢表換成 passwordinfo字段換成用戶名和密碼。管理員進(jìn)入系統(tǒng)后 checked 變量被置為管理員狀態(tài)讀者登錄后 checked 保持普通用戶狀態(tài)后續(xù)菜單和按鈕就靠這個變量控制顯隱和可用性。4. 圖書管理、讀者管理、圖書服務(wù)、數(shù)據(jù)安全五大功能模塊的落地做法4.1 功能結(jié)構(gòu)、菜單與權(quán)限控制這套系統(tǒng)的功能模塊延續(xù)了課程設(shè)計報告的典型結(jié)構(gòu)圖書管理、讀者管理、圖書服務(wù)、數(shù)據(jù)安全、系統(tǒng)管理五大板塊。主程序在第二次 read events 之后執(zhí)行do menu_main.mpr也就是把菜單程序掛載到主窗口。菜單的組織方式很簡單一級菜單對應(yīng)五大板塊二級菜單對應(yīng)錄入、修改、查詢、借書、還書、備份、恢復(fù)等具體操作。權(quán)限控制在菜單層就可以做不必每個表單單獨判斷。常見做法是給菜單項設(shè)置 SKIP FOR 條件例如“圖書錄入”菜單項在 checked 不等于管理員時灰顯寫法是SKIP FOR checked ! 1。這樣讀者登錄后能看到的菜單只有圖書查詢和借書還書管理員登錄后才顯示錄入、修改、備份、恢復(fù)等菜單項。正文中 checked 變量在 main.prg 里被初始化為 1讀者登錄成功時需要把它改成 0管理員登錄成功時改成 1否則所有菜單項都會按默認(rèn)值放行。4.2 圖書與讀者信息的錄入、修改圖書錄入表單的核心操作是向 bookinfo 表追加一條空記錄再把表單里的值寫入字段。保存按鈕的代碼結(jié)構(gòu)一般是SELECT bookinfo APPEND BLANK REPLACE 編號 WITH ALLTRIM(THISFORM.txt編號.VALUE) REPLACE 書號 WITH ALLTRIM(THISFORM.txt書號.VALUE) REPLACE 書名 WITH ALLTRIM(THISFORM.txt書名.VALUE) REPLACE 作者 WITH ALLTRIM(THISFORM.txt作者.VALUE) REPLACE 出版社 WITH ALLTRIM(THISFORM.txt出版社.VALUE) REPLACE 定價 WITH VAL(THISFORM.txt定價.VALUE) REPLACE 冊數(shù) WITH VAL(THISFORM.txt冊數(shù).VALUE) REPLACE 圖書種類 WITH ALLTRIM(THISFORM.txt圖書種類.VALUE) REPLACE 入庫日期 WITH THISFORM.txt入庫日期.VALUEsave 之前必須做必填項校驗書號、書名、定價、冊數(shù)這四個字段建議必填。定價和冊數(shù)是數(shù)值型從文本框拿到的是字符串必須用 VAL() 轉(zhuǎn)換。錄入成功后刷新表格 Grid 的 RecordSource讓新記錄立即顯示出來。修改界面的不同之處在于多出上一條、下一條、查詢?nèi)齻€按鈕。上一條下一條就是移動記錄指針SELECT bookinfo SKIP -1 IF BOF() GO TOP ENDIF THISFORM.REFRESH()Bof 和 Eof 是兩個經(jīng)常被忽略的邊界指針已經(jīng)到第一行時再 SKIP -1 會進(jìn)入文件頭此時必須 GO TOP 拉回來否則記錄指針就會停留在無效位置表單上顯示的字段值全是空的。查詢按鈕一般用 locate 按編號找記錄找到后刷新表單即可。讀者錄入和修改的邏輯同構(gòu)只是表換成 readeruinfo保存時要額外確認(rèn)“是否允許借”默認(rèn)置為 .T.新讀者密碼默認(rèn)可以用“123456”或?qū)W號后六位課程設(shè)計里這種簡化完全可以接受。4.3 圖書查詢與借書還書圖書查詢支持書名、作者、出版社三種查詢方式落地時最省事的做法是三條 SQL 分支把查詢結(jié)果輸出到臨時表再用 Grid 展示SELECT * FROM bookinfo ; WHERE 書名 LIKE % ALLTRIM(THISFORM.txt條件.VALUE) % ; INTO CURSOR temp_search THISFORM.grid1.RecordSourceType 1 THISFORM.grid1.RecordSource temp_search THISFORM.grid1.REFRESH()LIKE 配合百分號是模糊查詢的常用姿勢書名包含關(guān)鍵字即可命中。查詢條件為空時會把整張表都查出來如果數(shù)據(jù)量大頁面會卡可以在 WHERE 條件里加一個AND 冊數(shù) 0之類的過濾。INTO CURSOR 的輸出是臨時表程序退出后自動消失不會污染正式數(shù)據(jù)。借書的流程比查詢多幾步。先檢查 readeruinfo 的“是否允許借”字段是否為 .T.再檢查 bookinfo 里對應(yīng)書號的冊數(shù)是否大于 0兩者都通過就往 lendinfo 插入一條記錄SELECT bookinfo LOCATE FOR ALLTRIM(書號) ALLTRIM(THISFORM.txt書號.VALUE) IF !FOUND() WAIT WINDOW 沒有這本書 RETURN ENDIF IF 冊數(shù) 0 WAIT WINDOW 這本書已全部借出 RETURN ENDIF SELECT lendinfo APPEND BLANK REPLACE 讀者編號 WITH cyonghu REPLACE 書號 WITH ALLTRIM(bookinfo.書號) REPLACE 借閱日期 WITH DATE() REPLACE 借閱天數(shù) WITH 30 REPLACE 借閱情況 WITH 在借 REPLACE 是否延期 WITH .F. SELECT bookinfo REPLACE 冊數(shù) WITH 冊數(shù) - 1還書邏輯正好相反按讀者編號和書號找到“在借”狀態(tài)的那條記錄更新歸還日期為當(dāng)前日期借閱情況改為“已還”再把 bookinfo 的冊數(shù)加回去。如果當(dāng)前日期超過借閱日期加上借閱天數(shù)則把是否延期置 .T.方便管理員做逾期統(tǒng)計。4.4 數(shù)據(jù)備份與恢復(fù)數(shù)據(jù)安全模塊在課程設(shè)計里往往是湊頁數(shù)的真正能落地的做法就是文件級備份。備份按鈕的核心代碼如下CLOSE DATABASES ALL COPY FILE library.dbc TO backup_library.dbc COPY FILE bookinfo.dbf TO backup_bookinfo.dbf COPY FILE readeruinfo.dbf TO backup_readeruinfo.dbf COPY FILE lendinfo.dbf TO backup_lendinfo.dbf COPY FILE passwordinfo.dbf TO backup_passwordinfo.dbf COPY FILE dairy.dbf TO backup_dairy.dbf這里最容易踩的坑就是 CLOSE DATABASES ALL只要 library.dbc 處于打開狀態(tài)COPY FILE 就會提示文件被占用?;謴?fù)操作反過來執(zhí)行把備份文件復(fù)制回原文件名。備份文件建議按日期命名比如 backup_library_20241208.dbc這樣需要回滾時可以明確知道是哪個時間點的數(shù)據(jù)。更完善一點的做法是先把整個 data 目錄壓縮成 ZIP 文件再復(fù)制到本機(jī)另一個磁盤目錄。VFP 本身沒有內(nèi)置 ZIP 命令可以用 VFP 的SET LIBRARY TO調(diào)用外部壓縮庫或者直接用 Windows 命令行的 RAR 在備份按鈕里 Shell 出去。課程設(shè)計答辯階段能講清楚“備份前先關(guān)庫、恢復(fù)前先覆蓋”這個原理就可以了。5. 避坑VFP 圖書借閱系統(tǒng)的常見翻車現(xiàn)場與排查5.1 啟動報“文件不存在”或直接秒退現(xiàn)象雙擊運行 main.prgVFP 閃一下就沒影了或者提示“文件 start.scx 不存在”。原因VFP 的默認(rèn)工作目錄和程序所在目錄不一致。直接 do 一個腳本時VFP 不會自動切換當(dāng)前目錄set defa 沒生效自然找不到 data 目錄下的庫和 form 目錄下的表單。解決把 set defa 和 set path 放在主程序最前面確保路徑設(shè)置發(fā)生在任何 do form 之前。檢查 sys(16) 返回值是否包含完整路徑如果 rat 出來的路徑錯了多半是直接 do 而不是運行 .exe。這也解釋了為什么 main.prg 里那兩行路徑代碼那么值錢刪掉它整個系統(tǒng)就是黑匣子。5.2 登錄永遠(yuǎn)提示“沒有此用戶”現(xiàn)象明明數(shù)據(jù)庫里有讀者編號登錄卻提示“沒有此用戶”。原因readeruinfo 的讀者編號是 C(10)文本框中輸入 10 位以內(nèi)的編號時allt(讀者編號) 會去掉右端空格然后比較理論上是能匹配的。真正的問題往往出在 Lendinfo 和 Readeruinfo 兩張表的讀者編號字段寬度不一致或者讀者編號是數(shù)值型字段文本框給它傳字符比較類型對不上。解決打開表設(shè)計器逐張檢查“讀者編號”的類型和寬度全部統(tǒng)一為 C(10)。如果有的表是數(shù)值型在 get 出編號時用 STR(讀者編號, 10) 轉(zhuǎn)成字符串。查不到記錄時先用SELECT * FROM readeruinfo WHERE 讀者編號 輸入值在命令窗口驗證數(shù)據(jù)是否存在縮小問題范圍。5.3 密碼輸對了也提示密碼錯誤現(xiàn)象用戶確認(rèn)密碼沒輸錯但系統(tǒng)反復(fù)提示“密碼錯誤請重新輸入”。原因passwordinfo 表的密碼字段寬度是 C(7)如果初始錄入時管理員密碼超過 7 位保存時會被截斷到 7 位。密碼文本框中輸入的內(nèi)容比字段長時VFP 比較的是被截斷后的字段值和完整輸入值永遠(yuǎn)匹配不上。解決把 passwordinfo 密碼字段加寬到 C(16) 或 C(20)同時建議讀者表的密碼字段統(tǒng)一用 C(16)。文本密碼框在單機(jī)課程設(shè)計里夠用但要把密碼存為在明文這一點在答辯時主動說清楚作為可改進(jìn)項提出比被老師追問要體面得多。5.4 備份時提示“文件正在使用”現(xiàn)象備份按鈕一執(zhí)行就報“文件正在使用”或共享沖突。原因VFP 打開數(shù)據(jù)庫后library.dbc 和正在使用的表文件都被占用了COPY FILE 不能覆蓋被獨占打開的 .dbc 或 .dbf 文件。很多人直接寫 COPY FILE 卻不先關(guān)庫正好觸發(fā)這個限制。解決備份前強(qiáng)制加兩行CLOSE DATABASES ALL 關(guān)閉所有數(shù)據(jù)庫CLOSE TABLES ALL 關(guān)閉所有表。備份結(jié)束后再重新 OPEN DATABASE library?;謴?fù)操作更要先確認(rèn)程序沒有打開任何表否則文件覆蓋失敗后數(shù)據(jù)庫文件還處于半損壞狀態(tài)最穩(wěn)妥的流程是退出系統(tǒng)到 VFP 命令窗口手動復(fù)制覆蓋后再運行系統(tǒng)。5.5 登錄三次鎖定失效現(xiàn)象連續(xù)輸錯三次密碼表單并沒有鎖定或者重新進(jìn)入登錄表單后又能繼續(xù)嘗試。原因n 計數(shù)器若定義為表單的局部變量每次釋放并重新執(zhí)行登錄表單時init 事件都會把 n 重新初始化為 1鎖定標(biāo)志全部清零。系統(tǒng)雖然有三次鎖定代碼實際卻起不到攔截作用。解決把 n 聲明為全局變量在 main.prg 里統(tǒng)一初始化或者在表單 init 里讀一個自定義表單屬性 thisform.nCount。公共變量方案最簡單退出系統(tǒng)時順手重置即可。如果想讓鎖定更嚴(yán)格還可以配合 VFP 的SET SECURITY或者寫一個登錄失敗日志表記錄失敗次數(shù)和最后失敗時間。6. 進(jìn)階把課程設(shè)計改造成能打包發(fā)布的完整系統(tǒng)課程設(shè)計能跑起來只是及格線真正加分的是把它從“演示系統(tǒng)”變成“可交付系統(tǒng)”。第一個值得做的事情是建一個借閱歷史視圖把三張表關(guān)聯(lián)起來查詢時不用手動寫多表 JOINCREATE SQL VIEW v_lend_history AS ; SELECT Readeruinfo.姓名, Readeruinfo.讀者編號, ; Booksinfo.書名, Booksinfo.作者, ; Lendinfo.借閱日期, Lendinfo.歸還日期, ; Lendinfo.借閱情況 ; FROM Readeruinfo INNER JOIN Lendinfo ; ON Readeruinfo.讀者編號 Lendinfo.讀者編號 ; INNER JOIN Booksinfo ON Lendinfo.書號 Booksinfo.書號這個視圖把所有借閱明細(xì)變成一張平鋪表查詢表單的 Grid 直接綁定 v_lend_history省去在代碼里反復(fù)寫關(guān)聯(lián)條件也方便后續(xù)做統(tǒng)計報表。打包發(fā)布是第二個重點。VFP 程序的發(fā)行步驟并不復(fù)雜將 main.prg 設(shè)為主程序新建菜單 menu_main.mnx把項目編譯成 .app再用構(gòu)建管理器生成 .exe。發(fā)布目錄必須帶上 VFP 運行庫常見的是 vfp6r.dll、vfp9r.dll 之類否則別人機(jī)器上沒裝 VFP 環(huán)境雙擊 exe 會提示“無法定位程序輸入點”。這個細(xì)節(jié)是很多人血淚經(jīng)驗的來源我見過太多同學(xué)在自己機(jī)器上跑挺順copy 到老師電腦上就報錯基本都是運行庫沒帶全。最后建議在答辯前跑一遍完整的冒煙驗證流程步驟操作預(yù)期結(jié)果1讀者注冊新賬號記錄寫入 readeruinfo默認(rèn)允許借書2新賬號登錄登錄成功菜單不含圖書錄入3查詢一本書Grid 顯示結(jié)果借閱情況可見4借書Lendinfo 新增在借記錄冊數(shù)減一5還書記錄改為已還冊數(shù)加一6管理員登錄后備份備份文件生成成功7恢復(fù)備份數(shù)據(jù)回到備份時狀態(tài)8連續(xù)輸錯三次密碼登錄控件禁用提示自動退出這套流程 10 分鐘就能跑完但能把表單間跳轉(zhuǎn)、字段更新、權(quán)限控制全部覆蓋到。從那以后我每次拿到一份數(shù)據(jù)庫課程設(shè)計都會先執(zhí)行一遍建表語句再逐張打開表確認(rèn)字段類型、寬度、索引確認(rèn)沒有從別的項目復(fù)制來的殘留字段最后才看界面代碼。庫表設(shè)計這一步走穩(wěn)了后面的表單和報表全是順?biāo)浦邸OM麕偷侥?。本文還有配套的精品資源點擊獲取