架構(gòu)的學(xué)校培訓(xùn)管理系統(tǒng)畢業(yè)設(shè)計實戰(zhàn):從Nacos到Docker Compose全鏈路拆解)
簡介本資源是一套面向高校學(xué)生與軟件開發(fā)學(xué)習(xí)者的微服務(wù)架構(gòu)學(xué)校培訓(xùn)管理系統(tǒng)可直接用于畢業(yè)設(shè)計、課程設(shè)計或企業(yè)級項目練手。系統(tǒng)前端采用Vue.js搭配Element UI與Ant Design Vue組件庫后端基于Spring Boot使用Mybatis Plus操作MySQL通過Dubbo與OpenFeign完成跨服務(wù)調(diào)用并以Nacos作為注冊中心與配置中心實現(xiàn)了學(xué)員報名、簽到、分組、座位分配、云直播、在線考試、結(jié)業(yè)證下載等模塊同時包含系統(tǒng)日志、基礎(chǔ)參數(shù)管理與網(wǎng)關(guān)非法請求過濾。壓縮包共913個文件約2.28MB以454個Java源碼、102個Vue組件、93個JS腳本、69個XML配置及20個YML文件為主另含Dockerfile、SQL腳本與構(gòu)建批處理文件覆蓋完整的前后端與部署結(jié)構(gòu)。項目代碼可直接編譯運行已有389人學(xué)習(xí)適合需要完整微服務(wù)實戰(zhàn)案例、快速搭建環(huán)境并理解服務(wù)拆分與調(diào)用鏈路的讀者參考。1. 從一份能直接跑起來的微服務(wù)學(xué)校培訓(xùn)管理系統(tǒng)說起如果你正在為畢業(yè)設(shè)計或課程設(shè)計找一套真正能跑通、能寫進論文、還能在答辯時經(jīng)得起追問的項目這套基于微服務(wù)架構(gòu)的學(xué)校培訓(xùn)管理系統(tǒng)值得認真拆一遍。它不是那種把代碼堆在一起、跑起來就報一堆錯的“僵尸項目”而是把學(xué)員報名、簽到、分組、座位分配、云直播、在線考試、結(jié)業(yè)證下載這些真實業(yè)務(wù)場景串成了一條完整鏈路。前端用 Vue.js 搭配 Element UI 和 Ant Design Vue后端基于 Spring Boot用 MyBatis Plus 操作 MySQL跨服務(wù)調(diào)用走 Dubbo 和 OpenFeign注冊中心和配置中心用 Nacos網(wǎng)關(guān)模塊負責(zé)過濾非法請求系統(tǒng)模塊管理操作日志和基礎(chǔ)參數(shù)。這套組合基本覆蓋了當(dāng)前 Java 微服務(wù)方向畢業(yè)設(shè)計的主流技術(shù)棧適合計算機相關(guān)專業(yè)、軟件工程課程設(shè)計以及需要展示完整前后端分離架構(gòu)的畢業(yè)設(shè)計選題。下面我從資源結(jié)構(gòu)、環(huán)境搭建、核心模塊實現(xiàn)、避坑排查到進階技巧按實際復(fù)現(xiàn)順序拆開講。2. 資源結(jié)構(gòu)與微服務(wù)模塊拆分先看清六個 Dockerfile 背后的部署邏輯拿到一個微服務(wù)項目最怕的就是上來就mvn spring-boot:run結(jié)果 Nacos 沒起、數(shù)據(jù)庫沒連、端口沖突全撞在一起。這套項目的根目錄里有一組很顯眼的文件package.bat、build.bat、run-web.bat、.env.development以及六個Dockerfile。六個 Dockerfile 不是重復(fù)文件而是對應(yīng)六個可獨立部署的服務(wù)模塊。先把這個結(jié)構(gòu)理清楚后面啟動才不會亂。2.1 從 package.bat 和 build.bat 看構(gòu)建順序package.bat和build.bat是 Windows 下的批處理腳本通常一個負責(zé)前端依賴安裝與打包一個負責(zé)后端 Maven 多模塊編譯。常見做法是package.bat先進入前端目錄執(zhí)行npm install和npm run build把靜態(tài)資源產(chǎn)出到指定目錄build.bat再在根目錄執(zhí)行mvn clean package -DskipTests把每個微服務(wù)打成可執(zhí)行 jar。這兩個腳本的順序不能反因為部分網(wǎng)關(guān)或靜態(tài)資源服務(wù)在打包時會去讀取前端構(gòu)建產(chǎn)物。# package.bat 典型內(nèi)容拆解 cd ./training-web call npm install call npm run build cd .. echo 前端構(gòu)建完成# build.bat 典型內(nèi)容拆解 call mvn clean package -DskipTests echo 后端多模塊編譯完成邏輯說明npm install安裝前端依賴npm run build生成生產(chǎn)環(huán)境靜態(tài)文件mvn clean package清理舊產(chǎn)物并重新編譯所有子模塊。參數(shù)上-DskipTests跳過單元測試畢業(yè)設(shè)計階段可以加快構(gòu)建速度但如果你要寫測試章節(jié)建議去掉這個參數(shù)單獨跑一次測試模塊。2.2 六個 Dockerfile 分別對應(yīng)什么服務(wù)六個 Dockerfile 通常對應(yīng)網(wǎng)關(guān)服務(wù)、系統(tǒng)管理服務(wù)、學(xué)員服務(wù)、考試服務(wù)、直播服務(wù)、前端靜態(tài)資源服務(wù)。每個 Dockerfile 的基礎(chǔ)鏡像一般是openjdk:8-jre或openjdk:11-jre前端可能是nginx:alpine。它們的存在意味著這套項目支持容器化部署但畢業(yè)設(shè)計答辯時不一定非要上 Docker本地直接跑 jar 包也能演示。文件/模塊作用啟動依賴網(wǎng)關(guān)服務(wù) Dockerfile請求過濾、路由轉(zhuǎn)發(fā)Nacos 必須先啟動系統(tǒng)管理服務(wù) Dockerfile操作日志、基礎(chǔ)參數(shù)MySQL、Nacos學(xué)員服務(wù) Dockerfile報名、簽到、分組、座位MySQL、Nacos考試服務(wù) Dockerfile在線考試、結(jié)業(yè)證MySQL、Nacos直播服務(wù) Dockerfile云直播模塊Nacos、可能依賴第三方推流配置前端 DockerfileNginx 托管 Vue 構(gòu)建產(chǎn)物后端網(wǎng)關(guān)地址2.3 .env.development 里的前端環(huán)境變量.env.development是 Vue 項目的開發(fā)環(huán)境配置文件里面通常有VUE_APP_BASE_API指向網(wǎng)關(guān)地址比如http://localhost:8080。這個值必須和網(wǎng)關(guān)服務(wù)實際端口一致否則前端所有請求都會 404。很多同學(xué)本地跑不起來不是后端代碼有問題而是這里寫了一個不存在的端口。# .env.development 常見內(nèi)容 NODE_ENVdevelopment VUE_APP_BASE_APIhttp://localhost:8080參數(shù)說明VUE_APP_BASE_API是前端 axios 請求的基地址網(wǎng)關(guān)端口如果是 8080這里就寫 8080如果網(wǎng)關(guān)改了端口這里必須同步改。改完要重啟npm run serve熱更新有時不會重新讀取環(huán)境變量。2.4 run-web.bat 的啟動順序run-web.bat一般是本地開發(fā)啟動腳本可能按順序啟動 Nacos、后端各服務(wù)、前端。但批處理腳本里如果用了start命令窗口會一閃而過看不到報錯。我一般會手動分窗口啟動先確認 Nacos 控制臺能訪問再逐個起服務(wù)。# 手動啟動順序建議 # 1. 啟動 Nacos startup.cmd -m standalone # 2. 啟動系統(tǒng)管理服務(wù) java -jar system-service.jar # 3. 啟動學(xué)員服務(wù) java -jar student-service.jar # 4. 啟動考試服務(wù) java -jar exam-service.jar # 5. 啟動網(wǎng)關(guān) java -jar gateway-service.jar # 6. 啟動前端 cd training-web npm run serve邏輯說明Nacos 作為注冊中心和配置中心必須最先啟動否則其他服務(wù)注冊不上網(wǎng)關(guān)最后啟動或與其他服務(wù)同時啟動都可以但前端要等網(wǎng)關(guān)就緒后再訪問。每個服務(wù)啟動后去 Nacos 控制臺的服務(wù)列表里確認是否注冊成功這是判斷微服務(wù)是否正常的第一步。3. Nacos 配置與跨服務(wù)調(diào)用Dubbo 和 OpenFeign 怎么選、怎么配微服務(wù)項目能不能跑通一半看 Nacos一半看跨服務(wù)調(diào)用。這套項目同時用了 Dubbo 和 OpenFeign很多同學(xué)會疑惑為什么不用一個。實際場景里Dubbo 適合內(nèi)部高性能 RPC 調(diào)用OpenFeign 適合對外或跨模塊的 HTTP 調(diào)用。畢業(yè)設(shè)計里兩種都出現(xiàn)答辯時能講清楚選型理由比只寫一種更加分。3.1 Nacos 單機模式啟動與配置導(dǎo)入Nacos 默認是集群模式本地開發(fā)必須加-m standalone。啟動后訪問http://localhost:8848/nacos默認賬號密碼都是nacos。然后要把項目里的配置文件導(dǎo)入 Nacos通常每個服務(wù)有一個dataId格式如student-service-dev.yaml。# Windows 啟動 Nacos cd nacos/bin startup.cmd -m standalone # Linux 啟動 Nacos sh startup.sh -m standalone# student-service-dev.yaml 示例 spring: datasource: url: jdbc:mysql://localhost:3306/training_school?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: mapper-locations: classpath*:/mapper/**/*.xml global-config: db-config: id-type: auto參數(shù)說明serverTimezoneAsia/Shanghai不加可能報時區(qū)錯誤mapper-locations要覆蓋所有模塊的 XML 文件id-type: auto表示主鍵自增如果數(shù)據(jù)庫用了雪花 ID 要改成assign_id。配置發(fā)布后服務(wù)啟動時會自動拉取改配置后部分服務(wù)支持動態(tài)刷新但數(shù)據(jù)源這類配置通常需要重啟。3.2 Dubbo 服務(wù)暴露與引用Dubbo 在 Spring Boot 里通常用DubboService暴露服務(wù)用DubboReference引用服務(wù)。注冊中心地址指向 Nacos。// 服務(wù)提供方 DubboService public class StudentServiceImpl implements StudentService { Override public StudentDTO getById(Long id) { // 業(yè)務(wù)邏輯 return studentMapper.selectById(id); } } // 服務(wù)消費方 RestController public class ExamController { DubboReference private StudentService studentService; GetMapping(/exam/student/{id}) public StudentDTO getStudent(PathVariable Long id) { return studentService.getById(id); } }邏輯說明DubboService把實現(xiàn)類注冊到 NacosDubboReference從 Nacos 訂閱并生成代理。參數(shù)上Dubbo 默認端口是 20880如果多個服務(wù)在同一臺機器上跑要確保端口不沖突可以在配置里指定dubbo.protocol.port。常見坑是服務(wù)提供方?jīng)]啟動或沒注冊成功消費方啟動時報No provider available這時候先去 Nacos 服務(wù)列表確認提供方是否在線。3.3 OpenFeign 聲明式調(diào)用與超時配置OpenFeign 更適合 RESTful 接口調(diào)用聲明一個接口加FeignClient注解即可。FeignClient(name system-service, path /system) public interface SystemFeignClient { GetMapping(/log/list) ListLogDTO getLogList(RequestParam(page) Integer page, RequestParam(size) Integer size); }# OpenFeign 超時配置 feign: client: config: default: connectTimeout: 5000 readTimeout: 10000參數(shù)說明name對應(yīng) Nacos 里的服務(wù)名path是統(tǒng)一前綴connectTimeout是連接超時readTimeout是讀取超時。默認超時較短考試模塊或直播模塊如果接口響應(yīng)慢容易觸發(fā)超時建議適當(dāng)調(diào)大。常見坑是 Feign 接口的方法參數(shù)沒加RequestParam或PathVariable啟動時報錯或調(diào)用時參數(shù)丟失。3.4 網(wǎng)關(guān)過濾非法請求的配置位置網(wǎng)關(guān)模塊通常用 Spring Cloud Gateway配置在application.yml里通過predicates和filters過濾請求。非法請求過濾一般包括token 校驗、路徑白名單、請求頭檢查。spring: cloud: gateway: routes: - id: student-service uri: lb://student-service predicates: - Path/student/** filters: - StripPrefix1 - name: AuthFilter邏輯說明lb://student-service表示從 Nacos 負載均衡到學(xué)員服務(wù)StripPrefix1去掉第一層路徑AuthFilter是自定義過濾器用來校驗 token。常見坑是白名單沒配登錄接口導(dǎo)致登錄請求也被攔截前端一直 401。4. 核心業(yè)務(wù)模塊落地報名、簽到、分組、座位、考試、結(jié)業(yè)證這套系統(tǒng)的業(yè)務(wù)模塊比較多但畢業(yè)設(shè)計答辯時不需要每個都講得一樣細。挑三到四個能體現(xiàn)技術(shù)難點的模塊重點寫其他模塊說明功能即可。下面按數(shù)據(jù)流和實現(xiàn)難度拆幾個關(guān)鍵模塊。4.1 學(xué)員報名與簽到模塊的數(shù)據(jù)表設(shè)計報名和簽到通常涉及三張表學(xué)員表、報名記錄表、簽到記錄表。學(xué)員表存基本信息報名記錄表關(guān)聯(lián)學(xué)員和培訓(xùn)班簽到記錄表記錄每次簽到時間和狀態(tài)。CREATE TABLE student ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, phone VARCHAR(20), id_card VARCHAR(18), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE enroll_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT, student_id BIGINT NOT NULL, class_id BIGINT NOT NULL, enroll_time DATETIME DEFAULT CURRENT_TIMESTAMP, status TINYINT DEFAULT 0 ); CREATE TABLE sign_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT, student_id BIGINT NOT NULL, class_id BIGINT NOT NULL, sign_time DATETIME DEFAULT CURRENT_TIMESTAMP, sign_type TINYINT DEFAULT 1 );參數(shù)說明status字段用 0 表示待審核、1 表示已通過、2 表示已拒絕sign_type用 1 表示正常簽到、2 表示補簽。常見坑是報名和簽到?jīng)]有加唯一索引導(dǎo)致同一學(xué)員重復(fù)報名或重復(fù)簽到。建議在enroll_record上加(student_id, class_id)唯一索引。4.2 學(xué)員分組與座位分配的算法實現(xiàn)分組和座位分配是這套系統(tǒng)里比較有亮點的模塊。分組可以按人數(shù)平均分也可以按成績或地區(qū)分座位分配通常按簽到順序或隨機分配。// 平均分組示例 public ListListStudentDTO groupStudents(ListStudentDTO students, int groupCount) { ListListStudentDTO groups new ArrayList(); for (int i 0; i groupCount; i) { groups.add(new ArrayList()); } for (int i 0; i students.size(); i) { groups.get(i % groupCount).add(students.get(i)); } return groups; }邏輯說明i % groupCount保證學(xué)生輪流進入每個組人數(shù)差不超過 1。參數(shù)上groupCount不能大于學(xué)生總數(shù)否則會出現(xiàn)空組。座位分配類似可以用Collections.shuffle打亂后按順序填充座位表。常見坑是分組后沒有持久化刷新頁面就丟了記得把分組結(jié)果寫入group_record表。4.3 在線考試與結(jié)業(yè)證下載的流程串聯(lián)在線考試模塊通常包括題庫管理、試卷生成、答題提交、自動判分。結(jié)業(yè)證下載一般是在考試通過后生成 PDF 或圖片提供下載鏈接。// 自動判分簡化邏輯 public int calculateScore(ListAnswerDTO answers, ListQuestionDTO questions) { int score 0; MapLong, String correctMap questions.stream() .collect(Collectors.toMap(QuestionDTO::getId, QuestionDTO::getCorrectAnswer)); for (AnswerDTO answer : answers) { String correct correctMap.get(answer.getQuestionId()); if (correct ! null correct.equals(answer.getAnswer())) { score answer.getScore(); } } return score; }參數(shù)說明answer.getScore()是每題分值通常從試卷配置里讀取correctMap用題目 ID 映射正確答案。結(jié)業(yè)證生成可以用 iText 或 EasyExcel生成后存到文件服務(wù)器或本地目錄數(shù)據(jù)庫里存路徑。常見坑是考試提交后沒有事務(wù)控制判分和保存成績分開執(zhí)行中間出錯導(dǎo)致成績丟失。4.4 云直播模塊的接入邊界云直播模塊通常不是自己實現(xiàn)推流服務(wù)器而是接入第三方直播 SDK 或生成推流地址。畢業(yè)設(shè)計里一般只做直播間創(chuàng)建、推流地址生成、觀看頁面嵌入。常見做法是后端生成一個帶簽名的推流地址前端用 video.js 或第三方播放器播放。注意不要在這部分寫涉及具體第三方平臺賬號的敏感信息用占位配置即可。5. 避坑與常見問題排查從 Nacos 注冊失敗到前端跨域微服務(wù)項目跑不起來百分之八十的問題集中在 Nacos、數(shù)據(jù)庫、端口和跨域。下面這幾條是我實際復(fù)現(xiàn)時踩過的坑按現(xiàn)象、原因、解決寫清楚。5.1 服務(wù)啟動后 Nacos 服務(wù)列表為空現(xiàn)象服務(wù)日志顯示啟動成功但 Nacos 控制臺看不到任何服務(wù)。原因spring.cloud.nacos.discovery.server-addr配置錯誤或者 Nacos 沒啟動。解決先確認 Nacos 控制臺能訪問再檢查每個服務(wù)的bootstrap.yml或application.yml里的 Nacos 地址是否為localhost:8848。如果用了 Docker地址不能寫 localhost要寫宿主機 IP。5.2 跨服務(wù)調(diào)用報 No provider available現(xiàn)象消費方啟動時報No provider available from registry。原因提供方?jīng)]注冊成功或者 Dubbo 的接口包路徑不一致。解決去 Nacos 服務(wù)列表確認提供方是否存在檢查提供方和消費方的接口全限定名是否完全一致檢查 Dubbo 版本是否兼容。5.3 前端請求全部 404 或跨域現(xiàn)象前端頁面能打開但所有接口請求失敗控制臺報 404 或 CORS 錯誤。原因.env.development里的VUE_APP_BASE_API指向錯誤或者網(wǎng)關(guān)沒配跨域。解決確認網(wǎng)關(guān)端口和前端配置一致在網(wǎng)關(guān)加 CORS 配置允許前端域名和請求方法。# 網(wǎng)關(guān)跨域配置 spring: cloud: gateway: globalcors: cors-configurations: [/**]: allowedOrigins: * allowedMethods: * allowedHeaders: *5.4 數(shù)據(jù)庫時區(qū)或編碼導(dǎo)致中文亂碼現(xiàn)象報名信息里的中文姓名顯示為亂碼。原因數(shù)據(jù)庫連接 URL 沒加characterEncodingutf8或者數(shù)據(jù)庫本身字符集不是 utf8mb4。解決連接 URL 加useUnicodetruecharacterEncodingutf8數(shù)據(jù)庫和表都改成 utf8mb4。5.5 考試提交后成績沒保存現(xiàn)象考試頁面提示提交成功但后臺查不到成績。原因判分和保存不在同一個事務(wù)里或者保存時拋異常被吞掉。解決在提交方法上加Transactional并檢查日志里是否有異常堆棧。常見坑是前端傳的答案格式和后端接收的 DTO 字段名不一致導(dǎo)致答案為空。6. 進階技巧用 Docker Compose 一鍵拉起整套微服務(wù)本地分窗口啟動六個服務(wù)太麻煩而且每次重啟都要按順序來。我后來習(xí)慣用 Docker Compose 把 Nacos、MySQL、Redis 和各個服務(wù)編排在一起一條命令拉起整套環(huán)境。這套項目自帶六個 Dockerfile正好可以串起來。6.1 編寫 docker-compose.yml 的關(guān)鍵參數(shù)version: 3.8 services: nacos: image: nacos/nacos-server:latest environment: - MODEstandalone ports: - 8848:8848 mysql: image: mysql:8.0 environment: - MYSQL_ROOT_PASSWORD123456 - MYSQL_DATABASEtraining_school ports: - 3306:3306 gateway-service: build: context: ./gateway-service depends_on: - nacos ports: - 8080:8080 student-service: build: context: ./student-service depends_on: - nacos - mysql參數(shù)說明depends_on只保證啟動順序不保證服務(wù)就緒所以 Nacos 啟動后最好加一個健康檢查或等待腳本MYSQL_DATABASE會自動建庫但表結(jié)構(gòu)還是要手動導(dǎo)入 SQL 文件。常見坑是 Docker 里的服務(wù)訪問 MySQL 不能用 localhost要用服務(wù)名mysql。6.2 驗證整套系統(tǒng)是否跑通的三步檢查第一步訪問 Nacos 控制臺確認所有服務(wù)都在服務(wù)列表里。第二步訪問網(wǎng)關(guān)的健康檢查接口或登錄接口確認網(wǎng)關(guān)路由正常。第三步打開前端頁面走一遍報名、簽到、考試流程確認數(shù)據(jù)能寫入數(shù)據(jù)庫。# 檢查 Nacos 服務(wù)列表 curl http://localhost:8848/nacos/v1/ns/service/list?pageNo1pageSize20 # 檢查網(wǎng)關(guān)路由 curl http://localhost:8080/actuator/gateway/routes邏輯說明第一個命令返回注冊的服務(wù)名列表如果為空說明服務(wù)沒注冊上第二個命令返回網(wǎng)關(guān)路由配置確認路由規(guī)則是否加載。這兩個接口在開發(fā)階段很實用比翻日志快。6.3 一個我常犯的錯誤剛開始用 Docker Compose 時我總以為depends_on能保證 Nacos 完全啟動后再啟動其他服務(wù)結(jié)果服務(wù)還是注冊失敗。后來每次都在啟動腳本里加一個循環(huán)等待確認 Nacos 的 8848 端口能訪問后再啟動業(yè)務(wù)服務(wù)。從那以后我每次編排微服務(wù)都強制走一遍端口等待不再依賴depends_on的順序。希望這套拆解能幫你順利跑通這份學(xué)校培訓(xùn)管理系統(tǒng)把畢業(yè)設(shè)計或課程設(shè)計穩(wěn)穩(wěn)落地。本文還有配套的精品資源點擊獲取