習(xí)網(wǎng)站開發(fā)全流程:從需求分析到上線部署實戰(zhàn))
每年這時候都有不少朋友來問畢設(shè)選題尤其是計算機科學(xué)與技術(shù)方向十個里有六七個想做學(xué)習(xí)類網(wǎng)站。這個方向確實討巧需求清晰、技術(shù)棧通用、演示效果直觀但正因為做的人多反而容易做成一堆功能堆砌的課程列表頁。我前段時間剛完成一個編號為m248的項目——計算機科學(xué)與技術(shù)學(xué)習(xí)網(wǎng)站的設(shè)計與開發(fā)從需求分析到部署上線完整走了一遍有些經(jīng)驗值得拿出來聊聊。這個網(wǎng)站的核心定位不是做一個放視頻的課件站而是把課程檢索、學(xué)習(xí)路線、在線練習(xí)、個人筆記幾個環(huán)節(jié)串起來讓一個剛接觸計算機的新手或者想系統(tǒng)補基礎(chǔ)的同學(xué)能沿著一條明確路徑往前走。整個開發(fā)周期大約六周技術(shù)棧選了Spring Boot加Vue的前后端分離方案數(shù)據(jù)庫用的MySQL另外用Redis做緩存和會話管理。這篇文章會把設(shè)計思路、模塊實現(xiàn)、踩過的坑、以及上線后的運營細節(jié)都攤開講適合正在做類似畢設(shè)、或者想自己搭一個學(xué)習(xí)站點的同學(xué)參考。1. 這個學(xué)習(xí)網(wǎng)站到底解決什么問題從用戶痛點倒推需求動手寫第一行代碼之前最該想清楚的是網(wǎng)站給誰用、解決什么具體問題。我見過太多同類項目一上來就堆課程分類、視頻播放、論壇討論最后界面長得像低配版慕課網(wǎng)但用戶根本不知道從哪里開始學(xué)。做學(xué)習(xí)網(wǎng)站最核心的價值不是提供資源而是提供路徑。1.1 目標(biāo)用戶畫像與核心痛點我做需求分析時把目標(biāo)用戶分成三類各自的痛點非常不一樣計算機專業(yè)低年級本科生大一、大二剛接觸編程學(xué)校課程按學(xué)期推進但很多人在數(shù)據(jù)結(jié)構(gòu)、操作系統(tǒng)這類核心課上跟不上需要課外補充學(xué)習(xí)資料。他們的痛點是資料太多、不知道按什么順序看。轉(zhuǎn)碼自學(xué)者非科班出身想通過自學(xué)進入開發(fā)行業(yè)。這類人往往不缺學(xué)習(xí)資源和教程缺的是系統(tǒng)性的路線圖和能檢驗學(xué)習(xí)效果的練習(xí)題。課程設(shè)計/期末復(fù)習(xí)人群需要快速查找特定知識點比如二叉樹遍歷HTTP狀態(tài)碼希望有精準(zhǔn)的搜索結(jié)果和精簡的總結(jié)。三類人群交集明顯都需要結(jié)構(gòu)化內(nèi)容 可驗證的學(xué)習(xí)成果。所以我把網(wǎng)站定位為學(xué)習(xí)路徑 內(nèi)容檢索 在線練習(xí)三位一體的工具型站點而不是又一個視頻點播平臺。1.2 功能需求收斂砍掉哪些、留住哪些初期我列了十多個功能點包括視頻彈幕、論壇、積分商城、在線聊天后來全部砍掉。保留下來并且最終做出來的只有五個模塊模塊解決的問題關(guān)鍵功能課程中心知識獲取課程分類、關(guān)鍵詞檢索、章節(jié)內(nèi)容瀏覽學(xué)習(xí)路線學(xué)習(xí)路徑按階段展示路線節(jié)點、節(jié)點進度標(biāo)記在線評測學(xué)習(xí)效果驗證精選練習(xí)題目、代碼提交、自動判題學(xué)習(xí)筆記知識沉淀個人筆記寫、改、刪、按課程歸類后臺管理內(nèi)容維護課程/題目/路線圖的增刪改查、用戶管理砍功能的原則很簡單每一項功能必須能回答用戶使用它的頻率有多高和沒有它會不會影響核心體驗。視頻彈幕這種功能做出來熱鬧但和學(xué)習(xí)效率這個核心價值沒有強關(guān)聯(lián)反而是在線評測這種看起來不顯眼的功能對學(xué)習(xí)效果的提升是實打?qū)嵉摹J聦嵶C明最后演示的時候評委最感興趣的也是自動判題這個模塊。2. 技術(shù)選型的取舍邏輯一個人開發(fā)也要考慮未來有人維護技術(shù)選型是這類項目最容易糾結(jié)的環(huán)節(jié)。選太熱門的怕爛大街選太冷門的怕出問題沒人幫忙。我的結(jié)論是在成熟生態(tài)里挑一套自己最熟悉的組合比追求技術(shù)新穎更重要。2.1 前后端方案對比與最終選擇主選方案是Spring Boot 3 Vue 3 MySQL 8備選方案是Python Flask/Django Vue SQLite/MySQL。兩者的取舍我做了個簡單對比對比維度Java Spring Boot方案Python方案上手成本中高需要理解Bean、依賴注入等概念低Flask幾十行能跑起服務(wù)生態(tài)成熟度高企業(yè)級應(yīng)用廣泛遇到問題容易搜到答案高但偏腳本場景重型業(yè)務(wù)少代碼執(zhí)行/判題支持多語言編譯執(zhí)行方便javac/gcc等進程管理成熟執(zhí)行子進程也方便但并發(fā)和資源隔離要小心答辯友好度高評審普遍認(rèn)可Spring全家桶中視評審老師偏好而定部署成本稍高要裝JDK、打jar包低pip依賴裝完就能跑最終選了Spring Boot主要是因為畢設(shè)場景下可預(yù)測性優(yōu)先。Java的生態(tài)太龐大了遇到前端跨域、Redis連接、文件上傳這類問題網(wǎng)上隨便一搜就是完整的解決方案不太會在環(huán)境層面卡住。另外在線評測模塊需要調(diào)用外部編譯器比如javac、gcc、pythonJava在管理子進程、限制資源占用比如超時、內(nèi)存上限方面的做法更成熟這一點在后面的開發(fā)中確實省了很多事。2.2 關(guān)鍵依賴組件清單除了主框架我還選了幾個配套組件這里列一下選型和理由Redis 6.x做登錄會話緩存、課程點擊量緩存。邏輯上Session原來可以放服務(wù)器內(nèi)存但考慮到將來可能部署到多實例用Redis屬于現(xiàn)在麻煩一點、以后少改架構(gòu)的決策。MySQL 8 Nginx數(shù)據(jù)持久化和靜態(tài)資源/CDN入口。MySQL的全文索引ngram parser在搜索功能里幫了大忙這個后面細說。MyBatis-Plus數(shù)據(jù)訪問層。比純MyBatis少寫很多CRUD樣板代碼尤其在后臺管理的增刪改查上效率提升明顯。前端用Vite構(gòu)建 Element Plus組件庫Element Plus的后臺表格、表單、樹形控件都是現(xiàn)成的能保住開發(fā)進度。提示選型階段一定要寫一個簡單的技術(shù)選型說明文檔把每個組件用來解決什么問題寫清楚。答辯的時候老師幾乎必問為什么用Redis為什么不用MongoDB提前準(zhǔn)備好理由比到時候現(xiàn)想強得多。3. 核心功能模塊設(shè)計與實現(xiàn)順序先做骨架再填血肉功能實現(xiàn)順序我建議按用戶主路徑來排先讓他能瀏覽課程內(nèi)容再給他路線圖和練習(xí)最后才是個人筆記和后臺管理。這樣每一步做完都能跑起來看到效果不會出現(xiàn)開發(fā)兩個月、聯(lián)調(diào)才崩的窘境。3.1 數(shù)據(jù)庫設(shè)計五張核心表一張路線表數(shù)據(jù)庫設(shè)計是這類項目的地基。我建的核心表如下字段設(shè)計考慮了擴展性表名核心字段作用usersid, username, password_hash, role用戶認(rèn)證與權(quán)限區(qū)分categoriesid, name, parent_id, sort_order課程分類樹coursesid, category_id, title, summary, cover_url課程基本信息course_chaptersid, course_id, title, content_html, sort_order章節(jié)內(nèi)容problemsid, title, description, input_desc, output_desc, difficulty練習(xí)題目描述learning_path_nodesid, title, description, order_index, link_type, link_id學(xué)習(xí)路線節(jié)點judge_recordsid, user_id, problem_id, code, language, status, execute_time提交與判題記錄notesid, user_id, course_id, title, content_markdown個人學(xué)習(xí)筆記這里想特別說一下learning_path_nodes這張表的設(shè)計。學(xué)習(xí)路線本質(zhì)上是一個有向無環(huán)圖節(jié)點之間有依賴關(guān)系比如學(xué)完數(shù)據(jù)結(jié)構(gòu)再學(xué)算法。我最初想用鄰接表存節(jié)點關(guān)系后來發(fā)現(xiàn)對學(xué)習(xí)路線來說線性序列 階段分組就夠用了。每個節(jié)點存一個order_index前端按這個排序渲染時間線后臺調(diào)整順序只需要改這個字段。真要做復(fù)雜的課程依賴判斷比如必須先修完課程A才能解鎖課程B再用單獨的依賴表也不遲前期不做過度設(shè)計。3.2 課程中心搜索是門面分類樹是骨架課程中心是整個網(wǎng)站訪問量最大的頁面實現(xiàn)上分兩部分分類瀏覽和關(guān)鍵詞搜索。分類瀏覽用兩級分類就夠了一級是編程語言數(shù)據(jù)結(jié)構(gòu)操作系統(tǒng)計算機網(wǎng)絡(luò)數(shù)據(jù)庫這樣的大類二級是具體課程或?qū)n}。前端渲染分類樹用遞歸組件數(shù)據(jù)一次從后端取完不搞懶加載減少請求次數(shù)。搜索是重點也是坑點。剛開始我用的是 MySQL 的LIKE %關(guān)鍵詞%課程少的時候沒問題但數(shù)據(jù)量上來之后有兩個問題一是性能差不能走索引全表掃描二是匹配不聰明搜二分查找匹配不到標(biāo)題為Binary Search 算法詳解的課程。后來改成 MySQL 全文索引配合 ngram 解析器ALTER TABLE courses ADD FULLTEXT INDEX ft_course_title (title) WITH PARSER ngram;查詢時用MATCH(title) AGAINST(二分查找 IN NATURAL LANGUAGE MODE)中英文混合的內(nèi)容也能正確匹配。課程數(shù)量級在幾萬條以內(nèi)MySQL全文索引完全夠用沒必要上Elasticsearch運維成本高不少。課程詳情頁除了展示章節(jié)內(nèi)容我還加了一個相關(guān)課程推薦的邏輯按同一分類下點擊量排序取前五條。這個功能雖然簡單但對用戶體驗的提升很明顯讓用戶在看完一節(jié)課之后有地方可以去而不是關(guān)掉頁面。3.3 在線評測最費心也是最有亮點的一塊在線評測模塊是整個網(wǎng)站技術(shù)含量最高的部分也是答辯時老師問得最多的地方。核心流程是用戶提交代碼 → 后端調(diào)用相應(yīng)語言的編譯器/解釋器 → 在受控環(huán)境中運行 → 比對輸出 → 返回結(jié)果。整個流程我簡化成四個環(huán)節(jié)第一代碼執(zhí)行。后端接收入?yún)⒑蟀汛a寫入臨時文件調(diào)用javac、gcc、python等命令編譯執(zhí)行。判題用例放在受限目錄運行時把用戶程序的輸出重定向到臨時文件然后和答案文件比對。第二資源限制。這是必須做的否則一個惡意死循環(huán)就能把服務(wù)器拖垮。我用了兩層防護外層在調(diào)用層設(shè)置超時一般單用例 3 秒內(nèi)層用操作系統(tǒng)的資源限制功能限制進程 CPU 時間和內(nèi)存subprocess.run( [command, code_file, input_file], capture_outputTrue, timeout10, preexec_fnlimit_resources )Java端也有對應(yīng)的方案用ProcessBuilder起子進程配合destroyForcibly()做超時兜底。第三安全隔離。說實話讓用戶提交任意代碼在服務(wù)器上執(zhí)行還是有風(fēng)險的。演示環(huán)境里我用 Docker 容器做隔離每個判題請求起一個臨時容器跑完直接銷毀。雖然資源開銷大但安全性能保證。如果實在不想引入Docker至少要做到禁止用戶提交Shell腳本、限制可執(zhí)行文件路徑白名單、以低權(quán)限用戶運行判題進程。第四結(jié)果反饋。判題結(jié)果不只是通過/不通過我會給用戶展示編譯錯誤信息、運行超時提示、第一個不匹配的用例的期望輸出和實際輸出。這一步對學(xué)習(xí)體驗很重要——用戶看到具體的失敗原因才知道怎么改代碼。3.4 學(xué)習(xí)路線圖用JSON配置而非硬編碼學(xué)習(xí)路線圖我最初想在前端寫死節(jié)點后來發(fā)現(xiàn)每次調(diào)整路線都要改前端代碼、重新打包發(fā)布太麻煩了。改成運行時可配置的方案路線圖數(shù)據(jù)存數(shù)據(jù)庫前端從接口拉取按階段和時間線渲染。簡化版的路線JSON結(jié)構(gòu)類似{ 階段1: [編程語言入門, 計算機基礎(chǔ)], 階段2: [數(shù)據(jù)結(jié)構(gòu), 算法設(shè)計], 階段3: [操作系統(tǒng), 計算機網(wǎng)絡(luò), 數(shù)據(jù)庫原理], 階段4: [實踐項目, 專項進階] }前端對每個節(jié)點渲染卡片用戶點擊某個節(jié)點可以跳轉(zhuǎn)到對應(yīng)的課程或練習(xí)。學(xué)習(xí)進度標(biāo)記就存user_id node_id is_finished邏輯簡單但很實用。線路圖的數(shù)據(jù)內(nèi)容我花了不少心思。參考了幾所高校的教學(xué)計劃把CS核心課程按照依賴關(guān)系排了一遍高等數(shù)學(xué)、離散數(shù)學(xué)作為前置基礎(chǔ)然后才是數(shù)據(jù)結(jié)構(gòu)、計算機組成原理再往后是操作系統(tǒng)、編譯原理、計算機網(wǎng)絡(luò)。這個依賴關(guān)系雖然不是絕對正確但對新手來說是一個非常友好的引導(dǎo)。4. 踩坑實錄開發(fā)途中真正浪費時間的五個問題這個項目前后踩了不少坑挑五個最典型的寫出來每一個都是在搜索引擎上繞了很久才搞定的希望后來的同學(xué)少走彎路。4.1 富文本編輯器的XSS注入問題學(xué)習(xí)筆記模塊一開始我用的是富文本編輯器用戶可以輸入任意HTML。結(jié)果測試時發(fā)現(xiàn)一個大問題用戶可以在筆記里插入script標(biāo)簽或者惡意事件屬性比如img srcx onerroralert(1)。如果不做處理別人瀏覽到這篇筆記時就會執(zhí)行這段腳本典型的存儲型XSS漏洞。解決思路是前端渲染前過濾 后端入庫前直接拒絕危險內(nèi)容。后端用Jsoup框架做白名單過濾只允許正常的p、a、img、code、pre等標(biāo)簽所有on*屬性和script標(biāo)簽一律清除。筆記內(nèi)容從Markdown源文本保存渲染成HTML時才過濾雙保險。4.2 課程搜索搜不到和搜不準(zhǔn)并存沒上全文索引之前搜索有兩個毛病。搜動態(tài)規(guī)劃能出結(jié)果但搜dp就匹配不到任何內(nèi)容因為標(biāo)題里寫的是中文全稱反過來搜Java會把JavaScript的課程也搜出來因為LIKE %Java%子串匹配的粒度太粗了。后來用了ngram全文索引情況好了很多但還有一個細節(jié)要處理全文索引默認(rèn)按相關(guān)性排序相關(guān)性評分受詞頻影響課程標(biāo)題字段短、關(guān)鍵詞密度高評分反而合理。另外我在搜索接口上加了一個簡單的中文分詞步驟把用戶輸入的查詢短語按常規(guī)分隔符空格、逗號拆開再拼接成MATCH ... AGAINST的布爾模式SELECT * FROM courses WHERE MATCH(title) AGAINST(Java 并發(fā) IN BOOLEAN MODE)這樣Java 并發(fā)可以被精確匹配而不是被當(dāng)成一個完整長詞匹配效果肉眼可見地變好。4.3 Vue Router History模式部署后刷新404前端用的History路由模式本地開發(fā)一切正常打包部署到Nginx之后訪問首頁沒問題但在/courses/12這樣的詳情頁按F5刷新直接404。原因很簡單Nginx默認(rèn)在找不到對應(yīng)文件時才走不到前端路由因為生產(chǎn)環(huán)境沒有/courses/12這個真實路徑。解決辦法是在Nginx配置里加一個回退邏輯location / { try_files $uri $uri/ /index.html; }所有非靜態(tài)文件的請求都回退到index.html由前端路由接管。這個坑我記得特別清楚因為排查時一度懷疑是Vue Router版本問題調(diào)了很久最后發(fā)現(xiàn)就是一行Nginx配置的事。4.4 在線評測的隱藏扣分項運行時錯誤信息不完整判題模塊在測試時發(fā)現(xiàn)用戶代碼如果出現(xiàn)數(shù)組越界、空指針、除以零這類異常只能看到一個籠統(tǒng)的運行時錯誤具體哪一行出錯、錯誤信息是什么完全看不到。對學(xué)習(xí)者來說這種反饋基本等于沒有。后來改成了捕獲并記錄異常堆棧在Java判題場景里用戶代碼的異常信息會打印到標(biāo)準(zhǔn)錯誤輸出流判題進程把stderr的內(nèi)容捕獲下來如果判題結(jié)果是RERuntime Error就把堆棧的前幾行返回給前端展示。注意這里要做好信息截斷只顯示異常類型和行號不暴露服務(wù)器內(nèi)部路徑和敏感信息。4.5 跨域問題差點讓前端聯(lián)調(diào)崩掉前后端分離開發(fā)時前端跑在localhost:5173后端跑在localhost:8080必然會遇到跨域問題。一開始我在后端加了CrossOrigin注解能解決一部分GET請求但帶自定義Header的POST請求依然報跨域錯誤。正確的做法是在后端寫一個全局的CORS配置類允許指定的前端來源、請求方法、請求頭和攜帶憑證registry.addMapping(/**) .allowedOrigins(http://localhost:5173) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true);這里有一個小坑allowedOrigins(*)和allowCredentials(true)不能同時使用瀏覽器會直接拒絕必須寫明確的前端域名。聯(lián)調(diào)階段這個配置幫我省了一整天的排查時間。5. 數(shù)據(jù)從哪來種子內(nèi)容準(zhǔn)備與內(nèi)容安全底線網(wǎng)站功能寫完只是第一步更費時間的是讓網(wǎng)站看起來有內(nèi)容。一個空蕩蕩的學(xué)習(xí)網(wǎng)站再好的功能也沒人愿意用。我給自己定了一個目標(biāo)上線時至少要有一套完整的課程內(nèi)容和100道可判題的練習(xí)。5.1 種子數(shù)據(jù)的來源與版權(quán)處理課程內(nèi)容這塊我的做法是引用公開資料 整理原創(chuàng)講義而不是直接搬運別人的課程視頻或文檔。具體來源包括公開課程大綱參考國內(nèi)外知名高校公開的課程頁面吸收他們的知識點組織方式自己重新編寫摘要和章節(jié)結(jié)構(gòu)。經(jīng)典教材目錄比如數(shù)據(jù)結(jié)構(gòu)、操作系統(tǒng)這類經(jīng)典教材的章節(jié)順序本身就是很好的知識組織框架據(jù)此設(shè)計課程分類。網(wǎng)絡(luò)公開的OJ題目很多OJ平臺有開放題目集自己重新改寫題目描述和測試用例標(biāo)注題目來源不能原樣復(fù)制。這里要特別提醒一句畢設(shè)源碼和內(nèi)容都要注意版權(quán)邊界。直接從慕課網(wǎng)、B站把別人的視頻嵌進來雖然演示時方便但存在侵權(quán)風(fēng)險。我的方案是以圖文講義和代碼示例為主視頻只是補充版權(quán)上穩(wěn)妥得多。5.2 在線題目的打磨測試用例比描述更重要練習(xí)題準(zhǔn)備中我最大的體會是一道題值的不是題目描述而是測試用例。一道判斷回文數(shù)的題目測試用例至少要包含正例1211221、負例12310、邊界值0負數(shù)、溢出情況。原本我以為寫完題目描述就完事了后來測試時發(fā)現(xiàn)用戶提交的代碼五花八門邊界用例不充分判題結(jié)果非常不穩(wěn)定。后面我每道題至少配8到10個用例3個公開示例用例前端顯示 5個以上隱藏用例判題時使用。隱藏用例的意義在于用戶就算看到了示例也不能只針對示例寫死答案必須真正理解算法。5.3 內(nèi)容安全底線UGC內(nèi)容不能裸奔學(xué)習(xí)筆記和用戶昵稱是用戶生成內(nèi)容UGC這部分必須有審核機制。我的做法是三層過濾第一層前端輸入限制。昵稱長度、筆記字?jǐn)?shù)、圖片上傳格式先在前端攔住。第二層后端內(nèi)容過濾。引入敏感詞庫做關(guān)鍵詞匹配命中直接拒絕提交或者把內(nèi)容標(biāo)記為待審核狀態(tài)。第三層運營后臺審核。后臺管理列表里加一個筆記審核頁簽管理員可以查最近一周產(chǎn)生的筆記一鍵下架違規(guī)內(nèi)容。這個設(shè)計在答辯時很加分因為能體現(xiàn)安全意識和隱私保護意識而很多同類項目完全沒考慮這些問題。6. 部署上線與運營細節(jié)從畢設(shè)到真正可使用的學(xué)習(xí)站點功能開發(fā)完成后我部署在一臺輕量云服務(wù)器上2核4G配置系統(tǒng)用的Ubuntu 22.04環(huán)境是Nginx MySQL Redis Spring Boot jar包。整個部署過程比較標(biāo)準(zhǔn)說幾個值得注意的細節(jié)。6.1 前后端分開部署與Nginx配置前端打包后的靜態(tài)文件放在/var/www/html后端jar包用systemd管理服務(wù)設(shè)置開機自啟和崩潰自動重啟。Nginx這里配置一個反向代理把/api/前綴的請求轉(zhuǎn)發(fā)到后端服務(wù)server { listen 80; server_name your-domain.com; root /var/www/html; index index.html; location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location / { try_files $uri $uri/ /index.html; } }如果服務(wù)器帶寬不高建議Nginx開啟壓縮圖片資源做一下瘦身網(wǎng)頁首屏加載速度會有顯著提升。為了省流量我的封面圖統(tǒng)一用了WebP格式比JPG大概小30%左右。6.2 用HTTPS保護用戶會話登錄功能上線后HTTP明文傳輸用戶的賬號密碼肯定不行。我申請了免費的HTTPS證書在Nginx里配置443端口和證書路徑同時把80端口請求301重定向到HTTPS。這一步看起來不起眼但它保證了登錄會話的安全性也避免部分瀏覽器對非HTTPS頁面的不安全警告勸退用戶。6.3 冷啟動讓網(wǎng)站真正被用起來網(wǎng)站上線后最尷尬的是沒有用戶。冷啟動階段我做了三件事拉身邊人試用找了十來位同學(xué)、朋友注冊體驗收集了一輪真實反饋。印象最深的是有人反饋學(xué)習(xí)路線圖很清晰但點擊節(jié)點跳轉(zhuǎn)后不知道該怎么回來于是我在路線圖頁面加了面包屑導(dǎo)航。SEO基礎(chǔ)配置給每個課程頁面配置合理的title和meta description提交搜索引擎收錄。雖然學(xué)習(xí)網(wǎng)站不是靠搜索流量起家的但別讓搜索引擎完全抓不到。定期更新題目上線后每周更新5到10道新題保持在線評測模塊的活躍度。網(wǎng)站不怕小怕的是放著不管。6.4 備份最后的保命手段數(shù)據(jù)備份是最容易被忽略的環(huán)節(jié)。我配置了一個簡單的定時任務(wù)每天凌晨用mysqldump備份數(shù)據(jù)庫保留最近七天的備份文件。另外用戶上傳的圖片和筆記附件單獨打包備份到對象存儲。畢設(shè)答辯結(jié)束、網(wǎng)站不維護了數(shù)據(jù)備份依然有價值——至少交出去的時候還能恢復(fù)給下一屆同學(xué)或者作為代碼倉庫的一部分。最后說點實在的做這個計算機科學(xué)與技術(shù)學(xué)習(xí)網(wǎng)站我最深的感受是寫代碼的時間只占三分之一剩下三分之二是需求梳理、數(shù)據(jù)準(zhǔn)備和排坑。尤其是學(xué)習(xí)路線和在線評測這兩個模塊前者要理解教學(xué)邏輯后者要保證判題安全都是純CRUD頁面體現(xiàn)不了的能力。如果讓我重做一次我會把在線評測的沙箱方案從Docker改成更輕量級的多進程隔離減少每次判題的資源開銷提高并發(fā)能力。另外后臺管理界面我會提前兩周開始做別拖到最后通宵趕工——后臺的CRUD頁面雖然邏輯不復(fù)雜但表單字段多、列表篩選條件多工作量比想象中大不少。最后分享一個小技巧把學(xué)習(xí)路線圖的配置數(shù)據(jù)單獨抽成一個JSON文件放在前端資源目錄里開發(fā)時先不用接數(shù)據(jù)庫直接讀JSON渲染頁面等UI確定了再切換到后端接口。這樣前端開發(fā)和后端開發(fā)在路線圖模塊上完全解耦是這次項目里節(jié)奏最順的一個模塊。