畢設(shè)全解析:從架構(gòu)設(shè)計(jì)到部署實(shí)戰(zhàn))
做畢設(shè)選“SpringBootVue停車場管理系統(tǒng)”這個(gè)題目的人這兩年是真的多。原因也很實(shí)在技術(shù)棧主流、業(yè)務(wù)場景清晰、前后端分離的架構(gòu)踩中當(dāng)下企業(yè)開發(fā)的主流范式答辯時(shí)既能講業(yè)務(wù)又能講技術(shù)怎么都有話說。不過題目選得容易真正落地卻有不少坑——版本兼容、權(quán)限控制、數(shù)據(jù)庫設(shè)計(jì)、打包部署每一步都有可能卡住你三五天。我前前后后幫人看過不少這個(gè)題目的代碼自己也完整搭過一版這篇就把整個(gè)項(xiàng)目的設(shè)計(jì)和實(shí)操細(xì)節(jié)拆開揉碎講一遍給正在做這個(gè)畢設(shè)的同學(xué)當(dāng)個(gè)參考。先說清楚這套系統(tǒng)是做什么的管理員登錄后臺(tái)維護(hù)車位信息、管理月卡用戶、設(shè)置計(jì)費(fèi)規(guī)則用戶端可以注冊登錄、綁定車牌、查看車位余量、繳納停車費(fèi)、申請(qǐng)?jiān)驴?。整個(gè)系統(tǒng)跑在SpringBootJPA/MyBatis這套后端上前端用Vue全家桶做SPA單頁應(yīng)用通過RESTful API通信。麻雀雖小五臟俱全該有的模塊一個(gè)不少用來做畢業(yè)論文的技術(shù)承載面足夠?qū)挾颐總€(gè)模塊都能引出對(duì)應(yīng)的技術(shù)點(diǎn)寫到論文里不愁沒有內(nèi)容。1. 項(xiàng)目定位與整體設(shè)計(jì)思路1.1 為什么選SpringBootVue這套組合畢業(yè)設(shè)計(jì)的技術(shù)選型第一原則不是“哪個(gè)最屌”而是“哪個(gè)最穩(wěn)、最能讓你順利畢業(yè)”。SpringBootVue正好踩在這個(gè)平衡點(diǎn)上。從后端看SpringBoot把Spring的配置地獄徹底壓平了你不需要理解復(fù)雜的XML配置幾個(gè)注解就能把接口跑起來。這對(duì)精力上要兼顧論文和找工作的應(yīng)屆生來說非常友好。更關(guān)鍵的是SpringBoot的自動(dòng)裝配原理、內(nèi)嵌Tomcat、Starter機(jī)制這些都是答辯時(shí)的經(jīng)典提問點(diǎn)屬于“你稍微準(zhǔn)備一下就能答好”的送分題。從前端看Vue的學(xué)習(xí)曲線比React平滑中文資料多遇到問題一搜就有答案。Vue的雙向綁定讓表單處理變得很直觀路由、狀態(tài)管理、組件通信這些概念理解起來也不費(fèi)勁。更重要的是Vue全家桶你能寫明白“響應(yīng)式原理”“虛擬DOM”“路由守衛(wèi)”這幾個(gè)點(diǎn)論文的技術(shù)分析章節(jié)就有著落了。這套組合還有一層隱性優(yōu)勢社區(qū)活躍度極高。你寫到某一步卡住了不管是CSDN還是GitHub幾乎都能找到現(xiàn)成的解決方案不會(huì)像小眾框架那樣問遍全網(wǎng)無應(yīng)答。1.2 功能模塊拆解從業(yè)務(wù)需求推導(dǎo)架構(gòu)做畢設(shè)不要一上來就寫代碼先把業(yè)務(wù)流程理清楚。停車場管理系統(tǒng)核心是“車進(jìn)場、車出場、收錢、管卡”這個(gè)閉環(huán)圍繞它展開功能模塊管理員端車位管理增刪改查車位、設(shè)置車位類型、訂單管理查看收費(fèi)記錄、處理異常訂單、月卡管理審核月卡申請(qǐng)、續(xù)期、退卡、用戶管理禁用/啟用賬號(hào)、計(jì)費(fèi)規(guī)則設(shè)置按時(shí)計(jì)費(fèi)或按次計(jì)費(fèi)、數(shù)據(jù)統(tǒng)計(jì)看板今日營收、車輛進(jìn)出趨勢、車位利用率。用戶端注冊登錄、綁定車牌、實(shí)時(shí)車位余量查看、停車記錄查詢、在線繳費(fèi)微信/支付寶模擬支付即可、月卡申請(qǐng)與續(xù)費(fèi)、個(gè)人資料維護(hù)。模塊劃分上建議遵循“高內(nèi)聚、低耦合”。車、訂單、用戶、計(jì)費(fèi)這四塊盡量獨(dú)立成package各模塊之間只通過Service接口交互不要互相直接拆內(nèi)部實(shí)現(xiàn)。這樣寫的好處是第一你論文里可以畫出清晰的模塊架構(gòu)圖答辯時(shí)有東西可講第二后期維護(hù)和加功能不會(huì)牽一發(fā)而動(dòng)全身。我見過很多人的畢設(shè)代碼是Controller里堆了兩千行所有業(yè)務(wù)邏輯全寫在接口里數(shù)表和訂單表強(qiáng)耦合。這種代碼跑起來沒問題但答辯時(shí)老師看一眼源碼問一句“你這個(gè)層與層的職責(zé)怎么劃分的”基本就啞火了。所以設(shè)計(jì)階段多花半天畫清楚模塊關(guān)系圖后面寫代碼能省不止兩天。1.3 技術(shù)棧選型與版本選擇別小看這個(gè)環(huán)節(jié)技術(shù)棧列表是論文里最顯眼的部分也是答辯老師最愛盯著看的部分。推薦一套親測穩(wěn)的組合層級(jí)技術(shù)選型說明前端框架Vue 2.6 Vue Router 3 Vuex用Vue 2是因?yàn)榻坛套疃唷⒆畛墒霦lement UI也完美兼容Vue 3項(xiàng)目如果時(shí)間充裕也可以但配套組件庫要先確認(rèn)兼容性UI組件庫Element UI表格、表單、對(duì)話框都有現(xiàn)成組件幾行代碼就能拼出后臺(tái)管理界面省下大把寫CSS的時(shí)間后端框架SpringBoot 2.5.xJDK8最高兼容組合網(wǎng)上的教程大部分基于這個(gè)版本遇到問題容易搜到答案你非要上Spring Boot 3.x就得配JDK17很多坑等著你填ORM層MyBatis-Plus單表CRUD不用寫SQL自帶分頁插件比原生MyBatis省一半工作量數(shù)據(jù)庫MySQL 5.7 / 8.05.7穩(wěn)定8.0性能更好兩個(gè)版本語法上基本無感隨便選認(rèn)證方案JWT Spring Security無狀態(tài)認(rèn)證前后端分離項(xiàng)目標(biāo)配答辯能講的東西多構(gòu)建工具M(jìn)aven 3.6.主流中的主流IDEA內(nèi)置支持直接用它build就行這里特別提醒一句版本不是越新越好尤其是畢設(shè)這個(gè)場景。你在搜索時(shí)如果發(fā)現(xiàn)“SpringBoot版本太高”引發(fā)配置類找不到、依賴沖突等問題大概率是用了3.x結(jié)果自己還沒意識(shí)到JDK版本沒對(duì)上。老老實(shí)實(shí)鎖死版本號(hào)按上表來能省掉大量不必要的排查時(shí)間。前端也一樣不要一上來就去追Vue 3 Vite的組合等你把Vue 2這套跑通了原理都弄明白了再去聊新特性不遲。2. 核心技術(shù)與實(shí)現(xiàn)細(xì)節(jié)解析2.1 后端SpringBoot自動(dòng)裝配原理與項(xiàng)目分層后端這塊我先說幾個(gè)大家容易忽略但答辯會(huì)問到的點(diǎn)。SpringBoot自動(dòng)裝配到底自動(dòng)了什么簡單說SpringBoot用EnableAutoConfiguration注解開啟自動(dòng)裝配這個(gè)注解通過Import(AutoConfigurationImportSelector.class)去加載META-INF/spring.factories文件里聲明的所有配置類然后通過ConditionalOnClass、ConditionalOnProperty這類條件注解按當(dāng)前classpath和配置動(dòng)態(tài)決定哪些Bean要?jiǎng)?chuàng)建。比如你引入了spring-boot-starter-webclasspath下有DispatcherServlet它就自動(dòng)把WebMvc相關(guān)的那套Bean裝配好。放到你的停車場系統(tǒng)里這個(gè)原理體現(xiàn)在哪在你引入spring-boot-starter-data-jpa或MyBatis-Starter的時(shí)候SpringBoot自動(dòng)幫你裝配好了DataSource、SqlSessionFactory、事務(wù)管理器。你不需要寫一行XML配置只需要在application.yml里填好數(shù)據(jù)庫連接信息就行。這個(gè)“自動(dòng)”的背后就是條件裝配在起作用。后端分層這塊無論如何都要拆干凈。我習(xí)慣按這套結(jié)構(gòu)組織代碼com.example.parking ├── controller // 接收請(qǐng)求參數(shù)校驗(yàn)返回結(jié)果 ├── service // 業(yè)務(wù)邏輯層事務(wù)控制在這里 ├── mapper/repository // 數(shù)據(jù)訪問層 ├── entity/model // 實(shí)體類 ├── dto // 數(shù)據(jù)傳輸對(duì)象避免實(shí)體類直接暴露給前端 ├── config // 配置類如SecurityConfig、CorsConfig ├── common // 統(tǒng)一返回結(jié)果、異常處理、工具類 └── utils // JWT工具、日期工具等Controller只負(fù)責(zé)“翻譯”HTTP請(qǐng)求和業(yè)務(wù)層調(diào)用不寫任何具體業(yè)務(wù)判斷Service負(fù)責(zé)業(yè)務(wù)規(guī)則比如計(jì)費(fèi)邏輯、月卡校驗(yàn)Mapper做純粹的數(shù)據(jù)讀寫。這么拆完論文里寫系統(tǒng)架構(gòu)設(shè)計(jì)時(shí)直接套三層架構(gòu)的圖例說明就行說出去體面代碼也好維護(hù)。事務(wù)控制是必考題。停車?yán)U費(fèi)這個(gè)場景就是典型事務(wù)需求——生成訂單、更新錢包余額、更新車位的狀態(tài)三步必須同時(shí)成功或同時(shí)失敗。在Service層的pay()方法上標(biāo)注Transactional就好了。答辯時(shí)老師問“你這個(gè)系統(tǒng)哪里用到了事務(wù)”你把這個(gè)案例拋出來然后順便說出事務(wù)的ACID四大特性這就是加分項(xiàng)。2.2 數(shù)據(jù)庫設(shè)計(jì)三范式、核心表結(jié)構(gòu)與索引策略數(shù)據(jù)庫設(shè)計(jì)直接決定你后期寫代碼時(shí)是絲滑還是痛苦。停車場管理系統(tǒng)我建議設(shè)計(jì)這幾張核心表用戶表user_id主鍵username唯一索引passwordBCrypt加密存儲(chǔ)phonerole區(qū)分管理員/普通用戶status啟用/禁用create_time。車位表space_id主鍵space_no唯一location位置描述type普通/VIP/新能源充電車位status空閑/占用/維修price_per_hour。訂單表order_id主鍵order_no業(yè)務(wù)編號(hào)user_id關(guān)聯(lián)用戶plate_number車牌號(hào)space_id關(guān)聯(lián)車位start_time、end_timetotal_amountstatus進(jìn)行中/已完成/已取消/異常。月卡表card_id主鍵user_idplate_numberstart_dateend_datestatus待審核/生效/過期/退卡注意一個(gè)用戶可能有多輛車所以車牌號(hào)要獨(dú)立存。計(jì)費(fèi)規(guī)則表rule_idrule_nameunit_priceunit_type按小時(shí)/按次max_daily_charge封頂值start_time/end_time可設(shè)置夜間優(yōu)惠時(shí)段。設(shè)計(jì)時(shí)有三條建議第一時(shí)間字段統(tǒng)一用datetime或timestamp別用字符串存后續(xù)計(jì)算停車時(shí)長、統(tǒng)計(jì)營收會(huì)非常崩潰第二價(jià)格字段用decimal(10,2)絕不用float浮點(diǎn)數(shù)的精度問題在計(jì)費(fèi)場景是不可接受的第三常用的查詢條件字段記得加索引——用戶停車記錄按user_id查車位列表按status篩選訂單表按order_no查明細(xì)這些都是高頻率查詢。索引不是越多越好每個(gè)表3~5個(gè)就夠?qū)懖僮黝l繁的表再多就反而拖慢性能了。2.3 前端Vue路由配置、插槽與組件通信前端這塊很多人上來就寫頁面寫到一半發(fā)現(xiàn)代碼亂成一團(tuán)。先用組件化的思路拆頁面結(jié)構(gòu)views/Login.vue登錄/注冊頁views/UserHome.vue用戶端首頁車位余量、入場繳費(fèi)、月卡申請(qǐng)views/AdminDashboard.vue管理員工作臺(tái)數(shù)據(jù)統(tǒng)計(jì)views/Admin/OrderList.vue訂單管理views/Admin/SpaceManage.vue車位管理views/Admin/CardManage.vue月卡管理路由配置要分角色這是Vue路由的核心考點(diǎn)。用戶和管理員看到的頁面不一樣不能就粗暴地把所有路由堆在一起。做法是利用Vue Router的meta字段配合前置守衛(wèi)// router/index.js const routes [ { path: /login, component: Login }, { path: /, component: Layout, redirect: /dashboard, meta: { requiresAuth: true, roles: [ADMIN] }, children: [ { path: dashboard, component: AdminDashboard }, { path: orders, component: OrderList } ] }, { path: /user, component: Layout, redirect: /user/home, meta: { requiresAuth: true, roles: [USER] }, children: [ { path: home, component: UserHome } ] } ] router.beforeEach((to, from, next) { const token localStorage.getItem(token) if (to.meta.requiresAuth !token) { next(/login) } else if (token to.meta.roles !to.meta.roles.includes(store.state.role)) { next(/403) // 沒權(quán)限跳轉(zhuǎn) } else { next() } })路由守衛(wèi)幾乎是前端面試題的??湍隳苤v明白“它是怎么攔截未登錄用戶的”“如何按角色控制訪問”答辯時(shí)這一塊就穩(wěn)了。如果再能說說動(dòng)態(tài)路由也就是從后端按角色返回路由表、前端router.addRoutes動(dòng)態(tài)注冊那技術(shù)深度一下子就上去了。組件通信是Vue的另一個(gè)高頻考點(diǎn)。停車余量這個(gè)數(shù)據(jù)用戶首頁、管理員看板、車位狀態(tài)列表都要用。這種跨組件共享的狀態(tài)就別用props一級(jí)級(jí)傳了直接用Vuex管理。在store里定義parkingSpaces模塊接口返回后commit到state任何組件里mapGetters一下就能用。至于$emit自定義事件傳參適合父子組件間簡單交互比如“點(diǎn)擊車位格子觸發(fā)彈窗顯示詳情”。插槽這塊容易被忽略但實(shí)際用起來很香。我在做管理員訂單列表時(shí)Element UI的el-table里需要根據(jù)不同訂單狀態(tài)顯示不同顏色和操作按鈕待支付、已完成、異常單。這時(shí)候就用到插槽el-table-column label狀態(tài) template #default{ row } el-tag :typestatusTagMap[row.status]{{ statusTextMap[row.status] }}/el-tag /template /el-table-column這樣你就不需要為每一種狀態(tài)單獨(dú)寫一列數(shù)據(jù)和展示分離代碼簡潔也不會(huì)重復(fù)。答辯講到“組件復(fù)用”的時(shí)候把插槽和具名插槽舉出來當(dāng)例子說服力很強(qiáng)。3. 實(shí)操過程與核心環(huán)節(jié)實(shí)現(xiàn)3.1 后端工程搭建從IDEA新建到第一個(gè)接口跑通這一步我會(huì)手把手拆解實(shí)際操作過程因?yàn)楹芏嗳丝ㄔ谧铋_始的環(huán)境配置上。第一步本地環(huán)境檢查。JDK必須是1.8這個(gè)很重要——你裝了JDK17再配SpringBoot 2.5就會(huì)出問題。在終端敲java -version確認(rèn)。接著裝Maven 3.6或3.8不一定要單獨(dú)裝IDEA自帶Bundled Maven也能用但用獨(dú)立Maven更方便管理本地倉庫。第二步在IDEA里新建項(xiàng)目。選擇Spring Initializr填好Group和Artifact依賴這里沒必要勾太多——先勾Spring Web、MyBatis Framework或Spring Data JPA、MySQL Driver、Lombok這幾個(gè)。Lombok一定要勾它能用注解幫你自動(dòng)生成getter/setter省掉的代碼量是肉眼可見的。第三步配application.yml。注意數(shù)據(jù)庫連接串的寫法server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/parking_system?useUnicodetruecharacterEncodingutf-8useSSLfalseserverTimezoneAsia/Shanghai username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: mapper-locations: classpath*:mapper/**/*.xml configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImplserverTimezoneAsia/Shanghai這個(gè)參數(shù)不加數(shù)據(jù)庫連接會(huì)報(bào)時(shí)區(qū)錯(cuò)誤這是新手最常遇到的經(jīng)典坑之一。log-impl配置成StdOutImpl后控制臺(tái)能直接看到SQL日志調(diào)試聯(lián)調(diào)的時(shí)候太方便了。第四步寫第一個(gè)接口“查詢空閑車位列表”。Controller、Service、Mapper各層各寫幾行代碼。跑起來后瀏覽器訪問http://localhost:8080/api/spaces/available能在JSON里看到數(shù)據(jù)就說明后端全鏈路通了。這一步的意義在于后端的骨架搭起來了后面每加一個(gè)模塊都按同樣的方式復(fù)制粘貼就行。我個(gè)人的習(xí)慣是每寫完一個(gè)模塊就啟動(dòng)跑一遍絕不等全部寫完再啟動(dòng)。真等到全寫完再調(diào)一百個(gè)報(bào)錯(cuò)疊在一起排查起來會(huì)讓人崩潰。3.2 前端工程搭建Vue安裝、依賴配置與開發(fā)環(huán)境避坑前端這塊很多同學(xué)掛在環(huán)境配置上所以我重點(diǎn)說一下踩坑細(xì)節(jié)。Vue環(huán)境的完整安裝路徑先裝Node.js注意版本不要用最新的推薦16.x的LTS版本。裝完了終端敲node -v和npm -v確認(rèn)。然后安裝Vue CLI腳手架npm install -g vue/cli。如果這一步在國內(nèi)網(wǎng)絡(luò)環(huán)境下很慢就配一下npm淘寶鏡像源npm config set registry https://registry.npmmirror.com。這是必須的一步否則你后面npm install裝依賴可能要等到天荒地老。創(chuàng)建項(xiàng)目在項(xiàng)目根目錄下執(zhí)行vue create parking-web。選擇Manually select features手動(dòng)勾選Vue Router、VuexCSS預(yù)處理器我習(xí)慣選Less。這樣創(chuàng)建出來的項(xiàng)目自帶路由和狀態(tài)管理的目錄結(jié)構(gòu)不用自己從零搭。注意靈犀一點(diǎn)Vue CLI 5.x版本創(chuàng)建的是Vue 3項(xiàng)目如果你想按上文說的用Vue 2創(chuàng)建時(shí)選Vue CLI的Preset或版本選項(xiàng)或者直接在腳手架里手動(dòng)指定Vue版本這個(gè)細(xì)節(jié)一定要提前確認(rèn)。裝Element UI和Axiosnpm install element-ui -S npm install axios -S npm install echarts -S # 后面做統(tǒng)計(jì)圖表用封axios請(qǐng)求和統(tǒng)一Token處理在src/utils/request.js里創(chuàng)建一個(gè)axios實(shí)例設(shè)置baseURL為http://localhost:8080/api。請(qǐng)求攔截器里從localStorage取token塞到請(qǐng)求頭響應(yīng)攔截器里處理403、500等錯(cuò)誤碼同時(shí)把后端返回的結(jié)構(gòu)統(tǒng)一剝離。service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] Bearer token } return config }) service.interceptors.response.use( response { if (response.data.code ! 200) { Message.error(response.data.message) return Promise.reject(new Error(response.data.message)) } return response.data }, error { if (error.response.status 401) { localStorage.removeItem(token) router.push(/login) } return Promise.reject(error) } )這一套寫完所有頁面直接調(diào)用request.get(/xx)就行不再需要每個(gè)接口都重復(fù)寫token邏輯。答辯時(shí)老師問你“你怎么做用戶認(rèn)證的”從這個(gè)攔截器講起把JWT的流程完整說出來深度就夠了。開發(fā)環(huán)境跨域解決前后端分離開發(fā)時(shí)前端地址是localhost:3000后端接口是localhost:8080瀏覽器默認(rèn)會(huì)攔截跨域請(qǐng)求。最簡單的方案是在前端vue.config.js里配置devServer的proxymodule.exports { devServer: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }這樣前端的/api請(qǐng)求會(huì)被代理到后端地址瀏覽器視角是“同源請(qǐng)求”跨域問題直接消解。同時(shí)后端也要配置CORS策略雙保險(xiǎn)。這個(gè)點(diǎn)特別重要因?yàn)楹芏嗳寺?lián)調(diào)時(shí)一看瀏覽器報(bào)跨域就懵實(shí)際上就是少配了這一個(gè)小文件。3.3 核心業(yè)務(wù)邏輯實(shí)現(xiàn)計(jì)費(fèi)規(guī)則、月卡校驗(yàn)與數(shù)據(jù)統(tǒng)計(jì)停車計(jì)費(fèi)是業(yè)務(wù)邏輯的核心也是答辯時(shí)最容易展示技術(shù)含量的地方。我建議這樣設(shè)計(jì)計(jì)費(fèi)服務(wù)入場記錄startTime出場時(shí)先算出時(shí)長然后調(diào)用計(jì)費(fèi)規(guī)則模塊按規(guī)則計(jì)算金額。// 簡單演示實(shí)際項(xiàng)目要結(jié)合規(guī)則表動(dòng)態(tài)計(jì)算 Transactional public PayResult calculateAndPay(String orderNo) { Order order orderMapper.findByOrderNo(orderNo); long hours ChronoUnit.HOURS.between(order.getStartTime(), LocalDateTime.now()); // 不足一小時(shí)按一小時(shí)算這是簡化的取整邏輯 if (hours 0) { hours 1; } // 如果有月卡且未過期覆蓋計(jì)費(fèi) MonthlyCard card cardMapper.findByPlateAndStatus( order.getPlateNumber(), ACTIVE); if (card ! null) { order.setTotalAmount(BigDecimal.ZERO); order.setStatus(COMPLETED); return new PayResult(order, MEMBER_CARD); } // 普通計(jì)費(fèi)調(diào)用規(guī)則表里的單價(jià) BigDecimal amount ruleMapper.getCurrentRule() .getUnitPrice().multiply(BigDecimal.valueOf(hours)); // 封頂邏輯 ... order.setTotalAmount(amount); order.setStatus(COMPLETED); orderMapper.updateById(order); spaceMapper.updateStatus(order.getSpaceId(), FREE); return new PayResult(order, PAID); }這個(gè)方法的亮點(diǎn)在于把“月卡優(yōu)先”和“按時(shí)段計(jì)費(fèi)”都體現(xiàn)出來了而且邏輯集中在Service層。答辯時(shí)你能說明白“為什么要放在當(dāng)前這個(gè)方法而非拆分到Controller”“事務(wù)為什么加在這一層”那說明你真的理解了這個(gè)系統(tǒng)的運(yùn)轉(zhuǎn)方式。數(shù)據(jù)統(tǒng)計(jì)看板是論文的亮點(diǎn)展示位。用ECharts畫幾個(gè)圖——近一周營收柱狀圖、24小時(shí)車輛進(jìn)出折線圖、車位類型利用率餅圖。后端提供對(duì)應(yīng)的聚合查詢接口比如用SQL的DATE_FORMAT分組統(tǒng)計(jì)每天營收SELECT DATE_FORMAT(create_time, %Y-%m-%d) AS day, SUM(total_amount) AS revenue FROM parking_order WHERE status COMPLETED GROUP BY DATE_FORMAT(create_time, %Y-%m-%d) ORDER BY day前端拿到數(shù)組以后用ECharts幾行代碼就能渲染出來。這塊呈現(xiàn)到論文上是“可視化數(shù)據(jù)展示”放到系統(tǒng)演示環(huán)節(jié)是“哇有個(gè)大屏看板”投入產(chǎn)出比極高。3.4 發(fā)布部署Vue打包放進(jìn)SpringBoot里畢設(shè)最后驗(yàn)收通常需要交付一個(gè)能直接跑起來演示的完整系統(tǒng)。兩邊分開部署不現(xiàn)實(shí)最簡單可靠的方式是把Vue打包后的靜態(tài)文件放進(jìn)SpringBoot里用一個(gè)8080端口搞定所有。第一步前端打包。在項(xiàng)目根目錄執(zhí)行npm run build靜態(tài)資源會(huì)輸出到dist文件夾。如果你的路由用了history模式在vue.config.js里配一下publicPath: ./否則部署后靜態(tài)資源路徑會(huì)找不到頁面白屏。這一步很多教程不會(huì)細(xì)說但是幾乎每個(gè)人都會(huì)踩到。第二步把dist整個(gè)文件夾復(fù)制到SpringBoot的src/main/resources/static目錄下。SpringBoot默認(rèn)情況下靜態(tài)文件放在這個(gè)目錄就能直接通過localhost:8080訪問到。第三步做一個(gè)兜底路由。Vue是SPA前端路由由js控制如果用戶直接訪問http://localhost:8080/admin/dashboard后端兜底到index.html由前端再接管路由。配置方式是在后端加一個(gè)ViewContorller或者直接寫一個(gè)Controller處理轉(zhuǎn)發(fā)Controller public class PageForwardController { RequestMapping(value /**/{path:[^\\.]*}) public String forward() { return forward:/index.html; } }注意這里的正則表達(dá)式排除了帶點(diǎn)的路徑不會(huì)影響接口請(qǐng)求和靜態(tài)資源文件本身。第四步打包后端。在IDEA右側(cè)Maven面板里執(zhí)行clean再執(zhí)行package生成target目錄下那個(gè)parking-0.0.1-SNAPSHOT.jar。然后在命令行里執(zhí)行java -jar parking-0.0.1-SNAPSHOT.jar。瀏覽器打開http://localhost:8080就能看到完整的系統(tǒng)了。這一個(gè)Jar包就能演示全部功能驗(yàn)收現(xiàn)場只需要一臺(tái)電腦。4. 常見問題與排查技巧實(shí)錄做了這么多次類似項(xiàng)目我把最典型的問題整理成速查表你可以直接拿來當(dāng)排障手冊用?,F(xiàn)象大概率原因解決方案SpringBoot項(xiàng)目啟動(dòng)失敗提示DataSource相關(guān)錯(cuò)誤沒配數(shù)據(jù)庫連接或MySQL沒啟動(dòng)檢查application.yml配置確認(rèn)MySQL服務(wù)已啟動(dòng)賬號(hào)密碼正確前端頁面白屏控制臺(tái)報(bào)靜態(tài)資源404publicPath配置不對(duì)或dist路徑不對(duì)Vue項(xiàng)目設(shè)publicPath: ./重新打包目錄確認(rèn)放到static根路徑下列表頁能打開點(diǎn)擊查詢后報(bào)跨域錯(cuò)誤前后端跨域未處理前端配devServer.proxy后端配CorsConfig雙重保障登錄失敗一直提示用戶名或密碼錯(cuò)誤密碼沒做加密導(dǎo)致比對(duì)不一致后端確認(rèn)用的是BCryptPasswordEncoder加密和matches校驗(yàn)保存訂單后事務(wù)不生效Service類上沒加Transactional或方法不是public檢查注解位置注意Spring對(duì)非public方法的代理限制接口報(bào)500但SQL日志沒打印MyBatis映射文件里的SQL有誤或resultType錯(cuò)誤打開log-impl: StdOutImpl看完整SQL在Navicat里手動(dòng)跑一遍驗(yàn)證上傳的圖片顯示不了路徑不對(duì)靜態(tài)資源映射沒配置或路徑拼接錯(cuò)誤確認(rèn)圖片保存路徑和訪問路徑一致用絕對(duì)URI拼接訪問地址排查思路心法遇到報(bào)錯(cuò)先看最上層的異常信息不要慌著翻日志全文。大多數(shù)情況是“配置缺失”或“依賴版本沖突”兩個(gè)原因之一。SpringBoot的報(bào)錯(cuò)信息其實(shí)寫得很貼心它會(huì)直接告訴你缺什么類、少什么配置。按著提示一步步排查比漫無目的地搜“SpringBoot xxx報(bào)錯(cuò)”要快得多。另外說兩個(gè)容易忽視的坑第一寫SQL時(shí)表名和字段名盡量不要和MySQL關(guān)鍵字沖突。比如我見過有人把表名命名為order結(jié)果插入時(shí)永遠(yuǎn)報(bào)語法錯(cuò)誤因?yàn)閛rder是保留字。要么加反引號(hào)要么直接叫parking_order后者更省心。第二JWT密鑰不要寫在代碼里硬編碼。放到application.yml里用Value注入論文里可以順帶提一句“使用配置化密鑰管理提高安全性”顯得考慮周全。同理數(shù)據(jù)庫密碼也不要寫死在代碼里配置化是最好的習(xí)慣。答辯前一周過一遍技術(shù)問答清單SpringBoot自動(dòng)裝配的原理是什么說說SpringMVC的處理流程從請(qǐng)求到響應(yīng)的完整過程。JWT認(rèn)證相比Session的優(yōu)勢在哪logout如何實(shí)現(xiàn)Vue響應(yīng)式數(shù)據(jù)的原理是什么路由守衛(wèi)在什么場景下用到怎么實(shí)現(xiàn)登錄攔截?cái)?shù)據(jù)庫的索引在哪些字段上建了為什么全部能用自己的話講一遍答辯基本穩(wěn)過。再補(bǔ)充一個(gè)經(jīng)驗(yàn)別忘了在GitHub上建個(gè)倉庫從第一天就把代碼推上去。這不僅是版本管理的問題論文里你可以寫“項(xiàng)目使用Git進(jìn)行版本控制”然后截一張?zhí)峤粴v史圖放進(jìn)開發(fā)工具章節(jié)真實(shí)感直接拉滿。而且萬一代碼寫崩了能隨時(shí)回滾到前一天能跑的版本這個(gè)安全感是任何本地備份都給不了的。我個(gè)人最后一次完整做這套系統(tǒng)的時(shí)候最有感觸的一點(diǎn)是真正花費(fèi)時(shí)間的不是寫代碼本身而是前后端的接口定義和字段對(duì)齊。所以我會(huì)建議你們在動(dòng)手之前先把所有接口的請(qǐng)求參數(shù)、響應(yīng)結(jié)構(gòu)用表格列出來比如“POST /api/user/login 參數(shù)username,password 返回token,role,userInfo”。前端按這張表調(diào)開發(fā)后端按這張表做實(shí)現(xiàn)兩邊各干各的也不會(huì)跑偏聯(lián)調(diào)時(shí)間能縮到極短。這個(gè)習(xí)慣哪怕畢業(yè)之后進(jìn)了團(tuán)隊(duì)做開發(fā)一樣是剛需。最后說一句實(shí)在話畢設(shè)的意義不在于做出一個(gè)完美無缺的商業(yè)系統(tǒng)而在于讓你完整體驗(yàn)一遍“從需求分析到設(shè)計(jì)、開發(fā)、測試、部署”的全流程。這個(gè)SpringBootVue停車場管理系統(tǒng)恰好能把這些環(huán)節(jié)都覆蓋到而且每一環(huán)都有足夠深的技術(shù)點(diǎn)可以挖。把這篇里面提到的細(xì)節(jié)吃透你不僅是在完成一個(gè)題目還在畢業(yè)前把一名后端開發(fā)最核心的技能棧扎扎實(shí)實(shí)過了一遍。這套積累的含金量比成績單上的那個(gè)分?jǐn)?shù)值錢多了。