開(kāi)發(fā):基于SpringBoot+Vue的工程教育認(rèn)證實(shí)戰(zhàn))
做了這么多年的教學(xué)管理類(lèi)系統(tǒng)我最大的感受是課程管理平臺(tái)聽(tīng)起來(lái)像學(xué)校里最簡(jiǎn)單的信息系統(tǒng)但真做進(jìn)去才會(huì)發(fā)現(xiàn)它最難的不是頁(yè)面長(zhǎng)什么樣而是一開(kāi)始就要想清楚“這個(gè)系統(tǒng)到底要管理什么”。如果只是做成課程、成績(jī)的電子登記表那用一張Excel就夠了根本不需要前后端分離加一堆權(quán)限設(shè)計(jì)。這里要說(shuō)的工程教育認(rèn)證就是計(jì)算機(jī)類(lèi)專(zhuān)業(yè)申請(qǐng)工程教育認(rèn)證時(shí)專(zhuān)家需要看到一套完整的教學(xué)過(guò)程證據(jù)鏈課程目標(biāo)是否支撐了畢業(yè)要求指標(biāo)點(diǎn)每門(mén)課的考核是否覆蓋了課程目標(biāo)期末的達(dá)成度計(jì)算是不是合理以及所有數(shù)據(jù)能不能一環(huán)扣一環(huán)地追溯。用表格手工填填到第三門(mén)課基本就會(huì)亂套。所以當(dāng)時(shí)在某高校的信息化項(xiàng)目里做這套“前后端分離的工程教育認(rèn)證計(jì)算機(jī)課程管理平臺(tái)”時(shí)我給自己定的第一原則是所有數(shù)據(jù)必須能由系統(tǒng)自動(dòng)串成一條證據(jù)鏈而不是又多了一個(gè)數(shù)據(jù)堆積工具。這套系統(tǒng)后端是SpringBoot MyBatis MySQL前端用Vue走JWT登錄鑒權(quán)支持管理員、教師、學(xué)生三類(lèi)角色。核心功能覆蓋課程庫(kù)維護(hù)、課程目標(biāo)與畢業(yè)要求指標(biāo)點(diǎn)關(guān)聯(lián)、考核權(quán)重配置、成績(jī)錄入、課程目標(biāo)達(dá)成度自動(dòng)計(jì)算、認(rèn)證材料導(dǎo)出等。如果你是正在做教學(xué)類(lèi)系統(tǒng)開(kāi)發(fā)、想學(xué)習(xí)前后端分離項(xiàng)目從零落地到部署的完整流程或者正在為工程認(rèn)證整理教學(xué)數(shù)據(jù)這篇內(nèi)容應(yīng)該能給你一份可以照抄的操作手冊(cè)。1. 系統(tǒng)定位先想清楚認(rèn)證要的“證據(jù)鏈”再談建系統(tǒng)1.1 傳統(tǒng)做法為什么撐不起認(rèn)證材料在做這套系統(tǒng)之前我特意看了某高校計(jì)算機(jī)專(zhuān)業(yè)一個(gè)學(xué)期的實(shí)際數(shù)據(jù)。一位講師帶兩門(mén)課期末結(jié)束后要同時(shí)整理四份材料課程目標(biāo)達(dá)成情況分析、期末試卷分析、過(guò)程性考核記錄、持續(xù)改進(jìn)說(shuō)明。這些數(shù)據(jù)散落在Excel、教務(wù)系統(tǒng)、紙質(zhì)實(shí)驗(yàn)報(bào)告里。算一門(mén)課的直接評(píng)估值需要先把所有學(xué)生成績(jī)按課程目標(biāo)拆開(kāi)再用表格函數(shù)匹配權(quán)重最后做加權(quán)平均。一門(mén)課算大半天算完之后還要擔(dān)心口徑是不是統(tǒng)一。這其實(shí)是工程認(rèn)證里最典型的痛點(diǎn)尤其在OBE理念下專(zhuān)家現(xiàn)場(chǎng)強(qiáng)調(diào)的正是“舉證閉環(huán)”。他隨時(shí)會(huì)問(wèn)你這門(mén)課有幾個(gè)課程目標(biāo)每個(gè)課程目標(biāo)靠哪些考核環(huán)節(jié)支撐學(xué)生每個(gè)環(huán)節(jié)的平均表現(xiàn)是多少最終達(dá)成度是怎么算出來(lái)的有沒(méi)有低于期望值的目標(biāo)對(duì)應(yīng)的改進(jìn)記錄在哪里如果系統(tǒng)只能錄入成績(jī)、查詢成績(jī)它根本回答不了這一連串問(wèn)題。所以這套系統(tǒng)的本質(zhì)不是替代教務(wù)系統(tǒng)而是做一套面向認(rèn)證邏輯的教學(xué)過(guò)程管理工具。它的核心設(shè)計(jì)圍繞“評(píng)價(jià)閉環(huán)”展開(kāi)數(shù)據(jù)鏈路必須能從上到下完整追溯“培養(yǎng)方案—畢業(yè)要求—指標(biāo)點(diǎn)—課程目標(biāo)—考核環(huán)節(jié)—學(xué)生成績(jī)”。我意識(shí)到這個(gè)邏輯的時(shí)間比較晚最開(kāi)始按普通課表系統(tǒng)的方式來(lái)設(shè)計(jì)數(shù)據(jù)庫(kù)結(jié)果后期返工很?chē)?yán)重所以這個(gè)教訓(xùn)值得先寫(xiě)出來(lái)。1.2 這套系統(tǒng)的功能地圖與用戶視角系統(tǒng)按三種角色區(qū)分功能入口權(quán)限邊界很清晰管理員負(fù)責(zé)基礎(chǔ)數(shù)據(jù)維護(hù)包括專(zhuān)業(yè)、班級(jí)、課程、教師賬號(hào)、畢業(yè)要求指標(biāo)點(diǎn)。管理員還能看到所有課程的認(rèn)證準(zhǔn)備狀態(tài)比如哪些課程目標(biāo)沒(méi)有配置權(quán)重、哪些課程沒(méi)有關(guān)聯(lián)指標(biāo)點(diǎn)。這個(gè)“待辦視圖”非常關(guān)鍵認(rèn)證準(zhǔn)備階段最容易漏的就是課程與指標(biāo)點(diǎn)的關(guān)聯(lián)關(guān)系。教師進(jìn)入某門(mén)課程后先維護(hù)課程基本信息、課程目標(biāo)、考核權(quán)重再錄入學(xué)生成績(jī)最后查看達(dá)成度分析報(bào)告。教師不需要理解指標(biāo)點(diǎn)結(jié)構(gòu)是怎么來(lái)的系統(tǒng)在配置權(quán)重時(shí)會(huì)自動(dòng)展示這門(mén)課程關(guān)聯(lián)的指標(biāo)點(diǎn)。學(xué)生查詢自己的課程列表、每門(mén)課每個(gè)課程目標(biāo)的達(dá)成情況、學(xué)期成績(jī)單。很多人會(huì)忽略一個(gè)頁(yè)面但我認(rèn)為它才是這個(gè)系統(tǒng)的價(jià)值擔(dān)當(dāng)“認(rèn)證報(bào)告中心”。支持按專(zhuān)業(yè)、學(xué)期、課程三個(gè)維度導(dǎo)出數(shù)據(jù)導(dǎo)出的內(nèi)容不只是成績(jī)匯總還包括達(dá)成度計(jì)算過(guò)程、權(quán)重配置明細(xì)、考核環(huán)節(jié)得分率。專(zhuān)家審查的時(shí)候這些導(dǎo)出的證明材料比在系統(tǒng)里現(xiàn)場(chǎng)點(diǎn)點(diǎn)更能說(shuō)明問(wèn)題。2. 技術(shù)選型拆解為什么是SpringBootVueMyBatisMySQL這套組合2.1 前后端分離對(duì)這個(gè)場(chǎng)景的價(jià)值高校環(huán)境有一個(gè)特點(diǎn)老師和管理員辦公的網(wǎng)絡(luò)位置不固定。教師可能在辦公室、家里、機(jī)房錄成績(jī)教務(wù)管理員在校內(nèi)審核學(xué)生可能從宿舍訪問(wèn)。前后端分離后前端打包成靜態(tài)文件部署在高性能的Nginx上后端作為獨(dú)立服務(wù)跑在服務(wù)器上動(dòng)靜分離的效果很直接靜態(tài)頁(yè)面由Nginx直接返回請(qǐng)求API才打到后端服務(wù)減少了后端壓力也讓現(xiàn)場(chǎng)部署靈活很多。另一個(gè)價(jià)值是并行開(kāi)發(fā)效率。前端和后端只需要約定好接口格式就能同時(shí)開(kāi)工。這個(gè)項(xiàng)目不算小課程管理、指標(biāo)點(diǎn)管理、成績(jī)錄入、達(dá)成度分析加起來(lái)有二十多個(gè)頁(yè)面。如果按單體JSP方式寫(xiě)模板和Java代碼耦合在一起改一個(gè)頁(yè)面流程就要重啟整個(gè)后端協(xié)作效率太低了。2.2 后端三件套怎么分工SpringBoot沒(méi)有懸念教學(xué)管理系統(tǒng)里最常用的就是它生態(tài)成熟、部署簡(jiǎn)單、社區(qū)資料多。MyBatis雖然常被說(shuō)“老”但在這類(lèi)系統(tǒng)里反倒是優(yōu)點(diǎn)因?yàn)檫_(dá)成度計(jì)算需要寫(xiě)大量的多表聚合SQLMyBatis的原生XML可以精確定義每一條SQL比全自動(dòng)ORM更可控。MySQL則是成本最低的選擇高校里隨便一臺(tái)服務(wù)器就能裝好。補(bǔ)充一個(gè)選型細(xì)節(jié)為什么這個(gè)項(xiàng)目用MyBatis而不是MyBatis-Plus網(wǎng)上很多模板工程默認(rèn)帶Plus但引入后會(huì)有一些不一致的坑比如邏輯刪除字段設(shè)計(jì)沖突、分頁(yè)插件版本不匹配。這個(gè)項(xiàng)目的核心統(tǒng)計(jì)SQL基本都在XML里手寫(xiě)所以從源頭就做了約束所有和認(rèn)證計(jì)算相關(guān)的查詢必須走XML不通過(guò)代碼里的Wrapper拼接。這個(gè)約定保守了一些但后期維護(hù)真的省心。2.3 數(shù)據(jù)庫(kù)設(shè)計(jì)按認(rèn)證邏輯來(lái)組織核心數(shù)據(jù)表大致是下面這一組我在設(shè)計(jì)時(shí)反復(fù)調(diào)整過(guò)最終穩(wěn)定的結(jié)構(gòu)是sys_user用戶表區(qū)分角色course課程表course_objective課程目標(biāo)表outcome_point畢業(yè)要求指標(biāo)點(diǎn)表co_point_relation課程目標(biāo)與指標(biāo)點(diǎn)關(guān)聯(lián)表assessment考核環(huán)節(jié)表比如平時(shí)作業(yè)、實(shí)驗(yàn)、期末score學(xué)生成績(jī)表按考核環(huán)節(jié)記錄colligation_result達(dá)成度計(jì)算結(jié)果表保存歷史結(jié)論課程與課程目標(biāo)是一對(duì)多一個(gè)課程目標(biāo)關(guān)聯(lián)多個(gè)考核環(huán)節(jié)一個(gè)考核環(huán)節(jié)對(duì)應(yīng)一批學(xué)生成績(jī)。指標(biāo)點(diǎn)是獨(dú)立維護(hù)的一組數(shù)據(jù)通過(guò)中間表與課程目標(biāo)關(guān)聯(lián)關(guān)聯(lián)時(shí)帶支撐強(qiáng)度H/M/L。這樣一來(lái)整個(gè)結(jié)構(gòu)就形成了一條干凈的數(shù)據(jù)鏈路課程 → 課程目標(biāo) → 指標(biāo)點(diǎn)課程目標(biāo) → 考核環(huán)節(jié) → 成績(jī)。任意一次達(dá)成度計(jì)算都能從成績(jī)表一路追溯回課程目標(biāo)和指標(biāo)點(diǎn)不會(huì)出現(xiàn)“這個(gè)分?jǐn)?shù)到底是哪來(lái)的”這種尷尬情況。我第一次設(shè)計(jì)時(shí)走過(guò)彎路把課程目標(biāo)直接放進(jìn)課程表加一個(gè)“課程目標(biāo)描述”字段就完事。后來(lái)發(fā)現(xiàn)一個(gè)目標(biāo)要對(duì)應(yīng)多個(gè)考核環(huán)節(jié)、多個(gè)成績(jī)記錄、多個(gè)指標(biāo)點(diǎn)根本不是加字段能解決的只能重新拆表。所以這段經(jīng)歷也可以給你參考如果一開(kāi)始就按認(rèn)證的舉證鏈條來(lái)設(shè)計(jì)后面所有查詢都會(huì)順手得多。3. 核心實(shí)現(xiàn)細(xì)節(jié)認(rèn)證邏輯怎么落地到代碼層3.1 用戶登錄與權(quán)限用JWT做最簡(jiǎn)鑒權(quán)先說(shuō)結(jié)論這種內(nèi)部管理系統(tǒng)不一定要上Spring Security全家桶。Spring Security功能全但配置起來(lái)容易在過(guò)濾鏈上踩坑尤其是前后端分離之后跨域、匿名請(qǐng)求、CSRF關(guān)閉這些配置一不小心就把人繞暈。這里采用JWT加攔截器的方式做一個(gè)可用、可維護(hù)、代碼量可控的登錄鑒權(quán)方案。后端登錄成功后生成token返回給前端前端保存后每次請(qǐng)求通過(guò)axios攔截器自動(dòng)帶上。后端寫(xiě)一個(gè)HandlerInterceptor在preHandle里解析token把用戶信息放入ThreadLocal后續(xù)業(yè)務(wù)方法直接取用盡量避免每層手動(dòng)傳用戶參數(shù)。加起來(lái)代碼量也就一百多行核心邏輯非常直白。有幾個(gè)要點(diǎn)值得注意token中只放userId和role不放密碼等敏感信息。過(guò)期時(shí)間設(shè)置成2小時(shí)內(nèi)部系統(tǒng)太長(zhǎng)不安全。攔截器放行登錄接口和靜態(tài)資源其余接口都要校驗(yàn)。開(kāi)發(fā)時(shí)我還特意加了一個(gè)“測(cè)試模式”配置項(xiàng)開(kāi)啟后跳過(guò)鑒權(quán)方便前端同學(xué)直接拿聯(lián)調(diào)數(shù)據(jù)。這個(gè)配置如果忘了在生產(chǎn)環(huán)境關(guān)閉系統(tǒng)等于對(duì)所有人裸奔這是我真實(shí)踩過(guò)的坑部署前一定要檢查。3.2 課程目標(biāo)與指標(biāo)點(diǎn)關(guān)聯(lián)認(rèn)證系統(tǒng)的靈魂課程目標(biāo)是整個(gè)認(rèn)證體系里的最小可評(píng)價(jià)單元。比如《面向?qū)ο蟪绦蛟O(shè)計(jì)》這門(mén)課可以有這樣幾個(gè)目標(biāo)C01掌握類(lèi)、對(duì)象、繼承與多態(tài)的基本概念能完成簡(jiǎn)單的類(lèi)建模。C02能運(yùn)用面向?qū)ο笏季S分析并實(shí)現(xiàn)小型應(yīng)用系統(tǒng)。C03能使用UML類(lèi)圖描述系統(tǒng)設(shè)計(jì)具備一定的文檔規(guī)范意識(shí)。每個(gè)目標(biāo)都要掛靠畢業(yè)要求的某個(gè)指標(biāo)點(diǎn)。比如C01可以關(guān)聯(lián)到“能夠?qū)⒐こ炭茖W(xué)的基本原理用于復(fù)雜工程問(wèn)題的識(shí)別與表達(dá)”的某個(gè)細(xì)分指標(biāo)點(diǎn)關(guān)聯(lián)強(qiáng)度標(biāo)為中支撐。界面上做的是一個(gè)多對(duì)多選擇器看起來(lái)簡(jiǎn)單但真正的價(jià)值在“完整性校驗(yàn)”。系統(tǒng)會(huì)檢查所有課程目標(biāo)是否至少掛了一個(gè)指標(biāo)點(diǎn)所有指標(biāo)點(diǎn)是否被合理數(shù)量的課程覆蓋。這個(gè)校驗(yàn)邏輯在認(rèn)證材料審查中非常關(guān)鍵而大部分課程管理系統(tǒng)根本沒(méi)做。有了這個(gè)校驗(yàn)教務(wù)管理員才能在認(rèn)證準(zhǔn)備階段快速發(fā)現(xiàn)問(wèn)題而不是到了專(zhuān)家進(jìn)校前一周才開(kāi)始通宵補(bǔ)材料。3.3 達(dá)成度計(jì)算從數(shù)據(jù)庫(kù)查詢到前端可視化達(dá)成度計(jì)算是整個(gè)平臺(tái)的核心亮點(diǎn)采用“加權(quán)得分率”思路。每個(gè)課程目標(biāo)對(duì)應(yīng)若干考核環(huán)節(jié)每個(gè)考核環(huán)節(jié)在課程成績(jī)中占固定比例目標(biāo)達(dá)成度就是各考核環(huán)節(jié)得分率的加權(quán)平均。計(jì)算公式如下達(dá)成度 Σ(考核環(huán)節(jié)得分率 × 考核環(huán)節(jié)權(quán)重) / Σ(考核環(huán)節(jié)權(quán)重)其中得分率 該考核環(huán)節(jié)全班平均得分 / 該考核環(huán)節(jié)滿分。舉一個(gè)實(shí)際例子。課程目標(biāo)C01關(guān)聯(lián)平時(shí)作業(yè)權(quán)重30%滿分100和期末卷面第一題權(quán)重20%滿分20。全班平時(shí)作業(yè)平均84分卷面第一題平均14分那么達(dá)成度 (84/100 × 30% 14/20 × 20%) / (30% 20%) (0.84 × 0.3 0.70 × 0.2) / 0.5 (0.252 0.14) / 0.5 0.784得到的0.784就是該課程目標(biāo)的達(dá)成度。如果教學(xué)團(tuán)隊(duì)設(shè)定的期望值是0.70那這個(gè)目標(biāo)就算達(dá)成如果低于0.70系統(tǒng)會(huì)在報(bào)告里標(biāo)記為未達(dá)成并提示教師填寫(xiě)改進(jìn)措施。對(duì)應(yīng)的SQL實(shí)現(xiàn)也不復(fù)雜核心是按考核環(huán)節(jié)統(tǒng)計(jì)全班平均分。下面這段是簡(jiǎn)化后的Mapper查詢思路SELECT a.id AS assessment_id, a.name AS assessment_name, a.ratio, AVG(s.score) AS avg_score, a.full_score FROM assessment a LEFT JOIN score s ON s.assessment_id a.id WHERE a.objective_id #{objectiveId} GROUP BY a.id, a.name, a.ratio, a.full_score前端拿到接口返回的明細(xì)后我用ECharts畫(huà)達(dá)成度柱狀圖每根柱子對(duì)應(yīng)一個(gè)課程目標(biāo)。達(dá)到期望值的用綠色未達(dá)到的用紅色下方附“持續(xù)改進(jìn)意見(jiàn)”輸入框。教師確認(rèn)后生成該學(xué)期該課程的達(dá)成度結(jié)論寫(xiě)入colligation_result表形成歷史檔案。認(rèn)證專(zhuān)家要看的其實(shí)就是這張圖加對(duì)應(yīng)的計(jì)算過(guò)程。3.4 成績(jī)錄入與過(guò)程材料管理這個(gè)模塊技術(shù)含量不高但使用頻率最高。教師可以按考核環(huán)節(jié)錄入班級(jí)成績(jī)支持按學(xué)生批量粘貼、從Excel一次性導(dǎo)入、單條修改。錄入時(shí)前端做一輪輸入校驗(yàn)成績(jī)范圍限定在0到滿分超出直接標(biāo)紅避免臟數(shù)據(jù)進(jìn)庫(kù)。導(dǎo)入Excel有一個(gè)隱藏的坑學(xué)生學(xué)號(hào)是文本格式但Excel經(jīng)常自動(dòng)轉(zhuǎn)成科學(xué)計(jì)數(shù)法。前端讀取Excel文件時(shí)必須把學(xué)號(hào)列強(qiáng)制按字符串解析。如果少了這一步會(huì)出現(xiàn)學(xué)生成績(jī)記錄錯(cuò)位而且排查難度非常大因?yàn)楸砻嫔峡疵啃卸加袛?shù)據(jù)。成績(jī)錄入完成后系統(tǒng)自動(dòng)統(tǒng)計(jì)每個(gè)學(xué)生的“目標(biāo)得分明細(xì)”也就是這名學(xué)生在每個(gè)課程目標(biāo)下各項(xiàng)考核的得分以及合成后的目標(biāo)得分。這個(gè)能力是認(rèn)證材料里“學(xué)生個(gè)體達(dá)成情況”的基礎(chǔ)也是做學(xué)業(yè)預(yù)警的依據(jù)。看到某個(gè)學(xué)生的某項(xiàng)課程目標(biāo)得分明顯偏低系統(tǒng)會(huì)給教師彈出一條提示方便教師及時(shí)關(guān)注。4. 從開(kāi)發(fā)機(jī)到服務(wù)器可復(fù)用的部署實(shí)戰(zhàn)記錄4.1 本地開(kāi)發(fā)環(huán)境準(zhǔn)備與前后端聯(lián)調(diào)先列一份版本建議可以直接照抄JDK8或17都可以我推薦17內(nèi)存和性能表現(xiàn)更好。Maven3.8以上配置國(guó)內(nèi)鏡像倉(cāng)庫(kù)會(huì)快很多。MySQL8.0以上安裝時(shí)字符集選utf8mb4。Node.js16以上Vue工程構(gòu)建需要。前端開(kāi)發(fā)默認(rèn)端口是5173后端服務(wù)端口是8080。后端啟動(dòng)前要修改application.yml里的數(shù)據(jù)庫(kù)連接、JWT密鑰確認(rèn)MySQL里已經(jīng)導(dǎo)入初始化SQL腳本。啟動(dòng)命令mvn spring-boot:run前端進(jìn)入項(xiàng)目目錄后執(zhí)行npm install npm run dev聯(lián)調(diào)時(shí)要特別注意跨域。開(kāi)發(fā)環(huán)境前后端端口不同Vue工程里配置了Vite代理把/api開(kāi)頭的請(qǐng)求轉(zhuǎn)發(fā)到后端8080。這樣比在后端開(kāi)放CORS更安全調(diào)試也方便。等發(fā)布到生產(chǎn)環(huán)境這個(gè)代理就不需要了由Nginx統(tǒng)一做轉(zhuǎn)發(fā)。4.2 Linux服務(wù)器上的生產(chǎn)部署生產(chǎn)環(huán)境我建議用一臺(tái)Linux服務(wù)器前端靜態(tài)文件由Nginx托管后端jar包用systemd托管。這樣無(wú)論是開(kāi)機(jī)自啟還是查看日志都比較方便。后端打包mvn clean package -DskipTests java -jar target/course-auth-platform.jar \ --spring.config.location/opt/course-auth/application.yml前端打包npm run build # dist目錄生成后復(fù)制到 /usr/share/nginx/course-auth/Nginx配置參考server { listen 80; server_name your-domain.com; location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location / { root /usr/share/nginx/course-auth; index index.html; try_files $uri $uri/ /index.html; } }注意Vue的history路由模式必須配合try_files否則用戶訪問(wèn)子路徑后刷新頁(yè)面就會(huì)404。這個(gè)問(wèn)題我見(jiàn)過(guò)太多次了部署文檔里一定要提醒自己。4.3 數(shù)據(jù)庫(kù)初始化與部署后的復(fù)查清單初始化SQL腳本要按順序執(zhí)行先建表再插入管理員賬號(hào)和基礎(chǔ)字典數(shù)據(jù)最后插入測(cè)試課程數(shù)據(jù)。字符集統(tǒng)一用utf8mb4否則部分課程目標(biāo)描述里的特殊符號(hào)可能存不進(jìn)去。部署完成后至少?gòu)?fù)查這幾項(xiàng)后端日志是否報(bào)數(shù)據(jù)庫(kù)連接失敗重點(diǎn)檢查時(shí)區(qū)配置。Nginx是否能正常訪問(wèn)/api請(qǐng)求是否成功轉(zhuǎn)發(fā)到后端。管理員賬號(hào)能否登錄菜單權(quán)限是否完整。打開(kāi)任意課程詳情頁(yè)確認(rèn)課程目標(biāo)、考核權(quán)重、指標(biāo)點(diǎn)關(guān)聯(lián)都有數(shù)據(jù)。按這個(gè)順序操作整個(gè)平臺(tái)從零到可用大概就是一小時(shí)左右。5. 常見(jiàn)問(wèn)題與排查經(jīng)驗(yàn)實(shí)錄5.1 跨域和登錄失效問(wèn)題前端訪問(wèn)接口時(shí)報(bào)跨域錯(cuò)誤原因通常是后端沒(méi)有放行預(yù)檢請(qǐng)求。攔截器里要顯式放行OPTIONS方法否則瀏覽器預(yù)檢失敗接口直接被攔。JWT過(guò)期后前端不會(huì)自動(dòng)跳登錄頁(yè)需要在axios響應(yīng)攔截器里判斷401狀態(tài)碼然后清除本地token并跳轉(zhuǎn)登錄。千萬(wàn)別把這個(gè)邏輯散落到各個(gè)頁(yè)面里否則后續(xù)維護(hù)會(huì)非常痛苦。5.2 MySQL驅(qū)動(dòng)與MyBatis配置的兼容MySQL 8.0的驅(qū)動(dòng)類(lèi)是com.mysql.cj.jdbc.Driver老配置里寫(xiě)的com.mysql.jdbc.Driver會(huì)直接啟動(dòng)失敗。另外 MyBatis的ResultMap字段映射默認(rèn)不支持下劃線轉(zhuǎn)駝峰需要在application.yml里開(kāi)啟mapUnderscoreToCamelCase否則數(shù)據(jù)庫(kù)查詢結(jié)果里一堆字段名對(duì)不上排查起來(lái)很容易頭大。5.3 達(dá)成度數(shù)據(jù)異常的處理思路如果算出來(lái)的達(dá)成度大于1大概率是權(quán)重沒(méi)有歸一化或者某個(gè)考核環(huán)節(jié)的滿分設(shè)置錯(cuò)誤。排查時(shí)先看每個(gè)考核環(huán)節(jié)的得分率是否都小于等于1再看權(quán)重之和是否接近1。這里有個(gè)非常有效的驗(yàn)證手段開(kāi)發(fā)階段準(zhǔn)備一門(mén)真實(shí)課程先用Excel手算一遍達(dá)成度再用系統(tǒng)輸出同一個(gè)結(jié)果做比對(duì)。兩邊數(shù)據(jù)一致后后續(xù)調(diào)整邏輯就有對(duì)照了。5.4 并發(fā)與數(shù)據(jù)量問(wèn)題高校的選課高峰一般集中在開(kāi)學(xué)頭兩周最多幾百人同時(shí)在線壓力其實(shí)不大。真正的壓力在學(xué)期末教師批量導(dǎo)入成績(jī)時(shí)會(huì)有大量INSERT操作。解決方法是控制單次批量提交行數(shù)比如每次200條分批插入。數(shù)據(jù)庫(kù)連接池用默認(rèn)配置撐住幾百個(gè)并發(fā)完全夠用不需要額外折騰。6. 寫(xiě)在最后壓測(cè)過(guò)了材料也交掉了我的幾點(diǎn)真實(shí)體會(huì)系統(tǒng)做完之后我反而覺(jué)得最值得回味的不是技術(shù)本身。這套課程管理平臺(tái)的技術(shù)難度沒(méi)有特別高真正的難點(diǎn)是在前期和教務(wù)處、任課老師反復(fù)確認(rèn)“認(rèn)證到底要什么”。我第一次搭好框架之后發(fā)現(xiàn)課程目標(biāo)和指標(biāo)點(diǎn)的關(guān)聯(lián)方向設(shè)計(jì)反了導(dǎo)致后面統(tǒng)計(jì)邏輯全部要改只能重新調(diào)整數(shù)據(jù)模型。所以這里有一個(gè)很實(shí)際的建議動(dòng)手寫(xiě)代碼之前先讓專(zhuān)業(yè)負(fù)責(zé)人挑一門(mén)真實(shí)課程按系統(tǒng)邏輯手算一遍達(dá)成度用Excel把結(jié)果算清楚再讓系統(tǒng)去復(fù)現(xiàn)這個(gè)結(jié)果。流程先跑通一次后面寫(xiě)代碼其實(shí)只是把這個(gè)流程自動(dòng)化而已。另一個(gè)經(jīng)驗(yàn)是這類(lèi)系統(tǒng)要同時(shí)留好“數(shù)據(jù)導(dǎo)入”和“數(shù)據(jù)導(dǎo)出”兩個(gè)口子。實(shí)際使用中老師更愿意在系統(tǒng)里改數(shù)據(jù)但期末填表時(shí)一定需要能導(dǎo)出一份標(biāo)準(zhǔn)的認(rèn)證表格。如果不做導(dǎo)出功能系統(tǒng)會(huì)被慢慢棄用因?yàn)槔蠋熃徊牧蠒r(shí)還得回到Excel世界。未來(lái)如果繼續(xù)擴(kuò)展可以做自動(dòng)生成持續(xù)改進(jìn)報(bào)告、對(duì)接學(xué)校統(tǒng)一身份認(rèn)證、增加學(xué)生問(wèn)卷調(diào)查與課程目標(biāo)的映射。不過(guò)這些都是錦上添花先把每門(mén)課的達(dá)成度算清楚、算正確這套系統(tǒng)的價(jià)值就已經(jīng)落地了。把這些過(guò)程記下來(lái)的目的只有一個(gè)等你真正上手做同類(lèi)系統(tǒng)時(shí)能少走一次彎路。