設(shè)計(jì)與實(shí)現(xiàn)全攻略)
又到了畢設(shè)季每年這個(gè)時(shí)候后臺(tái)問得最多的就是“有沒有合適的Java選題”。今天要聊的這個(gè)項(xiàng)目——基于SpringBoot的高校師生互選雙選系統(tǒng)屬于典型的“業(yè)務(wù)清晰、技術(shù)覆蓋面廣、工作量適中、答辯有話說”的類型。我用它幫幾個(gè)學(xué)生做過畢業(yè)設(shè)計(jì)也幫企業(yè)做過類似的內(nèi)部評審系統(tǒng)對于其中哪些地方容易踩坑、哪些模塊面試官最愛追問心里還是比較有底的。這套系統(tǒng)解決的核心問題很具體傳統(tǒng)的師生互選依賴線下填表、Excel匯總、人工協(xié)調(diào)效率低還容易出錯(cuò)。把它搬上線之后教師發(fā)布課題、學(xué)生瀏覽申報(bào)、導(dǎo)師確認(rèn)雙向選擇、管理員統(tǒng)一監(jiān)管全部在線完成。作為畢設(shè)項(xiàng)目它同時(shí)覆蓋了用戶角色權(quán)限管理、核心業(yè)務(wù)流轉(zhuǎn)、數(shù)據(jù)關(guān)系設(shè)計(jì)、文件上傳、消息通知等高頻考點(diǎn)可以說是一個(gè)性價(jià)比非常高的選題。這篇文章不打算只講“這個(gè)項(xiàng)目有什么功能”而是從需求拆解、技術(shù)選型、數(shù)據(jù)庫設(shè)計(jì)、核心代碼實(shí)現(xiàn)到常見坑位排查完整過一遍。無論你是準(zhǔn)備拿它當(dāng)畢設(shè)還是打算基于它做課程設(shè)計(jì)照著下面的思路走能省不少事。1. 項(xiàng)目整體設(shè)計(jì)與需求拆解1.1 雙選系統(tǒng)的本質(zhì)是什么高校師生互選場景常見于研究生選導(dǎo)師、本科畢業(yè)設(shè)計(jì)選題、創(chuàng)新項(xiàng)目團(tuán)隊(duì)招募等。雙選的含義是雙向選擇老師發(fā)布課題后學(xué)生遞交申請老師從申請者中確認(rèn)最終人選。這不是簡單的“選課”因?yàn)殡p方都有主動(dòng)權(quán)所以系統(tǒng)的業(yè)務(wù)邏輯相較于普通管理系統(tǒng)更復(fù)雜。把需求拆開看核心角色無非三類教師端發(fā)布課題、查看申請列表、通過/拒絕學(xué)生、錄入確認(rèn)結(jié)果。學(xué)生端瀏覽課題、提交申請、查看狀態(tài)、確認(rèn)導(dǎo)師。管理員端審核用戶、管理院系/專業(yè)數(shù)據(jù)、統(tǒng)計(jì)雙選結(jié)果、全局調(diào)控。很多人第一次做這種系統(tǒng)容易把精力放在“界面好不好看”上實(shí)際上這類系統(tǒng)真正的難點(diǎn)在于狀態(tài)流轉(zhuǎn)一個(gè)課題從“申報(bào)中”到“已選滿”一條申請從“待審核”到“已通過”中間的每一步都必須有明確的權(quán)限約束和狀態(tài)校驗(yàn)。狀態(tài)機(jī)設(shè)計(jì)不清楚到后期聯(lián)調(diào)必然一團(tuán)亂麻。1.2 為什么這個(gè)選題適合做畢設(shè)拋開業(yè)務(wù)價(jià)值不談單從畢設(shè)評審的角度看這個(gè)選題有幾個(gè)天然優(yōu)勢。技術(shù)層面SpringBoot本身就是目前Java后端招聘和面試的絕對主流用它做畢業(yè)設(shè)計(jì)寫不進(jìn)論文里的“隱性收益”是簡歷上多一行“熟練掌握SpringBoot MyBatis-Plus MySQL開發(fā)企業(yè)級Web應(yīng)用”這一行在篩選簡歷時(shí)的分量比堆十個(gè)管理系統(tǒng)都強(qiáng)。業(yè)務(wù)層面師生互選系統(tǒng)具備完整的CRUD、多角色權(quán)限、業(yè)務(wù)狀態(tài)流轉(zhuǎn)、簡單統(tǒng)計(jì)報(bào)表復(fù)雜度剛好卡在“比增刪改查高級又不像電商秒殺那樣難以落地”的位置。論文里能寫出業(yè)務(wù)流程圖、用例圖、時(shí)序圖答辯PPT的素材也豐富。更實(shí)際的一點(diǎn)是這類系統(tǒng)的功能邊界非常清晰不會(huì)被導(dǎo)師質(zhì)疑“工作量不足”也不會(huì)因?yàn)檫^度設(shè)計(jì)導(dǎo)致自己收不住尾。我見過太多人選了“智慧校園平臺(tái)”“云自習(xí)室系統(tǒng)”這類大而全的題目最后做出來四不像。雙選系統(tǒng)這種“小而深、閉環(huán)完整”的選題反而更容易拿高分。1.3 方案選型背后的核心思考確定做這個(gè)系統(tǒng)之后第一個(gè)決策就是技術(shù)棧怎么選。這直接決定了后面開發(fā)的順利程度和論文的技術(shù)含量。我的建議是主體用SpringBoot MyBatis-Plus MySQL權(quán)限用Sa-Token或JWT前端用Vue Element UI或Thymeleaf實(shí)現(xiàn)前后端不分離。很多學(xué)生糾結(jié)要不要上Spring Cloud、Redis、消息隊(duì)列我的態(tài)度很明確畢設(shè)項(xiàng)目的首要目標(biāo)是把核心業(yè)務(wù)做扎實(shí)而不是堆技術(shù)名詞。面試官問到你Redis用在了哪里你支支吾吾說“做了緩存”反而暴露短板。如果你希望系統(tǒng)有點(diǎn)亮點(diǎn)可以選兩個(gè)點(diǎn)做深一是雙選沖突檢測比如同一課題已被確認(rèn)、學(xué)生只能選擇一個(gè)導(dǎo)師的邏輯二是可視化統(tǒng)計(jì)用ECharts展示各專業(yè)雙選進(jìn)度、導(dǎo)師熱門度排行。這兩個(gè)點(diǎn)實(shí)現(xiàn)難度適中但在答辯時(shí)非常加分因?yàn)樗鼈儗儆凇皹I(yè)務(wù)痛點(diǎn)驅(qū)動(dòng)”的設(shè)計(jì)而不是為了用而用。2. 核心數(shù)據(jù)模型與數(shù)據(jù)庫設(shè)計(jì)2.1 業(yè)務(wù)實(shí)體梳理數(shù)據(jù)庫設(shè)計(jì)是一套系統(tǒng)能不能“立住”的地基。雙選系統(tǒng)最核心的實(shí)體有以下幾個(gè)用戶表user包含學(xué)生、教師、管理員三類角色用role字段區(qū)分。教師信息表teacher關(guān)聯(lián)用戶表擴(kuò)展職稱、研究方向、所屬院系等。學(xué)生信息表student關(guān)聯(lián)用戶表擴(kuò)展學(xué)號(hào)、專業(yè)、年級、績點(diǎn)等。課題表topic教師發(fā)布的雙選課題包含標(biāo)題、描述、名額上限、狀態(tài)。選題申請記錄表application學(xué)生提交申請后生成核心狀態(tài)字段貫穿整個(gè)流程。院系專業(yè)表department / major用于數(shù)據(jù)的組織與篩選。這里有一個(gè)很多人忽略的細(xì)節(jié)用戶表最好不要和角色表混在一起設(shè)計(jì)成一個(gè)大而全的表。正確的做法是用戶表只存賬號(hào)、密碼、角色、通用狀態(tài)具體的身份信息放到各自的擴(kuò)展表里。這樣后期如果要把系統(tǒng)擴(kuò)展成“可同時(shí)支持畢業(yè)論文選題和課程設(shè)計(jì)選題”不會(huì)因?yàn)楸斫Y(jié)構(gòu)僵化而返工。2.2 關(guān)鍵表結(jié)構(gòu)設(shè)計(jì)詳解重點(diǎn)講兩張核心表。課題表topic的關(guān)鍵字段建議這樣設(shè)計(jì)字段名類型說明idbigint主鍵teacher_idbigint發(fā)布教師IDtitlevarchar(100)課題名稱descriptiontext課題詳細(xì)要求max_studentsint可選學(xué)生人數(shù)上限selected_countint當(dāng)前已選人數(shù)statustinyint0-未開始 1-申報(bào)中 2-已截止 3-已滿員deadlinedatetime申報(bào)截止時(shí)間create_timedatetime發(fā)布時(shí)間應(yīng)用記錄表application這樣設(shè)計(jì)字段名類型說明idbigint主鍵topic_idbigint申請的課題IDstudent_idbigint申請學(xué)生IDapply_reasonvarchar(500)申請說明/個(gè)人優(yōu)勢statustinyint0-待審核 1-通過 2-拒絕 3-撤回create_timedatetime申請時(shí)間handle_timedatetime教師處理時(shí)間handle_remarkvarchar(255)審核備注2.3 數(shù)據(jù)庫設(shè)計(jì)中的常見坑先說一個(gè)最容易犯的錯(cuò)誤用status字段同時(shí)表達(dá)太多含義。比如有的同學(xué)會(huì)給課題表加一個(gè)“is_deleted”表示邏輯刪除然后又用“status”表示審核狀態(tài)、申報(bào)狀態(tài)、滿員狀態(tài)一個(gè)字段塞了三四種語義代碼里到處都得判空、判斷邊界后期維護(hù)苦不堪言。我的建議是拆開is_deleted獨(dú)立status只表示業(yè)務(wù)狀態(tài)滿員不完全依賴status而是在查詢時(shí)通過selected_count和max_students計(jì)算得出。另一個(gè)坑是缺少唯一約束。雙選系統(tǒng)里“同一學(xué)生對同一課題只能提交一次申請”“一個(gè)學(xué)生最終只能確認(rèn)一個(gè)導(dǎo)師”這類業(yè)務(wù)規(guī)則一定要在數(shù)據(jù)庫層面加上唯一索引否則并發(fā)操作下會(huì)產(chǎn)生臟數(shù)據(jù)。哪怕系統(tǒng)是單機(jī)部署、并發(fā)量極低加了唯一索引也能讓你少寫好幾十行防御代碼實(shí)測非常劃算。還有個(gè)容易被忽略的點(diǎn)是時(shí)間的存儲(chǔ)格式。數(shù)據(jù)庫一律用datetime前端展示格式化交給后端返回DTO不要在前端頁面里東拼西湊地格式化時(shí)間字符串后期改時(shí)區(qū)、改格式時(shí)你會(huì)瘋掉。3. 核心功能模塊的實(shí)現(xiàn)邏輯3.1 用戶認(rèn)證與權(quán)限控制雙選系統(tǒng)有三種角色權(quán)限模型可以用RBAC基于角色的訪問控制來實(shí)現(xiàn)。我的建議是不要自己手寫攔截器去一個(gè)個(gè)判斷角色直接用現(xiàn)成的權(quán)限框架。Sa-Token比Shiro輕量比Spring Security更貼合國內(nèi)開發(fā)習(xí)慣文檔又是中文的上手極快非常適合畢設(shè)項(xiàng)目。具體實(shí)現(xiàn)上幾個(gè)關(guān)鍵點(diǎn)登錄后簽發(fā)token前端每次請求攜帶token后端通過攔截器統(tǒng)一鑒權(quán)。接口級權(quán)限用注解或代碼判斷比如教師接口必須校驗(yàn)當(dāng)前登錄用戶角色為教師。越權(quán)問題必須做學(xué)生端只能操作自己的申請記錄教師端只能操作自己發(fā)布的課題。這是答辯時(shí)的高頻考點(diǎn)數(shù)據(jù)越權(quán)漏洞是很多畢設(shè)的低分點(diǎn)。3.2 教師發(fā)布課題流程教師的操作主線是提交課題 - 審核通過可選 - 學(xué)生可見 - 處理申請。課題發(fā)布時(shí)的幾個(gè)校驗(yàn)點(diǎn)要提前想清楚這些也是測試用例的重點(diǎn)課題名稱和描述不能為空字?jǐn)?shù)限制需要前后端雙重校驗(yàn)。課題名額上限必須大于0且不能超過系統(tǒng)設(shè)定閾值比如最多10人。同一教師同一時(shí)間發(fā)布的“申報(bào)中”課題數(shù)量建議加個(gè)上限比如5個(gè)。這個(gè)限制在真實(shí)場景里很常見但很少有學(xué)生會(huì)想到寫進(jìn)設(shè)計(jì)文檔里會(huì)是很好的加分細(xì)節(jié)。發(fā)布成功后課題初始狀態(tài)為“申報(bào)中”學(xué)生才可見。這里要注意可見性設(shè)計(jì)初審未通過的課題學(xué)生看不到學(xué)生只能看到“申報(bào)中”且未滿員的課題。這個(gè)賬務(wù)邏輯一定要在SQL查詢層控制不要把所有課題返回前端再過濾一是安全性差二是數(shù)據(jù)量大了之后性能會(huì)肉眼可見地下降。3.3 學(xué)生申報(bào)與雙選核心邏輯學(xué)生的操作流程瀏覽課題 - 查看詳情 - 提交申請 - 查看審核狀態(tài) - 雙選成功后確認(rèn)。這個(gè)環(huán)節(jié)是整個(gè)系統(tǒng)的心臟部位有兩個(gè)核心邏輯必須寫清楚。第一個(gè)是防重復(fù)申請。同一學(xué)生對同一課題只能申請一次申請還在“待審核”狀態(tài)時(shí)不能再次提交。實(shí)現(xiàn)時(shí)除了數(shù)據(jù)庫唯一索引兜底業(yè)務(wù)層也需要先做一次查詢判斷并給出友好的提示文案。第二個(gè)是雙選匹配邏輯。我見過很多實(shí)現(xiàn)把“雙選”理解復(fù)雜了其實(shí)核心規(guī)則就是兩條規(guī)則1一個(gè)學(xué)生最終只能成功匹配一個(gè)課題已通過狀態(tài)下不能再申請其他課題。規(guī)則2一個(gè)課題選滿之后自動(dòng)關(guān)閉申報(bào)不再接收新申請。就這兩條規(guī)則足以支撐整個(gè)系統(tǒng)的核心閉環(huán)。額外擴(kuò)展的規(guī)則比如學(xué)生可同時(shí)申報(bào)多個(gè)課題、但只能確認(rèn)一個(gè)可以根據(jù)具體業(yè)務(wù)場景自行設(shè)計(jì)但最終論文里的“雙選”概念必須要落到這兩條規(guī)則的代碼實(shí)現(xiàn)上。實(shí)現(xiàn)學(xué)生申請時(shí)推薦用事務(wù)控制Transactional(rollbackFor Exception.class) public boolean applyTopic(Long studentId, Long topicId, String reason) { // 1. 檢查學(xué)生當(dāng)前是否已有通過的課題 // 2. 檢查課題是否存在且狀態(tài)為“申報(bào)中” // 3. 檢查課題是否已滿員已選人數(shù) 名額上限 // 4. 校驗(yàn)是否重復(fù)申請 // 5. 創(chuàng)建申請記錄 // 6. 課題selected_count加1若達(dá)到上限則更新狀態(tài)為已滿員 // 7. 返回申請結(jié)果 }3.4 教師審核與學(xué)生確認(rèn)的閉環(huán)教師看到學(xué)生的申請列表后可以執(zhí)行“通過”或“拒絕”。這里有一個(gè)很多同學(xué)沒考慮到的細(xì)節(jié)教師通過一個(gè)學(xué)生的申請時(shí)事務(wù)里應(yīng)該把該學(xué)生此前對其他課題的待審核申請全部置為“已撤回”或自動(dòng)失效。不然就會(huì)出現(xiàn)一個(gè)學(xué)生被多個(gè)導(dǎo)師同時(shí)通過的邏輯沖突數(shù)據(jù)上直接亂套。學(xué)生收到“通過”通知后還需要完成最終確認(rèn)這一步也可以簡化為自動(dòng)確認(rèn)。這一步的意義是讓“雙選”名副其實(shí)導(dǎo)師選了你你也要選導(dǎo)師雙向確認(rèn)之后才算正式組隊(duì)成功。從演示效果看這個(gè)環(huán)節(jié)容易被評審老師認(rèn)為是系統(tǒng)的亮點(diǎn)值得細(xì)心打磨。確認(rèn)成功后課題selected_count字段同步更新達(dá)到上限則課題狀態(tài)自動(dòng)變?yōu)椤耙褲M員”。之后如果出現(xiàn)撤回、取消等操作名額要同步回滾這塊的狀態(tài)一致性需要通過事務(wù)保證借著這個(gè)點(diǎn)還能在論文里寫一段“數(shù)據(jù)一致性設(shè)計(jì)”。4. 項(xiàng)目構(gòu)建、部署與調(diào)試全流程4.1 從零搭建SpringBoot工程如果從零開始搭建工程我推薦用Spring Initializrstart.spring.io選擇Java 8或11畢設(shè)環(huán)境里JDK 8依然是最保險(xiǎn)的選擇不推薦追求Java 17SpringBoot版本選2.7.x系列這個(gè)版本穩(wěn)定且網(wǎng)上資料最豐富。如果選3.x要注意javax改成了jakarta一些老教程代碼會(huì)跑不起來無形中給自己挖坑。核心依賴建議spring-boot-starter-webmybatis-plus-boot-startermysql-connector-jlomboksa-token-spring-boot-starter權(quán)限spring-boot-starter-validation參數(shù)校驗(yàn)hutool工具類處理日期/ID生成非常方便項(xiàng)目結(jié)構(gòu)上推薦常用的分包方式com.example.selector ├── controller接口層 ├── service業(yè)務(wù)層 ├── mapper數(shù)據(jù)訪問層 ├── entity實(shí)體類 ├── dto數(shù)據(jù)傳輸對象 ├── vo視圖對象 ├── config配置類 └── common統(tǒng)一返回結(jié)果、異常處理等很多學(xué)生喜歡把全部代碼堆在controller里省事是省事但論文里寫“系統(tǒng)采用分層架構(gòu)設(shè)計(jì)”時(shí)會(huì)非常心虛代碼評審也會(huì)被打低分。分層會(huì)讓單個(gè)類代碼量變多但思路清晰很多這個(gè)時(shí)間值得花。4.2 統(tǒng)一返回結(jié)果與全局異常處理這是SpringBoot項(xiàng)目里最基礎(chǔ)也最值得認(rèn)真做的公共能力。定義一個(gè)Result類作為所有接口的統(tǒng)一返回格式包括code、message、data三個(gè)字段??刂破鞣祷刂等坑肦esult包裝返回示例{ code: 200, message: 操作成功, data: {} }同時(shí)寫一個(gè)RestControllerAdvice全局異常處理器把業(yè)務(wù)異常、參數(shù)校驗(yàn)異常、未知異常分別捕獲并返回友好信息。這樣做的意義不僅是對外表現(xiàn)統(tǒng)一更是讓自己少掉一半頭發(fā)——以后再也不用在每一個(gè)controller里try-catch了代碼清爽到飛起。4.3 本地調(diào)試的關(guān)鍵技巧開發(fā)中調(diào)試數(shù)據(jù)是一個(gè)耗時(shí)大頭。雙選系統(tǒng)涉及多個(gè)角色每次測試都要來回切換賬號(hào)我推薦幾個(gè)實(shí)用技巧。第一寫一個(gè)數(shù)據(jù)初始化CommandLineRunner啟動(dòng)項(xiàng)目時(shí)自動(dòng)插入測試賬號(hào)admin/teacher/student各一個(gè)和幾組測試數(shù)據(jù)這樣不用每次手動(dòng)往數(shù)據(jù)庫填數(shù)據(jù)切換角色調(diào)試效率翻倍。這個(gè)技巧很多學(xué)生沒用過但其實(shí)實(shí)現(xiàn)起來只需要二三十行代碼強(qiáng)烈推薦。第二善用Postman或Apifox。不要只靠瀏覽器URL直接訪問GET接口涉及到POST請求、JSON傳參、token鑒權(quán)用接口調(diào)試工具體驗(yàn)完全不同。Apifox更符合國內(nèi)用戶習(xí)慣可以保存接口用例答辯演示前把所有關(guān)鍵接口調(diào)通并保存成集合現(xiàn)場演示會(huì)非常從容。第三開啟MyBatis-Plus的SQL日志在application.yml里配置mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl這樣控制臺(tái)會(huì)把每一條執(zhí)行的SQL完整打印出來排查“數(shù)據(jù)怎么又查出來為空”“關(guān)聯(lián)查詢怎么失效了”這類問題時(shí)看SQL一眼定位比反復(fù)打斷點(diǎn)快得多。4.4 項(xiàng)目打包與部署演示畢設(shè)最終是需要跑起來給老師演示的建議提前準(zhǔn)備好兩種部署方式。本地演示用mvn clean package打出jar包配合java -jar命令啟動(dòng)瀏覽器訪問即可。這里一定要用Maven打成可執(zhí)行jar不要依賴IDE的run按鈕現(xiàn)場啟動(dòng)萬一IDE崩潰場面會(huì)非常尷尬。如果需要云端或服務(wù)器演示比如異地答辯、遠(yuǎn)程給老師展示可以部署到阿里云/騰訊云的輕量應(yīng)用服務(wù)器上。部署步驟不復(fù)雜裝JDK、裝MySQL、導(dǎo)入sql腳本、上傳jar包、用nohup后臺(tái)啟動(dòng)開放防火墻端口。如果公網(wǎng)IP審查不方便可以用內(nèi)網(wǎng)穿透工具把本地端口映射出去演示效果完全夠用。我見過太多學(xué)生到答辯前一天才開始操心部署的事結(jié)果MySQL密碼忘了、端口被占用、防火墻沒放行各種問題輪番轟炸。正確的做法是開發(fā)中期就跑通一次完整部署流程后續(xù)每做一個(gè)大模塊就在打包環(huán)境里驗(yàn)證一遍到答辯時(shí)部署就是肌肉記憶。5. 常見問題與排查實(shí)錄5.1 啟動(dòng)失敗端口被占用或數(shù)據(jù)庫連不上啟動(dòng)報(bào)Port 8080 was already in use說明8080端口被其他進(jìn)程占用了。Windows下用netstat -ano | findstr 8080查到占用進(jìn)程PID去任務(wù)管理器結(jié)束進(jìn)程即可或者直接在配置文件里把server.port換成一個(gè)冷門端口比如8090。連不上數(shù)據(jù)庫這種問題九成是application.yml里的用戶名密碼、URL參數(shù)寫錯(cuò)了。MySQL 8以上的驅(qū)動(dòng)類名是com.mysql.cj.jdbc.Driver很多教程還在用舊驅(qū)動(dòng)類名這一點(diǎn)要注意。URL里加上useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai避免中文亂碼和時(shí)間錯(cuò)亂。5.2 權(quán)限校驗(yàn)失效沒登錄也能訪問接口接口沒走登錄校驗(yàn)最常見的原因有兩個(gè)。一個(gè)是攔截器或過濾器沒有正確注冊另一個(gè)是放行路徑寫得太寬/**把所有請求都放掉了。注意檢查一下配置里的路徑匹配規(guī)則比如你設(shè)置了/api/**需要鑒權(quán)結(jié)果controller的映射路徑是/user/info那請求根本不會(huì)進(jìn)攔截器的管轄范圍。Sa-Token攔截器的注冊建議單獨(dú)寫一個(gè)配置類不要塞在啟動(dòng)類里。同時(shí)自定義注解比如SaCheckLogin、SaCheckRole(teacher)要確認(rèn)在方法上的位置正確是放在controller方法上而不是service方法上。5.3 數(shù)據(jù)錯(cuò)亂并發(fā)場景下名額超賣如果一個(gè)課題默認(rèn)名額是3個(gè)但是有5個(gè)學(xué)生幾乎同時(shí)提交申請可能會(huì)出現(xiàn)已選人數(shù)超過上限的“超賣”問題。這個(gè)屬于并發(fā)數(shù)據(jù)一致性范疇雖然畢設(shè)的系統(tǒng)要求不高但既然想到了用樂觀鎖或悲觀鎖都可以解決。最簡單的方案是給課題表的selected_count更新加上條件UPDATE topic SET selected_count selected_count 1 WHERE id ? AND selected_count max_students如果更新影響行數(shù)為0說明已滿員事務(wù)回滾提示“課題已選滿”。這個(gè)寫法簡單高效還能作為論文里的“并發(fā)控制設(shè)計(jì)”亮點(diǎn)性價(jià)比極高。5.4 前端頁面跨域請求失敗如果項(xiàng)目是前后端分離Vue端口8080后端端口8080或8090必然存在跨域問題。后端解決跨域有幾種方式最省事的是寫一個(gè)CorsFilter配置類允許指定來源和請求頭Configuration public class CorsConfig { Bean public CorsFilter corsFilter() { CorsConfiguration config new CorsConfiguration(); config.addAllowedOriginPattern(*); config.addAllowedMethod(*); config.addAllowedHeader(*); config.setAllowCredentials(true); UrlBasedCorsConfigurationSource source new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration(/**, config); return new CorsFilter(source); } }注意設(shè)置了allowCredentials(true)時(shí)allowedOrigin不能使用*必須用allowedOriginPattern(*)這是SpringBoot 2.4以后的規(guī)則改動(dòng)很多人卡在跨域這里半天其實(shí)原因就這么簡單。5.5 演示翻車現(xiàn)場口令背不下來最后一個(gè)實(shí)際的忠告。答辯演示時(shí)千萬不要現(xiàn)場打開數(shù)據(jù)庫去查密碼也不要登錄頁面一遍遍試。提前把三個(gè)角色的測試賬號(hào)密碼寫在演示腳本里最好是admin/123456、teacher01/123456、student01/123456這種規(guī)律性強(qiáng)、不會(huì)記錯(cuò)的組合。數(shù)據(jù)庫初始化腳本里就用這些賬號(hào)演示時(shí)一分鐘進(jìn)入系統(tǒng)把核心流程走完剩下的時(shí)間留給老師提問這才是最穩(wěn)的演示節(jié)奏。寫在最后根據(jù)我?guī)н^的多屆畢設(shè)經(jīng)驗(yàn)這套基于SpringBoot的高校師生互選雙選系統(tǒng)最大的價(jià)值在于用適中的復(fù)雜度覆蓋了Java Web開發(fā)的主要知識(shí)面三層架構(gòu)、數(shù)據(jù)庫設(shè)計(jì)、權(quán)限管理、事務(wù)控制、異常處理、接口規(guī)范每一塊都是面試和工作中真正要用的能力。跟著完整走一遍你不只是在完成一個(gè)畢設(shè)而是在把Java后端開發(fā)的整個(gè)骨架摸一遍——這些經(jīng)驗(yàn)寫在簡歷里比那個(gè)“項(xiàng)目名稱”要實(shí)在得多。如果后續(xù)時(shí)間充裕這個(gè)系統(tǒng)還可以繼續(xù)往兩個(gè)方向擴(kuò)展一是接入消息通知學(xué)生提交申請后教師收到郵件或站內(nèi)信提醒二是增加Excel導(dǎo)出功能管理員一鍵導(dǎo)出全校雙選結(jié)果報(bào)表。這兩個(gè)功能實(shí)現(xiàn)難度不高但對系統(tǒng)的“完整度”提升非常明顯。先把這個(gè)基礎(chǔ)版本做扎實(shí)后面的路自然就寬了。