:從數(shù)據(jù)庫(kù)設(shè)計(jì)到論文答辯全流程)
這幾年帶畢業(yè)設(shè)計(jì)SpringBoot加Vue的博物館信息管理系統(tǒng)幾乎是我見(jiàn)過(guò)最多人選的題目之一。光一個(gè)方向我前后看過(guò)幾十個(gè)版本有的偏重藏品管理有的著重預(yù)約流程還有的把展廳和志愿者都塞進(jìn)去。題目年年類似但做得好的和做得一般的拿出來(lái)的完成度會(huì)有天壤之別。這篇文章我想把這套系統(tǒng)從選題邏輯、數(shù)據(jù)庫(kù)設(shè)計(jì)、前后端實(shí)現(xiàn)到怎么轉(zhuǎn)化成畢業(yè)論文再到搭建過(guò)程中的高頻坑位整體捋一遍。如果你正在準(zhǔn)備這類畢業(yè)設(shè)計(jì)或者想用這個(gè)項(xiàng)目作為全棧入門練手順著這條線走下去能少走不少?gòu)澛贰N蚁日f(shuō)一個(gè)判斷博物館信息管理系統(tǒng)不是簡(jiǎn)單的“增刪改查”堆砌它是一個(gè)非常適合用來(lái)展示工程能力的綜合型業(yè)務(wù)系統(tǒng)。無(wú)論從業(yè)務(wù)復(fù)雜度、表結(jié)構(gòu)設(shè)計(jì)、權(quán)限控制、預(yù)約邏輯還是從Vue端界面呈現(xiàn)的角度它都能裝下足夠的干貨。對(duì)畢業(yè)生來(lái)說(shuō)它既不會(huì)難到無(wú)法落地也不會(huì)簡(jiǎn)單到答辯時(shí)無(wú)話可說(shuō)。1. 這個(gè)選題為什么年年火——畢業(yè)設(shè)計(jì)題型的真實(shí)分析1.1 “信息系統(tǒng)類畢業(yè)設(shè)計(jì)”的底層邏輯先把這個(gè)題目的本質(zhì)拆開(kāi)。任何信息管理系統(tǒng)無(wú)論前面掛的是“博物館”“圖書館”“健身房”還是“寵物店”它的底層骨架都差不太多用戶管理、內(nèi)容管理、預(yù)約或訂單處理、統(tǒng)計(jì)展示。選這類題目的學(xué)生本質(zhì)上是在用一套全棧技術(shù)棧解決一個(gè)中等復(fù)雜度的業(yè)務(wù)數(shù)據(jù)管理問(wèn)題。為什么博物館場(chǎng)景特別受歡迎原因是它兼顧了兩頭。一端是普通用戶也就是參觀者他們要瀏覽展覽、查看藏品、在線預(yù)約另一端是后臺(tái)管理員要維護(hù)藏品檔案、發(fā)布展覽信息、審核預(yù)約、管理展廳數(shù)據(jù)。這種“兩端都有事干”的設(shè)計(jì)讓前端頁(yè)面顯得豐富后端接口也不至于只是幾個(gè)空殼子。我在跟學(xué)生聊選題時(shí)經(jīng)常說(shuō)一句話畢業(yè)設(shè)計(jì)最怕的不是功能多而是功能少到?jīng)]法支撐論文的章節(jié)結(jié)構(gòu)。博物館管理系統(tǒng)天然有至少五個(gè)功能域——藏品信息管理、展廳與展覽管理、參觀預(yù)約管理、用戶與權(quán)限管理、公告與數(shù)據(jù)統(tǒng)計(jì)。這五個(gè)域一個(gè)個(gè)寫進(jìn)論文里需求分析、系統(tǒng)設(shè)計(jì)、功能實(shí)現(xiàn)、系統(tǒng)測(cè)試四章就都有實(shí)打?qū)嵉膬?nèi)容可以寫。1.2 相比其他信息系統(tǒng)博物館場(chǎng)景的特殊優(yōu)勢(shì)有學(xué)生問(wèn)我那跟“圖書管理系統(tǒng)”“二手交易平臺(tái)”比選博物館有什么差別差別在業(yè)務(wù)語(yǔ)義。圖書管理基本就是圖書增刪改查加借還流程業(yè)務(wù)邏輯相對(duì)線性二手交易平臺(tái)雖然業(yè)務(wù)豐富但涉及到支付、訂單狀態(tài)扭轉(zhuǎn)、買家賣家糾紛處理對(duì)畢業(yè)設(shè)計(jì)來(lái)說(shuō)容易“收不住”。博物館系統(tǒng)的業(yè)務(wù)量級(jí)恰好卡在中間藏品有朝代、材質(zhì)、年代、分類、狀態(tài)這些有專業(yè)感的屬性展覽有策劃周期和關(guān)聯(lián)關(guān)系預(yù)約有一整套狀態(tài)流轉(zhuǎn)。它比純CRUD多了一層“業(yè)務(wù)味道”但又不會(huì)像電商平臺(tái)那樣復(fù)雜到讓你陷進(jìn)分布式事務(wù)的泥潭。更要緊的是博物館系統(tǒng)在答辯時(shí)非?!昂弥v”。評(píng)委老師不用懂技術(shù)也能理解場(chǎng)景。你說(shuō)“參觀者在線預(yù)約參觀管理員后臺(tái)審核”一句話就能講清系統(tǒng)價(jià)值。反過(guò)來(lái)如果你做一個(gè)算法類的題目可能光解釋問(wèn)題定義就得花五分鐘。信息管理系統(tǒng)的優(yōu)勢(shì)就在這里業(yè)務(wù)模型是透明的技術(shù)實(shí)現(xiàn)的討論門檻自然就低了。1.3 動(dòng)工之前先確認(rèn)自己的基線技能選這個(gè)題目之前我建議你先做一次誠(chéng)實(shí)的現(xiàn)狀評(píng)估。需要具備的硬指標(biāo)有這么幾項(xiàng)Java基礎(chǔ)語(yǔ)法和面向?qū)ο笏枷氩荒苌柚辽倌芸炊甋ervice、Controller這些注解的含義會(huì)寫最簡(jiǎn)單的SQL知道主鍵、外鍵、索引大概是怎么回事前端方面能看懂Vue單文件組件的基本結(jié)構(gòu)知道data、methods、mounted是干什么用的。如果這些條件離你還有點(diǎn)遠(yuǎn)那第一步不是急著敲代碼而是先花兩周把基礎(chǔ)補(bǔ)齊。我見(jiàn)過(guò)一些學(xué)生Java還停留在“照著抄能跑”的階段就直接開(kāi)項(xiàng)目結(jié)果被Maven依賴、MyBatis映射、前端跨域三連擊勸退最后只能花錢請(qǐng)人代做這對(duì)于畢業(yè)設(shè)計(jì)來(lái)說(shuō)就失去意義了。反過(guò)來(lái)如果你已經(jīng)具備這些基礎(chǔ)那博物館管理系統(tǒng)是一個(gè)很好的放大器——你可以在一個(gè)可控的復(fù)雜度內(nèi)把后端分層、接口設(shè)計(jì)、前端組件化、權(quán)限控制整套工程實(shí)踐都過(guò)一遍做完之后簡(jiǎn)歷上也能多一個(gè)拿得出手的項(xiàng)目。2. 數(shù)據(jù)模型先行博物館信息系統(tǒng)的功能邊界與表單設(shè)計(jì)2.1 從需求分析到功能清單哪些模塊該保留哪些沒(méi)必要做很多學(xué)生拿到題目第一反應(yīng)是打開(kāi)IDE新建項(xiàng)目開(kāi)始寫代碼。這是順序錯(cuò)了。做信息系統(tǒng)第一步永遠(yuǎn)是畫功能清單。我習(xí)慣讓學(xué)生先拿一張紙把系統(tǒng)角色和功能列出來(lái)再?zèng)Q定表結(jié)構(gòu)。博物館信息管理系統(tǒng)通常保留兩大角色普通用戶參觀者和管理員。管理員內(nèi)部還可以再拆超級(jí)管理員負(fù)責(zé)賬號(hào)和數(shù)據(jù)維護(hù)普通管理員負(fù)責(zé)展覽和預(yù)約審核。這里的核心功能模塊我建議鎖定為五個(gè)藏品管理藏品的錄入、編輯、下架、詳情查看支持按名稱、朝代、分類檢索。展廳與展覽管理維護(hù)展廳基礎(chǔ)信息創(chuàng)建展覽并將展品關(guān)聯(lián)到展覽。預(yù)約管理參觀者提交預(yù)約、查看預(yù)約狀態(tài)管理員后臺(tái)審核或者自動(dòng)審核。用戶管理注冊(cè)、登錄、角色分配、賬號(hào)啟停用。系統(tǒng)管理公告發(fā)布、數(shù)據(jù)統(tǒng)計(jì)、操作日志。至于要不要做展廳VR、語(yǔ)音導(dǎo)覽、線上文創(chuàng)商城我一律建議慎重。這些功能聽(tīng)起來(lái)好看但每一個(gè)都會(huì)顯著拉長(zhǎng)開(kāi)發(fā)周期。畢業(yè)設(shè)計(jì)的核心是“完整”不是“酷炫”。做一個(gè)邏輯閉環(huán)的小系統(tǒng)遠(yuǎn)比做一個(gè)半成品的“大平臺(tái)”更有說(shuō)服力。2.2 核心表的字段設(shè)計(jì)與關(guān)系約定功能清單定了之后表結(jié)構(gòu)就是整個(gè)項(xiàng)目的承重墻。我建議至少設(shè)計(jì)這六張核心表用戶表user主鍵、用戶名、密碼密文存儲(chǔ)、昵稱、聯(lián)系電話、角色標(biāo)識(shí)、創(chuàng)建時(shí)間、狀態(tài)。角色標(biāo)識(shí)可以用一個(gè)字段區(qū)分也可以引入角色表做標(biāo)準(zhǔn)RBAC。小系統(tǒng)里我傾向于直接用字段區(qū)分省事且夠用。藏品表collection主鍵、藏品編號(hào)業(yè)務(wù)唯一、名稱、類別、朝代、材質(zhì)、尺寸、圖片地址、藏品狀態(tài)在庫(kù)/展出/修復(fù)/下架、簡(jiǎn)介、錄入人、錄入時(shí)間。這張表的字段是后面檢索功能和列表展示的數(shù)據(jù)來(lái)源字段命名要規(guī)范別一會(huì)兒用create_time一會(huì)兒用created_at。展廳表hall主鍵、展廳名稱、位置、容納人數(shù)上限、開(kāi)放時(shí)間、簡(jiǎn)介。展覽表exhibition主鍵、標(biāo)題、封面圖、展覽介紹、舉辦時(shí)間起止、關(guān)聯(lián)展廳ID、狀態(tài)籌備中/進(jìn)行中/已結(jié)束。預(yù)約表reservation主鍵、預(yù)約編號(hào)、用戶ID、展覽ID、預(yù)約日期、到館時(shí)間、預(yù)約人數(shù)、聯(lián)系電話、狀態(tài)待確認(rèn)/已確認(rèn)/已取消/已完成、提交時(shí)間。這張表是整個(gè)系統(tǒng)業(yè)務(wù)邏輯最密的地方后面會(huì)詳細(xì)說(shuō)。公告表notice主鍵、標(biāo)題、內(nèi)容、發(fā)布人、發(fā)布時(shí)間。這張表用來(lái)?yè)纹鹗醉?yè)信息和論文里的“信息發(fā)布”功能點(diǎn)。字段層面有幾個(gè)細(xì)節(jié)要提醒。第一個(gè)是密碼必須加密存儲(chǔ)這是安全底線。第二個(gè)是含有狀態(tài)語(yǔ)義的字段建議用Integer而不是String方便做狀態(tài)機(jī)的邏輯判斷。第三個(gè)是大量用于聯(lián)表查詢的字段比如exhibition_id、user_id一定要建索引。別小看這種細(xì)節(jié)答辯時(shí)老師問(wèn)到數(shù)據(jù)庫(kù)設(shè)計(jì)你能說(shuō)出索引和唯一約束的設(shè)置理由印象分會(huì)明顯不一樣。2.3 角色權(quán)限體系如何劃分超級(jí)管理員為什么不可或缺權(quán)限設(shè)計(jì)是信息系統(tǒng)類畢業(yè)設(shè)計(jì)的必考點(diǎn)。最簡(jiǎn)單好用的做法是用一張用戶表加一個(gè)role字段區(qū)分USER和ADMIN兩種角色。查詢功能通過(guò)登錄狀態(tài)控制管理功能通過(guò)角色控制。超級(jí)管理員往往是學(xué)生容易漏掉的點(diǎn)。很多人覺(jué)得系統(tǒng)里有管理員賬號(hào)就夠了為什么還要分超級(jí)管理員和普通管理員實(shí)際場(chǎng)景是這樣的。普通管理員可以管理藏品和展覽但不應(yīng)該能刪除其他管理員賬號(hào)也不應(yīng)能修改系統(tǒng)參數(shù)。系統(tǒng)則需要有一個(gè)最高權(quán)限賬號(hào)來(lái)兜底。這種“分級(jí)授權(quán)”的思想寫進(jìn)論文里是對(duì)權(quán)限管理的合理展開(kāi)也讓你后端的權(quán)限校驗(yàn)邏輯有了層次。3. SpringBoot后端接口設(shè)計(jì)順序與實(shí)現(xiàn)要點(diǎn)3.1 地基先打好統(tǒng)一返回體、異常處理和JWT后端工程搭建的時(shí)候我強(qiáng)烈建議第一件事不是寫業(yè)務(wù)接口而是把三樣基礎(chǔ)設(shè)施先做好。第一個(gè)是統(tǒng)一返回體。所有接口都返回一個(gè)統(tǒng)一包裝對(duì)象比如Result 里面包含code、message、data三個(gè)字段。這樣前端可以用統(tǒng)一的邏輯處理成功和失敗而不是每個(gè)接口各寫各的返回格式。public class ResultT { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(操作成功); result.setData(data); return result; } public static T ResultT error(String message) { ResultT result new Result(); result.setCode(500); result.setMessage(message); return result; } }第二個(gè)是全局異常處理。用RestControllerAdvice統(tǒng)一捕獲業(yè)務(wù)異常和系統(tǒng)異常。這一寫在排錯(cuò)時(shí)會(huì)救你很多命。否則一旦代碼里某個(gè)查詢報(bào)空指針前端只會(huì)看到一個(gè)格式亂七八糟的報(bào)錯(cuò)排查起來(lái)效率極低。第三個(gè)是登錄認(rèn)證。我推薦用JWT而不是簡(jiǎn)單的Session。JWT的核心思路是用戶登錄成功后后端簽發(fā)一個(gè)帶有效期的token前端后續(xù)請(qǐng)求都在header里帶上這個(gè)token后端通過(guò)攔截器解析并校驗(yàn)。這個(gè)方案的好處是無(wú)狀態(tài)、易于前后端分離部署而且“Token認(rèn)證機(jī)制”本身也是論文里一個(gè)很漂亮的章節(jié)素材。jwt: secret: your-secret-key expire: 86400 # 24小時(shí)3.2 藏品管理接口CRUD中容易被忽視的細(xì)節(jié)藏品管理模塊對(duì)應(yīng)的是一組標(biāo)準(zhǔn)CRUD接口。但這里有兩個(gè)細(xì)節(jié)值得展開(kāi)。第一個(gè)是分頁(yè)條件查詢。接口需要支持同時(shí)按照名稱模糊查詢、按朝代篩選、按分類篩選并返回分頁(yè)數(shù)據(jù)。使用MyBatis-Plus時(shí)可以這樣組織查詢條件Override public PageResultCollection pageCollections(CollectionQuery query) { LambdaQueryWrapperCollection wrapper new LambdaQueryWrapper(); wrapper.like(StringUtils.hasText(query.getName()), Collection::getName, query.getName()); wrapper.eq(StringUtils.hasText(query.getDynasty()), Collection::getDynasty, query.getDynasty()); wrapper.eq(query.getCategory() ! null, Collection::getCategory, query.getCategory()); wrapper.orderByDesc(Collection::getCreateTime); PageCollection page new Page(query.getPageNum(), query.getPageSize()); PageCollection result collectionMapper.selectPage(page, wrapper); return new PageResult(result.getRecords(), result.getTotal()); }這里有個(gè)經(jīng)驗(yàn)查詢條件對(duì)象和實(shí)體類分開(kāi)定義不要直接用實(shí)體類接收前端參數(shù)。原因很簡(jiǎn)單實(shí)體類字段會(huì)被MyBatis-Plus用于自動(dòng)填充和邏輯刪除混用容易出問(wèn)題而且在論文里你可以把“DTO與實(shí)體分離”作為接口設(shè)計(jì)的一項(xiàng)規(guī)范寫出來(lái)。第二個(gè)是圖片處理。藏品圖片的上傳建議上傳到服務(wù)器本地目錄數(shù)據(jù)庫(kù)里只存訪問(wèn)路徑。這個(gè)方案對(duì)畢業(yè)設(shè)計(jì)來(lái)說(shuō)夠用也不需要額外花錢開(kāi)通云存儲(chǔ)。但要注意配置虛擬路徑映射否則圖片文件寫到了本地磁盤前端卻訪問(wèn)不到。Configuration public class WebConfig implements WebMvcConfigurer { Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/upload/**) .addResourceHandler(file: uploadPath /); } }3.3 預(yù)約模塊整個(gè)系統(tǒng)最容易出錯(cuò)的地方預(yù)約管理是博物館系統(tǒng)區(qū)別于普通CRUD系統(tǒng)的核心點(diǎn)也是答辯時(shí)老師最喜歡深挖的地方。預(yù)約這里有三層邏輯。第一層是預(yù)約創(chuàng)建的合法性校驗(yàn)。用戶提交預(yù)約時(shí)后端不能只往表里插一條記錄要先校驗(yàn)預(yù)約的展覽是否存在并處于“進(jìn)行中”狀態(tài)預(yù)約日期是否在展覽舉辦時(shí)間范圍內(nèi)當(dāng)前預(yù)約人數(shù)是否超過(guò)展廳人數(shù)上限。這些校驗(yàn)邏輯全部通過(guò)才允許落庫(kù)。第二層是預(yù)約人數(shù)的控制。這里有兩種做法簡(jiǎn)單做法是預(yù)約時(shí)只校驗(yàn)單次預(yù)約人數(shù)不超過(guò)上限完整做法是統(tǒng)計(jì)該日期的累計(jì)預(yù)約人次與上限比較。做完整版的難度并不高一條SQL聚合查詢就搞定但避免超限的效果和論文里的說(shuō)辭會(huì)漂亮很多。SELECT COALESCE(SUM(visit_count), 0) FROM reservation WHERE exhibition_id #{exhibitionId} AND visit_date #{visitDate} AND status CONFIRMED第三層是狀態(tài)流轉(zhuǎn)。預(yù)約狀態(tài)我建議設(shè)置為PENDING待確認(rèn)、CONFIRMED已確認(rèn)、CANCELLED已取消、COMPLETED已完成。最簡(jiǎn)單的流轉(zhuǎn)是用戶在待確認(rèn)狀態(tài)下可以取消管理員可以將待確認(rèn)轉(zhuǎn)為已確認(rèn)系統(tǒng)在預(yù)約日期過(guò)后可以定時(shí)或手動(dòng)將已確認(rèn)變更為已完成。這個(gè)狀態(tài)機(jī)寫清楚后后端代碼結(jié)構(gòu)會(huì)清晰很多論文里也能畫一張狀態(tài)流轉(zhuǎn)圖。3.4 接口設(shè)計(jì)順序建議后端接口不要零散地亂寫我建議按依賴順序推進(jìn)先寫登錄注冊(cè)因?yàn)闆](méi)有token就無(wú)法調(diào)試其他接口再寫用戶管理和公告這些表結(jié)構(gòu)簡(jiǎn)單能幫你把統(tǒng)一返回體和異常處理的代碼跑通接著寫藏品和展廳吃透分頁(yè)條件和實(shí)體類分離最后寫預(yù)約模塊因?yàn)樗蕾囌褂[和展廳的數(shù)據(jù)屬于業(yè)務(wù)集成層。每寫完一個(gè)模塊就用Postman或Apifox把接口跑一遍再往前推進(jìn)。不要等全部寫完了再統(tǒng)調(diào)那時(shí)代碼里積累的錯(cuò)誤會(huì)讓你調(diào)試到崩潰。4. Vue前端管理端與參觀端的頁(yè)面結(jié)構(gòu)拆解4.1 后臺(tái)管理界面怎么組織導(dǎo)航與表格前端部分我建議使用Vue3加Element Plus這也是目前最主流的中后臺(tái)前端組合。管理端頁(yè)面結(jié)構(gòu)通常是標(biāo)準(zhǔn)的左側(cè)菜單加右側(cè)內(nèi)容區(qū)左側(cè)菜單按照后端模塊一一對(duì)應(yīng)首頁(yè)儀表盤、藏品管理、展廳管理、展覽管理、預(yù)約審核、用戶管理、公告管理。右側(cè)內(nèi)容區(qū)用Router來(lái)控制頁(yè)面切換每個(gè)模塊配一個(gè)獨(dú)立的視圖組件。注意菜單別做得太花哨Element Plus的el-menu組件能滿足需求而且這套結(jié)構(gòu)在論文里的“前端架構(gòu)設(shè)計(jì)”章節(jié)非常好寫。列表頁(yè)的設(shè)計(jì)有固定的套路頂部是篩選條件區(qū)域關(guān)鍵詞輸入框、下拉選擇、搜索重置按鈕中間是表格區(qū)域底部是分頁(yè)器。這個(gè)結(jié)構(gòu)幾乎適用于所有管理模塊。format一下用el-table綁定數(shù)據(jù)用el-pagination綁定分頁(yè)參數(shù)。template div classcollection-page el-form :inlinetrue el-form-item label藏品名稱 el-input v-modelquery.name placeholder請(qǐng)輸入 clearable / /el-form-item el-form-item label朝代 el-select v-modelquery.dynasty clearable el-option label唐代 value唐代 / el-option label宋代 value宋代 / /el-select /el-form-item el-form-item el-button typeprimary clickhandleSearch搜索/el-button /el-form-item /el-form el-table :datatableData v-loadingloading !-- 列定義省略 -- /el-table el-pagination v-model:current-pagequery.pageNum v-model:page-sizequery.pageSize :totaltotal current-changefetchData / /div /template當(dāng)你把第一個(gè)列表頁(yè)完整做出來(lái)后后面所有模塊的列表頁(yè)都是復(fù)制、改字段、調(diào)接口三個(gè)動(dòng)作。這也是為什么我不建議一上來(lái)就搞復(fù)雜封裝先做一個(gè)標(biāo)準(zhǔn)的讓你理解套路。先做一套最樸素的頁(yè)面跑通之后再考慮封裝一個(gè)BaseTable組件。按照做中學(xué)的順序來(lái)對(duì)新手更友好。如果一開(kāi)始就搞很多抽象組件很容易因?yàn)檫^(guò)度設(shè)計(jì)把自己繞暈。4.2 參觀端頁(yè)面觀眾視角的動(dòng)線設(shè)計(jì)參觀端是面對(duì)普通用戶的頁(yè)面主要包括首頁(yè)展示、展覽列表、藏品瀏覽、預(yù)約提交、個(gè)人中心。首頁(yè)我建議簡(jiǎn)單直接輪播圖展示重點(diǎn)展覽下面放最新公告和推薦展品。不要試圖塞太多東西信息層級(jí)越清晰越好。展覽列表頁(yè)展示所有正在進(jìn)行的展覽點(diǎn)擊進(jìn)入詳情頁(yè)在詳情頁(yè)預(yù)留“立即預(yù)約”按鈕。預(yù)約流程前端要設(shè)計(jì)得盡量少出岔子用戶選擇預(yù)約日期系統(tǒng)需要在頁(yè)面顯示該日期的剩余可預(yù)約情況。這個(gè)“剩余量”數(shù)據(jù)需要前端調(diào)一個(gè)接口去后端查詢。查詢到之后再讓用戶選擇參觀人數(shù)校驗(yàn)不超過(guò)剩余限額最后提交預(yù)約。整個(gè)流程可以做成一個(gè)步驟條組件引導(dǎo)用戶一步步完成操作。個(gè)人中心要展示我提交的預(yù)約列表每條記錄顯示狀態(tài)。注意待確認(rèn)狀態(tài)下的預(yù)約需要顯示“取消預(yù)約”按鈕已確認(rèn)狀態(tài)的預(yù)約可以展示二維碼或者取票碼。哪怕這個(gè)取票碼只是系統(tǒng)自動(dòng)生成的一串編號(hào)沒(méi)有真正的對(duì)接閘機(jī)它也能讓系統(tǒng)看起來(lái)有完整業(yè)務(wù)閉環(huán)。在論文里你可以寫“為已確認(rèn)預(yù)約生成唯一預(yù)約憑證”功能描述上完全說(shuō)得通。4.3 聯(lián)調(diào)時(shí)的關(guān)鍵約定API路徑、數(shù)據(jù)格式、Token注入前后端聯(lián)調(diào)是很多學(xué)生卡殼的地方其實(shí)大部分問(wèn)題都出在沒(méi)有提前約定接口規(guī)范。我這里分享一個(gè)我慣用的約定體系。接口路徑統(tǒng)一以/api開(kāi)頭比如/api/user/login、/api/collection/page。前端所有請(qǐng)求走axios實(shí)例baseURL指向這個(gè)前綴開(kāi)發(fā)環(huán)境通過(guò)Vite的proxy把請(qǐng)求轉(zhuǎn)發(fā)到后端地址// vite.config.js export default defineConfig({ server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } })這個(gè)配置的原理是開(kāi)發(fā)環(huán)境前端跑在5173端口后端跑在8080端口兩者不同源瀏覽器會(huì)攔截跨域請(qǐng)求。通過(guò)代理讓前端的請(qǐng)求先到達(dá)自己的5173端口再由Vite去請(qǐng)求后端從而繞過(guò)瀏覽器同源策略限制。axios請(qǐng)求攔截器統(tǒng)一注入token響應(yīng)攔截器統(tǒng)一處理code不等于200的情況service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] Bearer ${token} } return config }) service.interceptors.response.use( response { const res response.data if (res.code ! 200) { ElMessage.error(res.message) return Promise.reject(new Error(res.message)) } return res }, error { ElMessage.error(網(wǎng)絡(luò)請(qǐng)求異常) return Promise.reject(error) } )這套約定跑通之后聯(lián)調(diào)基本不會(huì)出現(xiàn)“前端拿不到數(shù)據(jù)”“后端說(shuō)前端沒(méi)傳參”這類互相甩鍋的局面。5. 畢業(yè)論文如何把系統(tǒng)實(shí)現(xiàn)寫成有邏輯的論文5.1 論文結(jié)構(gòu)如何映射到系統(tǒng)模塊很多學(xué)生做完系統(tǒng)之后開(kāi)始寫論文發(fā)現(xiàn)寫不出來(lái)或者寫出來(lái)像“系統(tǒng)說(shuō)明書”原因是沒(méi)有建立“論文結(jié)構(gòu)”和“系統(tǒng)結(jié)構(gòu)”的對(duì)應(yīng)關(guān)系。我建議按這個(gè)框架來(lái)走緒論這一章內(nèi)容包括研究的背景和意義博物館數(shù)字化管理的需求、國(guó)內(nèi)外研究現(xiàn)狀這里要寫文獻(xiàn)梳理不能只羅列網(wǎng)址、主要工作與論文組織結(jié)構(gòu)。相關(guān)技術(shù)介紹這一章把SpringBoot、Vue、MyBatis-Plus、JWT、Element Plus各用一個(gè)小節(jié)來(lái)介紹。注意不要寫成百科詞條要寫“為什么在本次系統(tǒng)中選用這項(xiàng)技術(shù)”比如“選用MyBatis-Plus是為了借助其內(nèi)置分頁(yè)插件簡(jiǎn)化數(shù)據(jù)訪問(wèn)層的開(kāi)發(fā)”之類。需求分析這一章從系統(tǒng)角色出發(fā)畫用例圖寫各角色的功能需求。非功能需求也要寫比如安全性密碼加密、Token鑒權(quán)、性能分頁(yè)查詢控制數(shù)據(jù)量、易用性前端操作流程清晰。系統(tǒng)設(shè)計(jì)這一章總體架構(gòu)圖、功能模塊設(shè)計(jì)、數(shù)據(jù)庫(kù)設(shè)計(jì)ER圖和表結(jié)構(gòu)說(shuō)明表、接口設(shè)計(jì)列出主要接口的路徑、請(qǐng)求方式、參數(shù)、返回值。系統(tǒng)實(shí)現(xiàn)這一章分模塊描述每個(gè)功能的實(shí)現(xiàn)配合核心代碼片段和頁(yè)面截圖。系統(tǒng)測(cè)試這一章測(cè)試環(huán)境說(shuō)明、功能測(cè)試用例表、測(cè)試結(jié)果分析。結(jié)論與展望這一章總結(jié)完成的工作指出不足和未來(lái)改進(jìn)方向。5.2 摘要、需求分析、系統(tǒng)設(shè)計(jì)這三章的寫作技巧摘要?jiǎng)e看它放在最前面通常是最后寫的。摘要是全文的微縮版核心邏輯是四句話系統(tǒng)解決什么問(wèn)題系統(tǒng)采用什么技術(shù)系統(tǒng)實(shí)現(xiàn)了哪些功能模塊經(jīng)過(guò)測(cè)試達(dá)到什么效果。第一次不會(huì)寫可以先寫一個(gè)粗糙版本放那兒等正文全部完成之后回頭精煉。需求分析這一章的得分點(diǎn)在于用例圖和數(shù)據(jù)流描述。用例如能用UML工具畫出來(lái)最好畫不出來(lái)的話畫一個(gè)功能結(jié)構(gòu)圖也比純文字強(qiáng)。功能需求描述要寫成“用戶能夠做什么”而不要寫“系統(tǒng)提供了什么按鈕”前者是需求語(yǔ)言后者是說(shuō)明書語(yǔ)言。系統(tǒng)設(shè)計(jì)這一章注意兩點(diǎn)。一是數(shù)據(jù)庫(kù)設(shè)計(jì)不能只貼建表SQL要給字段說(shuō)明表列名、類型、允許為空、說(shuō)明一列列列清楚。二是接口設(shè)計(jì)建議給出一個(gè)接口清單表格把每個(gè)模塊的接口統(tǒng)一列出包括請(qǐng)求類型和功能簡(jiǎn)述。這份表格不需要太細(xì)節(jié)但能直接證明你的系統(tǒng)設(shè)計(jì)是有規(guī)劃的。圖是論文中非常能提升觀感的部分。架構(gòu)圖、ER圖、功能結(jié)構(gòu)圖、預(yù)約流程圖建議多用圖說(shuō)話。畫圖工具不必糾結(jié)能用清楚的就行。5.3 測(cè)試章節(jié)避免流水賬測(cè)試章節(jié)是學(xué)生最容易寫砸的地方。很多人寫“打開(kāi)系統(tǒng)輸入用戶名密碼點(diǎn)擊登錄成功進(jìn)入首頁(yè)”這種寫法既無(wú)技術(shù)含量也無(wú)法體現(xiàn)測(cè)試的嚴(yán)謹(jǐn)性。測(cè)試應(yīng)當(dāng)以用例為單位每個(gè)用例包含用例編號(hào)、測(cè)試名稱、前置條件、操作步驟、預(yù)期結(jié)果、實(shí)際結(jié)果、是否通過(guò)。比如預(yù)約功能可以設(shè)計(jì)這樣的用例前置條件是后臺(tái)已存在一個(gè)正在進(jìn)行的展覽當(dāng)前預(yù)約人數(shù)未滿上限操作是用戶選擇展覽、日期、填寫人數(shù)后提交預(yù)期結(jié)果是預(yù)約成功并生成待確認(rèn)狀態(tài)的預(yù)約記錄。這個(gè)用例可以驗(yàn)證并發(fā)的邏輯。測(cè)試結(jié)論不要只寫“全部通過(guò)”寫上缺陷修復(fù)的過(guò)程更能體現(xiàn)工作量。5.4 截圖素材的收集心得寫論文時(shí)你會(huì)需要大量系統(tǒng)截圖。建議在開(kāi)發(fā)完成之后按照論文的章節(jié)順序統(tǒng)一把所有功能頁(yè)面截圖一遍歸檔到文件夾里。我見(jiàn)過(guò)一些學(xué)生代碼寫完了結(jié)果頁(yè)面上的測(cè)試數(shù)據(jù)亂糟糟截圖也臨時(shí)補(bǔ)效果慘不忍睹。提前準(zhǔn)備一套排版整潔、數(shù)據(jù)合理的截圖數(shù)據(jù)會(huì)讓整個(gè)論文質(zhì)量上一個(gè)臺(tái)階。我在搭建演示環(huán)境時(shí)通常會(huì)在數(shù)據(jù)庫(kù)腳本里預(yù)置一批樣例數(shù)據(jù)包括幾個(gè)朝代分明的藏品、兩個(gè)狀態(tài)不同的展覽以及一條待審核的預(yù)約。演示和截圖都能直接展示出系統(tǒng)的多狀態(tài)效果。6. 搭建過(guò)程中的高頻坑位與排查思路6.1 前端代理跨域時(shí)報(bào)錯(cuò)怎么查搭建時(shí)最常見(jiàn)的現(xiàn)象前端頁(yè)面能打開(kāi)但請(qǐng)求接口就報(bào)錯(cuò)。報(bào)錯(cuò)信息通常是CORS相關(guān)或者404。排查路徑是分層的。第一步先用瀏覽器直接訪問(wèn)后端接口地址比如直接打開(kāi)http://localhost:8080/api/collection/page看能不能返回?cái)?shù)據(jù)。如果后端本身報(bào)錯(cuò)那是代碼問(wèn)題如果后端正常而前端代理失敗那就是代理配置問(wèn)題。第二步檢查前端proxy的target端口是不是后端實(shí)際端口。第三步檢查請(qǐng)求路徑是否被正確拼接比如代理配置的是/api前綴請(qǐng)求寫成了http://localhost:8080/api那就會(huì)被拼成http://localhost:8080/api/api自然404。記住一個(gè)原則前端請(qǐng)求不要寫完整后端地址寫相對(duì)路徑由代理或部署后的網(wǎng)關(guān)來(lái)轉(zhuǎn)發(fā)。6.2 登錄認(rèn)證的死循環(huán)token過(guò)期與攔截器放行JWT相關(guān)的常見(jiàn)坑是登錄接口請(qǐng)求抵達(dá)后端時(shí)JWT攔截器先攔截了它發(fā)現(xiàn)沒(méi)有token返回“未登錄”錯(cuò)誤前端跳轉(zhuǎn)登錄頁(yè)但這就是登錄頁(yè)形成死循環(huán)。解決方案是在攔截器配置里放行登錄接口、注冊(cè)接口和靜態(tài)資源。同時(shí)在前后端約定好凡是接口返回401狀態(tài)碼一律做清空token并跳轉(zhuǎn)登錄頁(yè)處理。這里我還要提示一個(gè)小細(xì)節(jié)響應(yīng)攔截器里要先優(yōu)先處理401再處理code邏輯順序放反了也會(huì)出問(wèn)題。6.3 MyBatis-Plus時(shí)間字段、邏輯刪除和事務(wù)的隱藏坑如果你用了MyBatis-Plus有幾個(gè)細(xì)節(jié)容易踩坑。第一個(gè)是時(shí)間字段的自動(dòng)填充。創(chuàng)建時(shí)間、更新時(shí)間如果每次插入、更新都手動(dòng)set會(huì)非常痛苦。用TableField(fill FieldFill.INSERT)配合MetaObjectHandler實(shí)現(xiàn)自動(dòng)填充代碼會(huì)清爽很多。第二個(gè)是邏輯刪除。配置了TableLogic之后查詢語(yǔ)句會(huì)自動(dòng)拼接deleted0條件這是好事。但如果你在同一張表里用了唯一約束邏輯刪除的用戶再注冊(cè)同一個(gè)用戶名會(huì)報(bào)唯一鍵沖突因?yàn)檫壿媱h除并沒(méi)有物理刪除記錄。解決辦法通常是把唯一鍵改成包含deleted字段的聯(lián)合唯一索引或者注冊(cè)時(shí)先查詢包含已刪除的記錄。這個(gè)坑很少有人提前意識(shí)到但一旦踩到排查時(shí)間會(huì)很久。第三個(gè)是事務(wù)。預(yù)約創(chuàng)建時(shí)要查詢、校驗(yàn)、插入三步如果其中一步失敗之前的操作也應(yīng)該回滾。在方法上加上Transactional注解能在異常時(shí)自動(dòng)回滾數(shù)據(jù)庫(kù)操作。這個(gè)注解的使用在論文測(cè)試章節(jié)也可以作為事務(wù)一致性驗(yàn)證的一個(gè)點(diǎn)來(lái)寫。6.4 演示環(huán)境的數(shù)據(jù)初始化臨近答辯時(shí)你需要一個(gè)可以直接演示的環(huán)境。建議準(zhǔn)備一個(gè)演示數(shù)據(jù)庫(kù)腳本里面包含可用的管理員賬號(hào)、測(cè)試用戶賬號(hào)、若干條規(guī)格完整的藏品數(shù)據(jù)、進(jìn)行中和已結(jié)束的展覽各一個(gè)。開(kāi)啟服務(wù)后打開(kāi)前端登錄、瀏覽、預(yù)約、審核一路點(diǎn)下來(lái)不出錯(cuò)。還要注意靜態(tài)資源的路徑問(wèn)題。如果服務(wù)器換了操作系統(tǒng)上傳目錄的絕對(duì)路徑會(huì)失效盡量把上傳路徑做成可配置項(xiàng)寫在配置文件里。部署時(shí)只需改配置不需要改代碼。涉及文件上傳的演示環(huán)節(jié)最好在答辯前用同樣路徑試一次不然圖片顯示不出來(lái)的尷尬真會(huì)讓人撓頭。7. 寫在最后的實(shí)操體會(huì)如果讓我總結(jié)這套系統(tǒng)的搭建心得排第一位的是順序。先數(shù)據(jù)庫(kù)再后端再前端最后論文這個(gè)順序不是隨便定的每一步都是在為下一步鋪路。數(shù)據(jù)庫(kù)設(shè)計(jì)得不清楚后端代碼就混亂后端接口不定好前端聯(lián)調(diào)就返工系統(tǒng)功能不穩(wěn)定論文截圖就得一直重截。排第二位的是留痕。開(kāi)發(fā)過(guò)程中每一步遇到的問(wèn)題和解決方式建議記錄下來(lái)。畢業(yè)設(shè)計(jì)的論文里測(cè)試章節(jié)和總結(jié)章節(jié)非常需要這些素材。平時(shí)記錄的三言兩語(yǔ)寫論文時(shí)可能就是一段寶貴的內(nèi)容。排第三位的是控制欲望。別覺(jué)得功能越多越好。把核心模塊做扎實(shí)把異常情況處理好比掛一堆用不到的邊緣功能強(qiáng)得多。答辯時(shí)老師最看重的是你對(duì)系統(tǒng)的理解——為什么這么設(shè)計(jì)、遇到問(wèn)題怎么排查、系統(tǒng)有哪些可優(yōu)化之處。這些理解只有自己一行行敲出來(lái)才能真正說(shuō)得明白。最后分享一個(gè)小技巧在預(yù)置樣例數(shù)據(jù)時(shí)把藏品的朝代、材質(zhì)、來(lái)源、尺寸這些字段都填滿、填細(xì)致。一來(lái)頁(yè)面表格顯得專業(yè)二來(lái)論文截圖時(shí)不用手忙腳亂去補(bǔ)數(shù)據(jù)。細(xì)節(jié)上多花十分鐘現(xiàn)場(chǎng)演示觀感完全不同。祝每一個(gè)準(zhǔn)備做這套系統(tǒng)的同學(xué)都能順利走完全程。