車輛管理系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)指南)
每年三四月后臺(tái)私信被問爆的問題永遠(yuǎn)是同一個(gè)畢業(yè)設(shè)計(jì)到底選什么題目。尤其是計(jì)算機(jī)相關(guān)專業(yè)的同學(xué)既不想做純管理系統(tǒng)顯得太水又怕選太偏的技術(shù)棧把自己坑進(jìn)去。今天把我自己完整跑通的一套題拿出來講透——SpringBootVueMySQL 企業(yè)車輛管理系統(tǒng)。這不是我隨便挑的題目它是“安全牌”里的“最優(yōu)解”技術(shù)棧常見、業(yè)務(wù)邏輯清晰、功能模塊足夠撐起一篇像樣的論文而且部署成本極低你只要有一臺(tái)能跑Java的電腦就能完整復(fù)現(xiàn)整套系統(tǒng)。這套系統(tǒng)解決的是一個(gè)很實(shí)在的痛點(diǎn)企業(yè)里公車私用、用車審批靠紙質(zhì)單、車輛保養(yǎng)維修記錄全靠Excel管理員根本說不清哪輛車在用、哪輛該保養(yǎng)了。系統(tǒng)把車輛臺(tái)賬、用車申請、審批流轉(zhuǎn)、油費(fèi)記錄、保養(yǎng)維修、違章登記全部搬到線上角色分成管理員、車隊(duì)主管、普通員工三檔每類人看到的功能和操作權(quán)限都不一樣。如果你正在挑畢設(shè)題目或者已經(jīng)選了車輛管理類題目想找參考這篇文章會(huì)從數(shù)據(jù)庫設(shè)計(jì)、后端接口、前端聯(lián)調(diào)、打包部署到論文答辯把每個(gè)環(huán)節(jié)的實(shí)操細(xì)節(jié)和踩坑記錄都列清楚。1. 為什么這套“老三樣”技術(shù)棧是畢設(shè)的穩(wěn)妥之選1.1 技術(shù)選型背后的真實(shí)邏輯先聊點(diǎn)實(shí)際的。很多同學(xué)一上來就想搞微服務(wù)、搞分布式、搞Redis、搞消息隊(duì)列我勸你冷靜。畢業(yè)設(shè)計(jì)的核心目標(biāo)不是炫技而是讓評委老師在十分鐘內(nèi)看明白“你做了什么、怎么做的、為什么這么做”。SpringBootVueMySQL這套組合每一個(gè)環(huán)節(jié)都是答辯時(shí)能講出內(nèi)容的點(diǎn)SpringBoot負(fù)責(zé)后端接口簡潔快速和繁瑣的SSM配置說再見Vue負(fù)責(zé)前端頁面雙向綁定和組件化讓界面開發(fā)效率極高M(jìn)ySQL負(fù)責(zé)數(shù)據(jù)持久化SQL語句是面試必考寫這套系統(tǒng)等于順便復(fù)習(xí)我從輔導(dǎo)過的幾十個(gè)畢設(shè)項(xiàng)目里觀察到一個(gè)規(guī)律凡是能在答辯現(xiàn)場流暢演示、老師問技術(shù)細(xì)節(jié)不卡殼的基本都是“主流程扎實(shí)一兩個(gè)亮點(diǎn)”的項(xiàng)目而不是堆了十個(gè)框架的項(xiàng)目。車輛管理系統(tǒng)恰好能滿足這個(gè)要求——主流程是增刪改查和狀態(tài)流轉(zhuǎn)亮點(diǎn)可以放在用車時(shí)間沖突校驗(yàn)、車輛狀態(tài)自動(dòng)流轉(zhuǎn)、ECharts統(tǒng)計(jì)報(bào)表上三個(gè)亮點(diǎn)足夠撐場子了。1.2 企業(yè)車輛管理系統(tǒng)到底有哪些業(yè)務(wù)模塊別一聽“車輛管理系統(tǒng)”就以為只是個(gè)車輛信息的CRUD真正的業(yè)務(wù)線是圍繞“一輛車的全生命周期”展開的。我按實(shí)際需求拆解成六個(gè)模塊模塊核心功能字段/狀態(tài)要點(diǎn)車輛檔案管理車輛信息增刪改查、車輛狀態(tài)維護(hù)車牌號唯一、狀態(tài)分空閑/使用中/維修中/報(bào)廢用車申請審批員工提交申請、主管審核、車輛占用判斷申請狀態(tài)分待審核/已通過/已駁回/已取消駕駛員管理司機(jī)檔案、駕駛證信息、出車記錄一個(gè)駕駛員可綁定多輛車一般一輛車一個(gè)主駕費(fèi)用管理加油記錄、保養(yǎng)費(fèi)用、維修費(fèi)用、保險(xiǎn)費(fèi)用每次費(fèi)用關(guān)聯(lián)車輛、關(guān)聯(lián)里程數(shù)違章管理違章登記、扣分罰款、處理狀態(tài)狀態(tài)分未處理/已處理統(tǒng)計(jì)報(bào)表月度用車次數(shù)、費(fèi)用趨勢、車輛利用率用ECharts展示柱狀圖、餅圖模塊一拆出來你就明白了論文的“需求分析”和“功能設(shè)計(jì)”兩章基本不用愁每個(gè)模塊都能寫幾百字的業(yè)務(wù)描述。1.3 三類角色與權(quán)限控制思路權(quán)限設(shè)計(jì)是管理系統(tǒng)躲不開的點(diǎn)也是最容易被問到的。我的建議是別用Spring Security那一套重武器直接用攔截器角色字段就能實(shí)現(xiàn)。系統(tǒng)里設(shè)三類角色管理員擁有全部權(quán)限包括車輛信息維護(hù)、駕駛員管理、費(fèi)用錄入、數(shù)據(jù)查看車隊(duì)主管負(fù)責(zé)審核用車申請、查看車輛狀態(tài)、導(dǎo)出報(bào)表但不能修改車輛基礎(chǔ)信息普通員工只能提交用車申請、查看自己申請的審批進(jìn)度后端用JWT生成token登錄時(shí)把userId和roleId寫進(jìn)token里。寫一個(gè)攔截器Interceptor攔截所有/api/**請求校驗(yàn)token合法性再用HandlerMethod上的自定義注解或直接判斷roleId來控制接口訪問。代碼量不大但能在論文里寫“基于JWT的無狀態(tài)認(rèn)證”這個(gè)表述比“我用session存了一下”好聽多了。2. 數(shù)據(jù)庫設(shè)計(jì)核心表結(jié)構(gòu)與狀態(tài)流轉(zhuǎn)2.1 最少六張表跑通全部業(yè)務(wù)數(shù)據(jù)庫設(shè)計(jì)是整個(gè)系統(tǒng)的地基地基沒打好后面寫接口全是坑。我這套系統(tǒng)的表結(jié)構(gòu)設(shè)計(jì)如下你可以直接拿去調(diào)整system_user用戶表id、username、passwordBCrypt加密存儲(chǔ)、real_name、phone、dept_id、role_id、statussystem_role角色表id、role_name、role_code、remarkvehicle_info車輛信息表id、plate_no車牌號唯一索引、brand、model、color、seat_count、engine_no、frame_no、purchase_date、status1空閑/2使用中/3維修中/4報(bào)廢、driver_id、create_time、update_timevehicle_apply用車申請表id、apply_user_id、vehicle_id、apply_date、start_time、end_time、destination、reason、passenger_count、status1待審核/2已通過/3已駁回/4已取消、approver_id、audit_time、audit_remarkvehicle_fuel加油記錄表id、vehicle_id、fuel_type、fuel_price、fuel_amount、fuel_total、fuel_date、mileage、fuel_companyvehicle_maintenance保養(yǎng)維修表id、vehicle_id、type1保養(yǎng)/2維修、cost、mileage、garage_name、maintenance_date、description再加上一張違章表vehicle_violationid、vehicle_id、violation_time、location、reason、deduction_points、fine_amount、status、handle_date六張主表加三張基礎(chǔ)表這是一個(gè)非常標(biāo)準(zhǔn)的“中間量級”畢設(shè)數(shù)據(jù)庫。如果你希望再增加復(fù)雜度和論文亮點(diǎn)可以加一張vehicle_insurance保險(xiǎn)表然后把保養(yǎng)和加油記錄與“車輛里程數(shù)”聯(lián)動(dòng)形成“一車一檔全生命周期”的記錄閉環(huán)。2.2 時(shí)間沖突校驗(yàn)防止一輛車被同時(shí)申請這是整個(gè)系統(tǒng)技術(shù)含量最高的一個(gè)點(diǎn)也是答辯時(shí)能講得比較有深度的部分。用車申請?zhí)峤粫r(shí)必須校驗(yàn)“這輛車在申請時(shí)間段內(nèi)是否已經(jīng)被其他已通過的申請占用”否則就會(huì)出現(xiàn)一輛車同時(shí)跑兩個(gè)業(yè)務(wù)的笑話。判斷邏輯的核心SQL是時(shí)間段重疊檢測SELECT COUNT(*) FROM vehicle_apply WHERE vehicle_id #{vehicleId} AND status 2 -- 已通過 AND ( (start_time #{endTime} AND end_time #{startTime}) OR (start_time #{startTime} AND end_time #{endTime}) )兩段時(shí)間不重疊的條件是A.end B.start OR A.start B.end所以重疊的充要條件就是它的否定形式A.start B.end AND A.end B.start。這個(gè)邏輯理解透了寫出來就是一行SQL的事。為了更保險(xiǎn)你可以在審核通過的時(shí)候再校驗(yàn)一次因?yàn)榇嬖凇疤峤簧暾垥r(shí)空閑、審核時(shí)已被別人占用”的并發(fā)場景。2.3 車輛狀態(tài)的自動(dòng)流轉(zhuǎn)邏輯車輛status字段的變化聯(lián)動(dòng)是系統(tǒng)主流程的骨架員工提交申請通過后 → 車輛狀態(tài)置為2使用中使用結(jié)束后 → 管理員手動(dòng)歸還或系統(tǒng)按end_time自動(dòng)置為1空閑管理員登記維修 → 車輛狀態(tài)置為3維修中維修完成后 → 重置為1空閑我個(gè)人推薦“管理員手動(dòng)歸還”方案因?yàn)樽詣?dòng)歸還的邏輯在畢設(shè)里會(huì)有個(gè)尷尬點(diǎn)員工申請的時(shí)間結(jié)束了但車輛可能因故還在外面跑系統(tǒng)自動(dòng)置為空閑會(huì)讓數(shù)據(jù)失真。手動(dòng)歸還雖然多一步操作但業(yè)務(wù)上更真實(shí)答辯時(shí)老師問起來也更好解釋。3. SpringBoot后端從登錄鑒權(quán)到業(yè)務(wù)接口實(shí)現(xiàn)3.1 項(xiàng)目結(jié)構(gòu)與依賴版本建議先給出一份可以直接抄的版本搭配這是無數(shù)同學(xué)用血淚試出來的穩(wěn)定組合不建議隨意升級組件推薦版本原因JDK1.8穩(wěn)定網(wǎng)上資料最多Spring Boot2.7.x別用3.x3.x最低要求JDK17很多老教程直接失效MyBatis-Plus3.5.x自動(dòng)填充、分頁插件、LambdaQueryWrapper都很方便MySQL5.7或8.08.0需要注意認(rèn)證插件兼容性Maven3.6.33.8在某些鏡像源下會(huì)有奇怪問題Node14.xVue2/ 18.xVue3和前端框架對應(yīng)后端項(xiàng)目結(jié)構(gòu)用標(biāo)準(zhǔn)的分層架構(gòu)com.company.vehicle ├── controller // 接口層只做參數(shù)接收和結(jié)果封裝 ├── service // 業(yè)務(wù)邏輯層處理狀態(tài)流轉(zhuǎn)、沖突校驗(yàn) ├── mapper // MyBatis-Plus的Mapper接口 ├── entity // 數(shù)據(jù)庫實(shí)體類 ├── dto // 前端傳參對象如登錄DTO、申請DTO ├── common // 統(tǒng)一返回結(jié)果、異常處理、常量 ├── config // 跨域配置、攔截器注冊、分頁插件 └── utils // JWT工具、密碼加密工具3.2 統(tǒng)一返回結(jié)果與全局異常處理這是很多畢設(shè)代碼最容易漏但答辯最加分的東西。寫一個(gè)Result類所有接口統(tǒng)一返回{code: 200, message: success, data: ...}格式。再配合RestControllerAdvice做全局異常捕獲攔截BusinessException和SQLException轉(zhuǎn)換成對應(yīng)的錯(cuò)誤碼返回。這樣前端處理邏輯就非常簡單了只需要判斷res.code 200而且論文里也可以寫“設(shè)計(jì)了統(tǒng)一的異常處理機(jī)制提高了系統(tǒng)的健壯性”。3.3 分頁查詢與多條件篩選這個(gè)必須寫真代碼車輛列表是系統(tǒng)的主界面一定要支持分頁、按車牌號模糊查詢、按狀態(tài)篩選、按品牌篩選。用MyBatis-Plus的實(shí)現(xiàn)方式非常優(yōu)雅Override public IPageVehicleVO pageVehicles(VehicleQueryDTO dto) { PageVehicleInfo page new Page(dto.getPageNum(), dto.getPageSize()); LambdaQueryWrapperVehicleInfo wrapper new LambdaQueryWrapper(); wrapper.like(StringUtils.hasText(dto.getPlateNo()), VehicleInfo::getPlateNo, dto.getPlateNo()) .eq(dto.getStatus() ! null, VehicleInfo::getStatus, dto.getStatus()) .eq(StringUtils.hasText(dto.getBrand()), VehicleInfo::getBrand, dto.getBrand()) .orderByDesc(VehicleInfo::getCreateTime); return vehicleMapper.selectPage(page, wrapper); }StringUtils.hasText條件判斷這個(gè)寫法特別適合答辯講當(dāng)條件為空時(shí)自動(dòng)忽略該查詢條件動(dòng)態(tài)組合SQL而不是拼一堆if判斷字符串。加上MyBatis-Plus的分頁插件配置三行代碼就能搞定分頁物理查詢。3.4 文件上傳把MinIO作為車輛照片存儲(chǔ)的加分項(xiàng)車輛檔案里通常需要上傳車輛照片、行駛證照片。如果你不想把圖片存數(shù)據(jù)庫BLOB方案又慢又土又不想存本地磁盤打包部署后路徑容易丟可以引入MinIO。它和SpringBoot集成的標(biāo)準(zhǔn)流程是引入minio依賴、配置MinioClient、封裝一個(gè)MinioService實(shí)現(xiàn)上傳和預(yù)簽名URL訪問。論文里寫“基于MinIO的對象存儲(chǔ)方案實(shí)現(xiàn)了文件與業(yè)務(wù)數(shù)據(jù)的解耦”這個(gè)陳述比普通本地存儲(chǔ)高出一個(gè)檔次而且社區(qū)有大量現(xiàn)成代碼可以參考難度不大。4. Vue前端與前后端聯(lián)調(diào)實(shí)操4.1 初始化項(xiàng)目和目錄規(guī)劃前端我建議用Vue2Element UI的組合因?yàn)榫W(wǎng)上模板最多、坑最少導(dǎo)師哪怕不看前端代碼也見過這套界面。如果你已經(jīng)會(huì)Vue3用Vue3Element Plus也沒問題核心邏輯一致。目錄結(jié)構(gòu)如下src ├── api // 按模塊拆分的接口請求 │ ├── login.js │ ├── vehicle.js │ └── apply.js ├── assets // 靜態(tài)資源 ├── components // 公共組件如UploadImage、Pagination ├── router // 路由配置含路由守衛(wèi) ├── store // Vuex管理用戶信息和菜單狀態(tài) ├── utils // axios封裝、公共方法 └── views // 頁面文件按模塊建文件夾 ├── login ├── dashboard ├── vehicle ├── apply └── statistics4.2 Axios封裝與Token攔截器前端所有請求必須走統(tǒng)一封裝的axios實(shí)例不要直接在頁面里寫this.$http.get。我通常這樣封裝const service axios.create({ baseURL: /api, timeout: 15000 }); // 請求攔截器自動(dòng)攜帶token service.interceptors.request.use(config { const token localStorage.getItem(token); if (token) { config.headers[Authorization] Bearer token; } return config; }); // 響應(yīng)攔截器統(tǒng)一處理錯(cuò)誤碼 service.interceptors.response.use( response { const res response.data; if (res.code ! 200) { Message.error(res.message || 請求失敗); return Promise.reject(new Error(res.message)); } return res.data; }, error { if (error.response error.response.status 401) { localStorage.removeItem(token); router.push(/login); } Message.error(網(wǎng)絡(luò)異常請稍后重試); return Promise.reject(error); } );這兩個(gè)攔截器的價(jià)值在于所有頁面請求代碼都變得非常干凈而且token失效統(tǒng)一跳登錄頁。這個(gè)邏輯在論文“系統(tǒng)關(guān)鍵實(shí)現(xiàn)”章節(jié)里至少能寫半頁。4.3 路由守衛(wèi)與權(quán)限菜單登錄后前端要根據(jù)角色渲染不同的側(cè)邊欄菜單。最簡單的方案是在路由的meta里寫roles數(shù)組路由守衛(wèi)里判斷當(dāng)前用戶角色是否匹配router.beforeEach((to, from, next) { const token localStorage.getItem(token); if (to.path /login) { next(); return; } if (!token) { next(/login); return; } const roles JSON.parse(localStorage.getItem(roles) || []); if (to.meta.roles to.meta.roles.length 0) { if (to.meta.roles.some(role roles.includes(role))) { next(); } else { next(/403); } } else { next(); } });菜單動(dòng)態(tài)渲染用v-ifroleCode admin控制管理員專屬菜單項(xiàng)即可不需要引入復(fù)雜的動(dòng)態(tài)路由生成邏輯——除非你想在論文里多寫一個(gè)“基于角色動(dòng)態(tài)路由”的亮點(diǎn)那我建議你去查一下router.addRoutes的用法但說實(shí)話對這個(gè)小系統(tǒng)來說用處不大。4.4 前后端聯(lián)調(diào)的跨域問題開發(fā)環(huán)境跨域和打包后跨域是兩類問題處理方式完全不同開發(fā)階段在vue.config.js里配置proxy代理前端請求/api自動(dòng)轉(zhuǎn)發(fā)到http://localhost:8080這樣瀏覽器看到的請求是同源的不存在跨域。// vue.config.js module.exports { devServer: { port: 3000, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } };生產(chǎn)階段方案A后端配置CorsFilter全局允許跨域方案B前端打包后直接放進(jìn)后端static目錄天然同源。我強(qiáng)烈推薦方案B具體做法見下文部署章節(jié)它能把“你還需要單獨(dú)部署一個(gè)前端服務(wù)”這個(gè)變量完全消除答辯演示時(shí)直接一個(gè)Java進(jìn)程全部搞定。5. 從零到一完整部署數(shù)據(jù)庫、后端、前端三步走5.1 數(shù)據(jù)庫初始化與配置拿到源碼后第一步是啟動(dòng)MySQL把vehicle_management.sql導(dǎo)入數(shù)據(jù)庫。如果你用的MySQL 8.0一定要在連接串里加上時(shí)區(qū)和SSL參數(shù)否則連接報(bào)錯(cuò)會(huì)讓人懷疑人生# application.yml spring: datasource: url: jdbc:mysql://localhost:3306/vehicle?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrue username: root password: 你自己的密碼 driver-class-name: com.mysql.cj.jdbc.Driver其中allowPublicKeyRetrievaltrue是MySQL 8.0的新坑不加上去會(huì)報(bào)Public Key Retrieval is not allowed。serverTimezoneAsia/Shanghai是防止時(shí)間字段差8小時(shí)的必備參數(shù)。這兩條寫在部署文檔里能夠幫你省下大量排查時(shí)間。5.2 后端啟動(dòng)步驟后端啟動(dòng)其實(shí)就三步。第一步mvn clean install -DskipTests把依賴?yán)奖镜靥^測試加快速度。如果這一步卡在下載依賴就去改Maven的settings.xml把鏡像換成阿里云鏡像mirror idaliyunmaven/id mirrorOfcentral/mirrorOf urlhttps://maven.aliyun.com/repository/central/url /mirror第二步在IDEA里配置好JDK1.8和Maven直接運(yùn)行main方法。第三步看到“Started Application in xxx seconds”的日志再訪問http://localhost:8080/api/...驗(yàn)證。常見問題是端口被占用Windows下排查用netstat -ano | findstr 8080找到占用進(jìn)程的PID后去任務(wù)管理器結(jié)束任務(wù)或者在application.yml里換成8081。另一個(gè)高頻問題就是數(shù)據(jù)庫連不上檢查MySQL服務(wù)有沒有啟動(dòng)Windows服務(wù)里看“MySQL80”是否在運(yùn)行以及密碼和用戶名是否和應(yīng)用配置一致。5.3 前端啟動(dòng)與打包進(jìn)后端的經(jīng)典方案前端開發(fā)模式啟動(dòng)執(zhí)行npm install安裝依賴然后npm run serve默認(rèn)端口是vue.config.js里配的3000。瀏覽器打開http://localhost:3000輸入初始賬號登錄能通就是聯(lián)調(diào)成功。打包是最關(guān)鍵的操作。后端工程里src/main/resources/static/目錄先清空然后前端執(zhí)行npm run build把生成的dist目錄內(nèi)所有文件復(fù)制到static目錄最后重新打包后端mvn clean package -DskipTests這樣打出來的jar包就同時(shí)包含后端接口和前端頁面。部署時(shí)只需要java -jar vehicle.jar訪問http://localhost:8080前端頁面和后端接口都在這個(gè)端口上不需要再啟動(dòng)任何額外服務(wù)。這里必須提醒一個(gè)坑Vue打包默認(rèn)資源路徑是絕對路徑/如果你直接雙擊打開或丟到子目錄會(huì)白屏必須在vue.config.js或publicPath里設(shè)置成相對路徑module.exports { publicPath: ./, outputDir: dist, assetsDir: static };同時(shí)路由模式改用hash模式就是new Router({ mode: hash, ... })否則刷新頁面會(huì)出現(xiàn)404。這兩個(gè)配置是打包類項(xiàng)目最容易翻車的兩個(gè)點(diǎn)論文里或者部署文檔里一定要寫清楚原因。5.4 部署文檔應(yīng)該包含的核心內(nèi)容給你的部署文檔一個(gè)可以直接抄的骨架環(huán)境要求表JDK版本、MySQL版本、Node版本、數(shù)據(jù)庫初始化步驟建庫、導(dǎo)入SQL、修改賬號密碼、后端啟動(dòng)教程IDEA運(yùn)行或jar包運(yùn)行、前端啟動(dòng)教程npm install、npm run serve、打包部署教程build、復(fù)制文件到static、重新打包、常見問題端口占用、時(shí)區(qū)問題、白屏問題、依賴下載慢問題。這份部署文檔不僅能在項(xiàng)目提交時(shí)加分在找工作時(shí)也是“具備獨(dú)立部署能力”的直接證據(jù)。6. 我踩過的坑常見問題與排查速查表6.1 啟動(dòng)階段高頻報(bào)錯(cuò)我把帶學(xué)生跑這套系統(tǒng)時(shí)見過的高頻問題整理成表按出現(xiàn)頻率排序報(bào)錯(cuò)現(xiàn)象根本原因解決方案Application run failed端口被占用netstat -ano | findstr 8080結(jié)束對應(yīng)PID或改端口Access denied for user root數(shù)據(jù)庫密碼錯(cuò)誤核對application.yml中密碼Public Key Retrieval is not allowedMySQL8認(rèn)證問題連接串加allowPublicKeyRetrievaltrueFailed to configure a DataSource驅(qū)動(dòng)依賴缺失或URL寫錯(cuò)檢查驅(qū)動(dòng)依賴和url格式Maven下載jar包超時(shí)默認(rèn)國外鏡像源換成阿里云鏡像package javax.servlet不存在版本不兼容把spring-boot-starter-tomcat依賴加入或移除providedCannot be resolved to a typeIDEA緩存問題File → Invalidate Caches重啟6.2 運(yùn)行階段常見Bug運(yùn)行期的坑分三類。第一類是數(shù)據(jù)類比如時(shí)間字段顯示差8小時(shí)多半是連接串沒配serverTimezoneAsia/Shanghai或者Jackson序列化時(shí)沒格式化日期需要加spring.jackson.date-formatyyyy-MM-dd HH:mm:ss。第二類是文件類圖片上傳成功但是頁面顯示不出來先看訪問路徑是絕對路徑還是相對路徑再確認(rèn)靜態(tài)資源配置spring.web.resources.static-locations。第三類是狀態(tài)類審核通過了但車輛狀態(tài)沒變成“使用中”排查邏輯是看事務(wù)有沒有加Transactional、更新語句是否真的影響到了行記錄。一個(gè)我特別想提醒的細(xì)節(jié)Vue開發(fā)模式下請求正常、但打包后接口全部404大概率是baseURL寫死了http://localhost:8080。開發(fā)環(huán)境代理走的是/api相對路徑生產(chǎn)環(huán)境如果你把前端放進(jìn)jar包也必須用/api相對路徑讓請求走同源。把baseURL寫死成localhost的壞習(xí)慣會(huì)導(dǎo)致?lián)Q一臺(tái)機(jī)器部署就完全不可用。6.3 答辯前必測的三個(gè)場景答辯前一天強(qiáng)烈建議按這三個(gè)場景把系統(tǒng)完整跑一遍場景一管理員新增一輛車輛然后員工用這輛車提交申請主管審核通過管理員看到車輛狀態(tài)變成“使用中”歸還后變回“空閑”場景二兩輛車都被申請同一個(gè)時(shí)間段第二次申請彈出沖突提示場景三普通員工訪問管理員菜單被路由跳轉(zhuǎn)到403頁面。這三個(gè)場景分別對應(yīng)“主流程是否通暢”“業(yè)務(wù)規(guī)則是否生效”“權(quán)限控制是否到位”恰好也是老師最喜歡抽查的三個(gè)點(diǎn)。7. 論文寫作與答辯準(zhǔn)備的獨(dú)家經(jīng)驗(yàn)7.1 論文結(jié)構(gòu)怎么和源碼呼應(yīng)論文的寫作順序和數(shù)據(jù)表結(jié)構(gòu)高度相關(guān)我建議按照“選題背景→技術(shù)棧介紹→系統(tǒng)分析→系統(tǒng)設(shè)計(jì)→系統(tǒng)實(shí)現(xiàn)→系統(tǒng)測試→總結(jié)”的框架來寫第二章相關(guān)技術(shù)介紹SpringBoot講自動(dòng)配置原理、Vue講數(shù)據(jù)雙向綁定和組件化、MySQL講索引和事務(wù)、Element UI講解題思路第三章需求分析畫用例圖把員工、主管、管理員三類角色各自的用例畫清楚數(shù)據(jù)流圖畫到二級第四章系統(tǒng)設(shè)計(jì)數(shù)據(jù)庫ER圖、表結(jié)構(gòu)設(shè)計(jì)、接口設(shè)計(jì)列出核心接口的入?yún)⒊鰠⒌谖逭孪到y(tǒng)實(shí)現(xiàn)每個(gè)大模塊放1-2張頁面截圖配合核心代碼段重點(diǎn)寫JWT鑒權(quán)、時(shí)間沖突校驗(yàn)、分頁查詢?nèi)未a并解釋思路第六章系統(tǒng)測試黑盒測試為主列出測試用例表包括正常流程、異常流程和邊界值這里有個(gè)強(qiáng)烈的建議代碼不要貼大段論文里貼的每段代碼都必須配3行以上的解釋講清楚“這段代碼為什么這么寫”。老師們看論文時(shí)最反感的行為是把源碼整個(gè)附錄粘貼進(jìn)去湊頁數(shù)。7.2 老師最愛問的五個(gè)問題及應(yīng)答思路根據(jù)我旁聽多場答辯的經(jīng)驗(yàn)車輛管理系統(tǒng)的高頻問題基本集中在這五個(gè)問題一JWT和傳統(tǒng)Session有什么區(qū)別應(yīng)答要點(diǎn)JWT是無狀態(tài)的token中攜帶用戶信息服務(wù)端不需要存儲(chǔ)會(huì)話狀態(tài)適合前后端分離架構(gòu)Session依賴服務(wù)端存儲(chǔ)橫向擴(kuò)展時(shí)要考慮session共享。問題二MyBatis-Plus和MyBatis有什么區(qū)別應(yīng)答要點(diǎn)MP在MyBatis基礎(chǔ)上提供了通用Mapper和條件構(gòu)造器單表CRUD不用手寫SQL復(fù)雜查詢可以繼續(xù)用XML提高開發(fā)效率同時(shí)保留了靈活度。問題三一張車輛同時(shí)被兩個(gè)申請占用怎么防止應(yīng)答要點(diǎn)提交和審核時(shí)都做時(shí)間段重疊校驗(yàn)SQL用時(shí)間段重疊判斷條件審核更新語句加AND status 1條件通過“更新受影響行數(shù)是否為0”判斷并發(fā)沖突。問題四分頁是怎么實(shí)現(xiàn)的應(yīng)答要點(diǎn)MyBatis-Plus的分頁插件通過攔截器在SQL執(zhí)行前自動(dòng)拼接LIMIT語句物理分頁數(shù)據(jù)量大時(shí)性能優(yōu)于內(nèi)存分頁。問題五密碼在數(shù)據(jù)庫里是明文嗎應(yīng)答要點(diǎn)BCryptPasswordEncoder加密每次加密結(jié)果不同庫中不存明文即使數(shù)據(jù)庫泄露也無法逆向還原。7.3 演示數(shù)據(jù)準(zhǔn)備的三個(gè)小心機(jī)答辯現(xiàn)場演示是最容易翻車的環(huán)節(jié)而90%的翻車不是代碼問題是演示數(shù)據(jù)沒準(zhǔn)備好。第一個(gè)心機(jī)預(yù)置一些真實(shí)感強(qiáng)的數(shù)據(jù)比如十輛不同品牌型號的車輛車牌號用接近真實(shí)格式的“京A12345”而不是“car1”“test1”第二個(gè)心機(jī)準(zhǔn)備一條完整狀態(tài)的申請流程讓頁面在打開時(shí)恰好展示“待審核”和“已通過”兩種狀態(tài)第三個(gè)心機(jī)把統(tǒng)計(jì)報(bào)表的月份范圍縮小到近三個(gè)月并把數(shù)據(jù)錄入時(shí)間集中在這三個(gè)月這樣圖表看起來有趨勢有對比而不是一條直線。8. 寫在最后的幾句心里話帶過這么多畢設(shè)項(xiàng)目我的真實(shí)感受是其實(shí)每個(gè)拿到題目的同學(xué)都有能力做一個(gè)能用的系統(tǒng)拉開差距的從來不是代碼量而是“你有沒有真搞懂自己寫的每一行”。這套車輛管理系統(tǒng)你按我的步驟跑通一遍再自己動(dòng)手改兩個(gè)功能模塊哪怕只加一個(gè)導(dǎo)出Excel報(bào)表你就已經(jīng)超過了大多數(shù)只會(huì)抄代碼的同學(xué)。最后再分享一個(gè)小技巧如果你時(shí)間充裕強(qiáng)烈建議把代碼里的注釋改成自己組織語言寫的一版尤其是業(yè)務(wù)邏輯處的注釋。因?yàn)椴橹叵到y(tǒng)能查重文字但查不到你的理解深度。答辯時(shí)老師問“這個(gè)狀態(tài)流轉(zhuǎn)是怎么實(shí)現(xiàn)的”你如果能用自己的話解釋清楚那一刻你就真正駕馭了這個(gè)項(xiàng)目。祝順利。