用車4S店管理系統(tǒng)實(shí)戰(zhàn)解析)
每年到了畢業(yè)季計(jì)算機(jī)專業(yè)的同學(xué)就開始為選題頭疼。電商、商城、博客、會(huì)議室預(yù)約這些老面孔估計(jì)不少人都看厭了。我今天想認(rèn)真聊聊一個(gè)比較冷門但很實(shí)用的切入點(diǎn)基于springboot的農(nóng)用車4S店管理系統(tǒng)。這套題目如果你正在猶豫選什么或者已經(jīng)在開發(fā)路上卡住了這篇內(nèi)容應(yīng)該能幫你省不少事。它不光是做一個(gè)CRUD交差而是能讓你把進(jìn)銷存、售后維修、客戶管理一條鏈路全走通不管是拿來應(yīng)付畢設(shè)答辯還是想真的學(xué)點(diǎn)企業(yè)級(jí)項(xiàng)目的門道都挺合適。這個(gè)選題最舒服的地方在于業(yè)務(wù)場景你不需要憑空想象。農(nóng)用車的4S店和家用車4S店不一樣客戶基本都是周邊鄉(xiāng)鎮(zhèn)的種植戶和農(nóng)機(jī)手買的不是轎車而是拖拉機(jī)、收割機(jī)這類生產(chǎn)工具。這就意味著系統(tǒng)里必須把購機(jī)客戶檔案、農(nóng)機(jī)維修記錄、三包期內(nèi)配件更換、季節(jié)性的保養(yǎng)提醒這些真實(shí)需求都做進(jìn)去。相比千篇一律的圖書管理、商品下訂單這套系統(tǒng)在業(yè)務(wù)邏輯上更有深度答辯的時(shí)候老師可問的東西也多你反而更容易展示自己對(duì)業(yè)務(wù)的理解。我當(dāng)時(shí)給一個(gè)模擬項(xiàng)目做技術(shù)方案的時(shí)候花了比較多的時(shí)間在琢磨一個(gè)問題這套系統(tǒng)的核心價(jià)值到底在哪后來想明白了它本質(zhì)上不是一個(gè)普通的進(jìn)銷存而是一個(gè)圍繞農(nóng)機(jī)全生命周期的服務(wù)閉環(huán)。從客戶進(jìn)店咨詢、選型、簽合同、交車再到后面的首保、定期保養(yǎng)、故障維修、配件更換全部串起來。所以數(shù)據(jù)庫設(shè)計(jì)的時(shí)候就不能簡單搞幾張車輛表和訂單表完事得把業(yè)務(wù)狀態(tài)流轉(zhuǎn)、角色權(quán)限、統(tǒng)計(jì)報(bào)表這些都考慮進(jìn)去。下面我把整個(gè)思路和實(shí)操細(xì)節(jié)掰開揉碎了寫一遍。1. 內(nèi)容整體設(shè)計(jì)與思路拆解1.1 為什么選中springboot而不是SSH或SSM先說技術(shù)選型。很多畢設(shè)題目寫的是基于SSM框架但到現(xiàn)在這個(gè)時(shí)間點(diǎn)我建議是直接上springboot。道理很簡單SSM的痛點(diǎn)在于配置文件極其繁瑣spring、springmvc、mybatis三個(gè)框架各自一堆XML配置光讓它們?cè)谕粋€(gè)容器里協(xié)作就得折騰好幾天而這部分工作量對(duì)畢設(shè)來說毫無意義。springboot把約定大于配置做到了極致內(nèi)嵌Tomcat一鍵啟動(dòng)main方法就完事你省下來的時(shí)間可以全部用在業(yè)務(wù)邏輯上??赡苡腥擞X得用老框架顯得技術(shù)扎實(shí)其實(shí)恰恰相反?,F(xiàn)在出去面試聊到新項(xiàng)目還說自己手動(dòng)配SSM面試官會(huì)懷疑你是不是這幾年都沒有更新技術(shù)棧。springboot是當(dāng)前Java后端開發(fā)的事實(shí)標(biāo)準(zhǔn)學(xué)了以后工作里直接能用。而且springboot對(duì)畢設(shè)還有一個(gè)好處它自帶自動(dòng)配置的特性你在寫控制器和Mapper的時(shí)候可以明顯感受到代碼量更少、項(xiàng)目結(jié)構(gòu)更清晰。對(duì)于畢設(shè)這種時(shí)間緊張、但又要求跑通演示的場景無腦選springboot就對(duì)了。從項(xiàng)目體量來看農(nóng)用車4S店管理系統(tǒng)這種體量用springboot也剛剛好。模塊多實(shí)體類大概十幾張表業(yè)務(wù)接口幾十個(gè)但單機(jī)部署完全夠用不需要上微服務(wù)那一套。硬要引入Spring Cloud、消息隊(duì)列反而顯得大炮打蚊子答辯時(shí)也很難自圓其說。1.2 技術(shù)棧與模塊劃分的取舍邏輯整套系統(tǒng)的標(biāo)準(zhǔn)技術(shù)棧我按實(shí)際經(jīng)驗(yàn)排一下Java 8 Spring Boot 2.x MyBatis Plus MySQL 5.7/8.0 Redis可選 Vue / Thymeleaf前端方案二選一。這里有個(gè)關(guān)鍵取舍要說明白前端到底用前后端分離的Vue還是服務(wù)端渲染的Thymeleaf模板如果你的側(cè)重點(diǎn)是展示后端能力和業(yè)務(wù)邏輯前端基礎(chǔ)又一般那Thymeleaf更穩(wěn)妥。它和springboot配合得非常順滑不用跨域、不用Nginx部署打包成一個(gè)jar直接跑。缺點(diǎn)是頁面寫起來不夠精細(xì)交互效果受限制。如果你前端本身有點(diǎn)底子想用Vue把界面做得漂漂亮亮的那前后端分離方案絕對(duì)加分JSON交互、Restful風(fēng)格接口都是加分項(xiàng)。但代價(jià)是工作量翻倍你得單獨(dú)部署前端環(huán)境和聯(lián)調(diào)接口出問題排查起來也麻煩。從穩(wěn)妥角度考慮我個(gè)人的建議更偏向Thymeleaf加Bootstrap的輕量模板方案原因是畢設(shè)的重心永遠(yuǎn)是系統(tǒng)的功能完整性和業(yè)務(wù)閉環(huán)而不是花里胡哨的界面。你把一個(gè)頁面做得再炫如果登錄驗(yàn)證的權(quán)限邏輯都講不清楚老師還是不會(huì)給你高分的。模塊劃分通常分成這些系統(tǒng)管理員工登錄、角色權(quán)限、密碼修改、客戶管理購機(jī)客戶檔案、聯(lián)系人、歷史訂單、車輛管理車輛庫存、車輛品牌與型號(hào)、入庫出庫、銷售管理購機(jī)訂單、交車記錄、應(yīng)收款項(xiàng)、售后管理維修工單、保養(yǎng)記錄、三包申報(bào)、配件管理配件庫存、出入庫流水、統(tǒng)計(jì)報(bào)表銷售統(tǒng)計(jì)、維修頻次分析。每個(gè)模塊之間要保持清晰的數(shù)據(jù)關(guān)聯(lián)后面我在數(shù)據(jù)庫設(shè)計(jì)部分詳細(xì)講。1.3 這個(gè)系統(tǒng)比普通管理系統(tǒng)的難度高在哪很多學(xué)生做過圖書管理系統(tǒng)、學(xué)生管理系統(tǒng)最大的感覺是太簡單一張表一個(gè)頁面就是一個(gè)模塊邏輯上毫無挑戰(zhàn)。農(nóng)用車4S店管理系統(tǒng)不一樣的地方在于它有一條核心業(yè)務(wù)主鏈路車輛到店入庫、展廳展示、客戶簽訂購車合同、財(cái)務(wù)收款、售后建立車輛檔案、定期保養(yǎng)提醒、維修工單開單。這條鏈路里每一步都會(huì)改變車輛的狀態(tài)和其他業(yè)務(wù)表的數(shù)據(jù)。舉一個(gè)具體例子一輛拖拉機(jī)入庫時(shí)狀態(tài)是“在庫”客戶看中后下單購買狀態(tài)變?yōu)椤耙咽邸蓖瑫r(shí)系統(tǒng)自動(dòng)為客戶檔案綁定這輛車的車架號(hào)信息之后售后保養(yǎng)模塊才能根據(jù)這臺(tái)車的車架號(hào)生成保養(yǎng)記錄。如果只是在車輛表里改一個(gè)狀態(tài)字段而訂單表、客戶表、售后檔案表沒有同步聯(lián)動(dòng)系統(tǒng)就是割裂的答辯時(shí)一問到數(shù)據(jù)一致性就露餡。這也是為什么我說做這種項(xiàng)目一定要先用思維導(dǎo)圖把業(yè)務(wù)流轉(zhuǎn)理順不要急著寫代碼。數(shù)據(jù)表之間有外鍵關(guān)聯(lián)、有狀態(tài)機(jī)這些才是真正值錢的地方。另外還有一個(gè)被很多人忽略的難點(diǎn)農(nóng)用車的特殊業(yè)務(wù)屬性。農(nóng)機(jī)有國補(bǔ)、地補(bǔ)政策銷售訂單里往往要記錄補(bǔ)貼信息農(nóng)忙季節(jié)維修需求集中爆發(fā)售后模塊得支持緊急插單和工單優(yōu)先級(jí)零配件里有很多是易損件庫存在農(nóng)忙前后波動(dòng)很大所以配件出入庫必須帶時(shí)間戳和操作人。這些細(xì)節(jié)如果做進(jìn)去系統(tǒng)立刻就和網(wǎng)上的普通Demo拉開了檔次技術(shù)含量是實(shí)實(shí)在在的老師一看就知道你不是照著教程敲了一邊。2. 數(shù)據(jù)庫設(shè)計(jì)與核心模塊核心細(xì)節(jié)解析2.1 核心表結(jié)構(gòu)與關(guān)鍵字段設(shè)計(jì)數(shù)據(jù)庫設(shè)計(jì)是整套系統(tǒng)的地基這里務(wù)必多花時(shí)間。我用白話說一下最佳實(shí)踐表最好別少于10張不然業(yè)務(wù)展現(xiàn)不出來。標(biāo)準(zhǔn)表清單大致是這幾類第一是用戶權(quán)限域員工表管理員、銷售員、維修工、倉管員等角色可以用角色字段區(qū)分或者拆成用戶表加角色表。畢設(shè)級(jí)別用字段區(qū)分加一個(gè)簡單的登錄攔截就夠了不用上Spring Security那套太重的權(quán)限模型但如果想在答辯的時(shí)候多聊點(diǎn)技術(shù)引入一個(gè)role字段然后用攔截器判斷也完全說得過去。第二是基礎(chǔ)數(shù)據(jù)域車輛品牌表、車輛型號(hào)表、配件分類表。這幾個(gè)表主要是為了解決數(shù)據(jù)冗余問題下拉框的數(shù)據(jù)源都可以從這些表里動(dòng)態(tài)查詢而不是在前端寫死。舉個(gè)例子車輛入庫的時(shí)候需要選擇品牌和型號(hào)如果在車輛表里直接寫字符串到時(shí)候要改品牌名稱就得全表更新很麻煩。用外鍵關(guān)聯(lián)一行update就能搞定。第三是核心業(yè)務(wù)域客戶表、車輛庫存表、銷售訂單表、維修工單表、保養(yǎng)記錄表、配件庫存表、配件出入庫記錄表。每張表的關(guān)鍵字段我建議這樣設(shè)計(jì)客戶表姓名、手機(jī)號(hào)、身份證號(hào)保險(xiǎn)起見可加密或脫敏、所屬村鎮(zhèn)、客戶類型、備注加上創(chuàng)建時(shí)間和更新時(shí)間。車輛庫存表品牌ID、型號(hào)ID、車架號(hào)唯一、發(fā)動(dòng)機(jī)號(hào)、顏色、購入價(jià)格、銷售價(jià)格、入庫時(shí)間、庫存狀態(tài)。銷售訂單表訂單編號(hào)用時(shí)間戳加隨機(jī)數(shù)自定義生成客戶ID、車輛ID、成交價(jià)格、補(bǔ)貼金額、付款方式、訂單狀態(tài)、銷售員ID、簽訂時(shí)間。維修工單表工單編號(hào)、客戶ID、車輛ID、故障描述、工單狀態(tài)待接單、維修中、待結(jié)算、已完成、維修工ID、開單時(shí)間、完成時(shí)間、工時(shí)費(fèi)用。配件出入庫表配件ID、數(shù)量、方向入或出、關(guān)聯(lián)單號(hào)、操作人ID、操作時(shí)間。這里不直接改配件庫存表里的庫存數(shù)字而是每次操作都記錄一條流水這樣以后對(duì)賬、查歷史都有據(jù)可依是一個(gè)很實(shí)用的經(jīng)驗(yàn)。2.2 為什么狀態(tài)字段比刪除字段更重要在開發(fā)管理系統(tǒng)時(shí)很多初學(xué)者喜歡直接物理刪除數(shù)據(jù)比如客戶退掉訂單就直接把訂單記錄delete掉。這個(gè)做法在畢業(yè)設(shè)計(jì)里是大忌。一方面物理刪除會(huì)讓業(yè)務(wù)流水?dāng)嗟裟銢]法在統(tǒng)計(jì)報(bào)表里分析歷史數(shù)據(jù)另一方面老師問起“訂單取消了你怎么辦”如果你回答直接把數(shù)據(jù)刪了印象分會(huì)大打折扣。正確做法是給關(guān)鍵業(yè)務(wù)表設(shè)置狀態(tài)字段。訂單可以有“待付款、已付款、已交車、已取消”這么幾個(gè)狀態(tài)取消不是刪數(shù)據(jù)而是把狀態(tài)改成已取消并記錄取消原因。車輛庫存有“在庫、已預(yù)訂、已售、維修中”的狀態(tài)維修工單有“待接單、維修中、待結(jié)算、已完成”的狀態(tài)。狀態(tài)字段還有一個(gè)好處就是你在做列表頁篩選的時(shí)候特別方便一個(gè)下拉框就能把不同狀態(tài)的數(shù)據(jù)區(qū)分開前端的展示邏輯也簡單了。我給農(nóng)用車系統(tǒng)畫狀態(tài)流轉(zhuǎn)的時(shí)候會(huì)明確每一步能走到哪里。比如銷售訂單只有“已付款”狀態(tài)才能進(jìn)行交車操作“已取消”狀態(tài)不能直接改成“已完成”。這種狀態(tài)機(jī)的概念雖然在畢設(shè)里可以不做得那么嚴(yán)格但你心里得有一個(gè)清晰的流轉(zhuǎn)地圖寫Service層方法的時(shí)候就不會(huì)亂。2.3 權(quán)限控制和登錄攔截的兩種常見做法權(quán)限控制是系統(tǒng)管理模塊的核心也是答辯時(shí)的高頻提問點(diǎn)。常見的兩種實(shí)現(xiàn)方式各有適用場景。第一種是攔截器加Session。寫一個(gè)HandlerInterceptor在preHandle方法里判斷用戶是否登錄session里有沒有user對(duì)象沒登錄就重定向到登錄頁。然后通過注冊(cè)攔截器配置好攔截路徑和放行路徑比如登錄接口和靜態(tài)資源放行。這個(gè)方法簡單直觀、代碼量少適合Thymeleaf模板方案我比較推薦。缺點(diǎn)是如果要做細(xì)粒度的權(quán)限比如銷售員不能訪問配件管理頁面需要在攔截器里額外判斷角色的URL權(quán)限代碼稍微變多。第二種是Spring Security框架整合。功能強(qiáng)大支持基于角色的權(quán)限控制、方法級(jí)安全校驗(yàn)、記住我等功能但配置相對(duì)復(fù)雜學(xué)習(xí)成本高。如果為了省事用Spring Security默認(rèn)配置反而在做自定義登錄邏輯時(shí)要處理很多細(xì)節(jié)可能比攔截器方案更費(fèi)時(shí)間。畢設(shè)建議使用攔截器方案把精力留在業(yè)務(wù)功能上如果答辯老師問為什么不使用Spring Security可以從項(xiàng)目體量輕量化、避免過度設(shè)計(jì)這個(gè)角度來回答完全站得住腳。2.4 車輛銷售與售后維修的聯(lián)動(dòng)邏輯這個(gè)聯(lián)動(dòng)邏輯是系統(tǒng)設(shè)計(jì)的點(diǎn)睛之筆。車輛一經(jīng)銷售系統(tǒng)就應(yīng)該自動(dòng)做三件事第一在車輛庫存表里把該車輛的狀態(tài)改為“已售”并記錄銷售時(shí)間第二在客戶表里把該車輛的車架號(hào)綁定到客戶檔案也就是一個(gè)客戶可以查到他名下所有購買過的農(nóng)機(jī)第三自動(dòng)生成一條保養(yǎng)記錄初始數(shù)據(jù)首次保養(yǎng)時(shí)間通常是提車后的某個(gè)時(shí)間間隔這部分可以在Service層實(shí)現(xiàn)。售后維修的流程則是反向關(guān)聯(lián)。當(dāng)一臺(tái)農(nóng)用車進(jìn)店維修維修工單需要根據(jù)客戶選擇或者車牌號(hào)/車架號(hào)自動(dòng)帶出車輛型號(hào)和客戶信息。單據(jù)完成結(jié)算后費(fèi)用信息還要能匯總到客戶的消費(fèi)記錄里。這種多表聯(lián)動(dòng)的邏輯在代碼層面不難其實(shí)就是在Service層里寫update和insert的組合操作注意加上Transactional事務(wù)注解。事務(wù)是這個(gè)系統(tǒng)里非常重要的一個(gè)技術(shù)點(diǎn)只要涉及多表寫入的操作都必須加上否則中途報(bào)錯(cuò)會(huì)出現(xiàn)臟數(shù)據(jù)。答辯時(shí)你主動(dòng)提一句“我在多表操作時(shí)加了事務(wù)控制”老師的印象會(huì)完全不一樣。開發(fā)具體的代碼順序上建議從下往上寫先建實(shí)體類和Mapper接口然后Service接口加ServiceImpl實(shí)現(xiàn)類最后Controller層才寫接口。實(shí)體類的字段對(duì)應(yīng)數(shù)據(jù)庫表的字段建議用MyBatis Plus的代碼生成器插件可以從數(shù)據(jù)庫表直接生成實(shí)體類、Mapper和Service省去大量手寫樣板代碼的時(shí)間。不過注意生成的代碼只算是骨架核心業(yè)務(wù)邏輯你還是要自己寫。3. 實(shí)操過程與核心環(huán)節(jié)實(shí)現(xiàn)3.1 項(xiàng)目初始化與依賴配置要點(diǎn)用IDEA創(chuàng)建Spring Initializr項(xiàng)目在pom.xml里加依賴時(shí)要注意版本匹配。Spring Boot 2.7.x版本搭配MyBatis Plus 3.5.x是比較穩(wěn)妥的組合Redis如果有引入注意版本兼容。MySQL驅(qū)動(dòng)用mysql-connector-j如果是MySQL 8.0還要配置時(shí)區(qū)參數(shù)。關(guān)鍵的配置文件application.yml示例大概是這樣的server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/agricultural_4s?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: 你的密碼 mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0這段配置文件里有幾個(gè)點(diǎn)很關(guān)鍵。map-underscore-to-camel-case打開后數(shù)據(jù)庫的下劃線字段比如customer_name可以自動(dòng)映射到實(shí)體類的駝峰屬性customerName省掉大量手寫映射的麻煩。logic-delete-field配置了邏輯刪除的全局字段這樣調(diào)用MyBatis Plus的刪除方法時(shí)實(shí)際執(zhí)行的是update語句把deleted字段改成1數(shù)據(jù)并沒有真正消失。這跟我上一部分說的狀態(tài)字段思想是一致的全局配置一個(gè)邏輯刪除字段可以統(tǒng)一規(guī)范。3.2 登錄模塊與攔截器配置的完整實(shí)現(xiàn)登錄模塊看似簡單但有幾個(gè)細(xì)節(jié)不處理容易翻車。密碼存數(shù)據(jù)庫建議用MD5加鹽或者用更安全的BCrypt。如果把明文密碼直接存數(shù)據(jù)庫一旦論文被老師翻了數(shù)據(jù)庫截圖會(huì)非常尷尬。登錄流程是這樣的前端提交用戶名和密碼后端Service層先根據(jù)用戶名查出員工記錄然后比對(duì)密碼加鹽再M(fèi)D5后比對(duì)如果一致就把員工對(duì)象放進(jìn)Session同時(shí)重定向到首頁。如果用戶名不存在或者密碼不對(duì)返回錯(cuò)誤提示。對(duì)應(yīng)攔截器代碼寫一個(gè)類實(shí)現(xiàn)HandlerInterceptor接口public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 放行登錄請(qǐng)求和靜態(tài)資源 if (request.getRequestURI().contains(/login) || request.getRequestURI().contains(/css) || request.getRequestURI().contains(/js) || request.getRequestURI().contains(/images)) { return true; } // 判斷是否已登錄 Object user request.getSession().getAttribute(loginUser); if (user null) { response.sendRedirect(/login); return false; } return true; } }然后在配置類里注冊(cè)攔截器排除登錄接口和靜態(tài)資源路徑。這一步配好之后整個(gè)系統(tǒng)的頁面訪問就都有了安全保護(hù)。我做項(xiàng)目的時(shí)候踩過一個(gè)坑就是靜態(tài)資源路徑?jīng)]放行導(dǎo)致登錄頁的CSS全部加載不出來頁面樣式全丟。排查了半天才意識(shí)到是攔截器把靜態(tài)資源也攔了所以這里一定要把/css/**、/js/**、/images/**這些路徑都排除掉。3.3 車輛入庫到銷售出庫的完整流程編碼車輛入庫流程前端頁面是一個(gè)表單填寫品牌、型號(hào)、車架號(hào)、發(fā)動(dòng)機(jī)號(hào)、成本價(jià)、銷售指導(dǎo)價(jià)后端Controller接收到Vehicle實(shí)體后檢查車架號(hào)是否已存在唯一性校驗(yàn)然后insert入庫庫存狀態(tài)默認(rèn)是“在庫”并把入庫操作記錄到日志里或者直接返回成功提示。銷售出庫更復(fù)雜一點(diǎn)核心邏輯在Service層。銷售員選中一位客戶和一輛在庫車輛填寫成交價(jià)格和補(bǔ)貼金額點(diǎn)擊確認(rèn)。Service層方法執(zhí)行順序如下先查詢車輛是否存在且狀態(tài)為在庫然后查詢客戶是否存在再insert一條銷售訂單狀態(tài)為待付款同時(shí)把車輛狀態(tài)改到“已預(yù)訂”。付款確認(rèn)操作執(zhí)行時(shí)修改訂單狀態(tài)為已付款車輛狀態(tài)改成已售客戶檔案綁定車輛信息。這幾步操作必須放在同一個(gè)事務(wù)里任何一個(gè)環(huán)節(jié)失敗所有操作都回滾。Transactional(rollbackFor Exception.class) public boolean confirmSale(SaleOrder order) { // 1. 校驗(yàn)車輛狀態(tài) Vehicle vehicle vehicleMapper.selectById(order.getVehicleId()); if (vehicle null || !在庫.equals(vehicle.getStatus())) { throw new RuntimeException(車輛不存在或狀態(tài)異常); } // 2. 創(chuàng)建訂單 order.setOrderNo(generateOrderNo()); order.setStatus(待付款); saleOrderMapper.insert(order); // 3. 鎖定車輛 vehicle.setStatus(已預(yù)訂); vehicleMapper.updateById(vehicle); return true; }我再提一個(gè)很實(shí)用的發(fā)明訂單編號(hào)生成規(guī)則一般不用自增ID直接給用戶看而是自定義生成比如XS加日期加四位隨機(jī)數(shù)這樣既保證唯一性又顯得專業(yè)。生成時(shí)注意加同步鎖或者用UUID片段避免并發(fā)重復(fù)。3.4 售后維修工單的拆解與狀態(tài)流轉(zhuǎn)售后維修模塊是農(nóng)用車4S店系統(tǒng)的特色也是很多同學(xué)卡住的地方。維修工單的數(shù)據(jù)來源有兩類一是從客戶來電報(bào)修直接開單二是從預(yù)約保養(yǎng)提醒系統(tǒng)生成建議工單。工單單據(jù)要能處理一個(gè)多對(duì)多的關(guān)系一張工單可以關(guān)聯(lián)多個(gè)維修項(xiàng)目和多個(gè)更換配件。設(shè)計(jì)上建議拆成維修工單主表和維修明細(xì)表或者叫工單配件表。主表存工單號(hào)、客戶、車輛、總費(fèi)用、狀態(tài)、時(shí)間明細(xì)表存每個(gè)維修項(xiàng)目名稱、工時(shí)費(fèi)、更換的配件和數(shù)量。這樣設(shè)計(jì)后你在做統(tǒng)計(jì)報(bào)表的時(shí)候就能很容易地分析出哪個(gè)配件消耗最快、哪個(gè)維修項(xiàng)目出現(xiàn)頻率最高這些都是答辯時(shí)非常有分量的分析結(jié)果。維修工單狀態(tài)流轉(zhuǎn)我習(xí)慣這樣設(shè)計(jì)待接單、維修中、待結(jié)算、已完成、已取消。維修工登錄系統(tǒng)后看到待接單列表點(diǎn)擊接單后狀態(tài)改為維修中維修完成填寫維修結(jié)論和費(fèi)用明細(xì)狀態(tài)改為待結(jié)算財(cái)務(wù)確認(rèn)收款后狀態(tài)改為已完成。每一個(gè)狀態(tài)變更都要記錄操作日志可以用一個(gè)簡單的工單狀態(tài)歷史表來實(shí)現(xiàn)。這里也提醒一下不要把太多業(yè)務(wù)邏輯寫在Controller里。很多同學(xué)直接在Controller里寫上幾十行業(yè)務(wù)代碼看起來也能運(yùn)行但Controller層臃腫不堪。正確做法是Controller只負(fù)責(zé)接收參數(shù)、調(diào)用Service、返回結(jié)果業(yè)務(wù)邏輯全部封裝在Service層。這樣的分層結(jié)構(gòu)不僅代碼清晰還方便你寫單元測試答辯的時(shí)候說“我的業(yè)務(wù)邏輯都在Service層便于代碼復(fù)用和維護(hù)”這是一個(gè)很加分的點(diǎn)。3.5 報(bào)表統(tǒng)計(jì)模塊的實(shí)現(xiàn)思路與SQL示例統(tǒng)計(jì)報(bào)表是這類管理系統(tǒng)的門面哪怕功能簡單只要有這一塊系統(tǒng)完整度立刻高很多。常見的統(tǒng)計(jì)維度有銷售總金額按月、按季度、熱銷車輛型號(hào)排行、維修工單數(shù)量走勢、配件庫存預(yù)警低于安全庫存的配件列表。如果不想引入復(fù)雜的前端圖表庫可以用后端的服務(wù)端渲染把所有統(tǒng)計(jì)數(shù)據(jù)算好放到Model里然后前端用簡單表格加CSS來展示。如果用了Vue、ECharts那效果會(huì)更炫但工作量也相應(yīng)增加。核心是這個(gè)統(tǒng)計(jì)SQL怎么寫我舉一個(gè)稍微有點(diǎn)代表性的例子統(tǒng)計(jì)每個(gè)月份的銷售額和訂單數(shù)。SELECT DATE_FORMAT(create_time, %Y-%m) AS month, COUNT(*) AS order_count, SUM(actual_amount) AS total_amount FROM sale_order WHERE status 已付款 GROUP BY DATE_FORMAT(create_time, %Y-%m) ORDER BY month DESC這類分組統(tǒng)計(jì)SQL一定要自己會(huì)寫并且能解釋清楚GROUP BY的含義。很多同學(xué)在用MyBatis Plus時(shí)基本不寫SQL導(dǎo)致統(tǒng)計(jì)報(bào)表的時(shí)候完全不會(huì)了。我的建議是統(tǒng)計(jì)類操作不要用MyBatis Plus的Wrapper直接寫XML里的自定義SQL映射雖然多寫一點(diǎn)代碼但邏輯清晰、可控性強(qiáng)排查問題也直接。4. 常見問題與排查技巧實(shí)錄4.1 IDEA和Maven相關(guān)的高頻問題項(xiàng)目導(dǎo)入IDEA后經(jīng)常遇到Maven依賴下載失敗或者jar包紅線的場景這個(gè)問題基本可以歸結(jié)為網(wǎng)絡(luò)和鏡像源配置。建議在Maven的settings.xml里配置國內(nèi)鏡像源替換中央倉庫的下載地址這樣依賴下載速度會(huì)快很多。還有一個(gè)容易忽略的點(diǎn)是Java版本與Spring Boot版本匹配問題比如用了Spring Boot 3.x卻配了Java 8項(xiàng)目根本跑不起來。Spring Boot 3.x要求Java 17及以上如果你電腦上裝的是Java 8用Spring Boot 2.7.x系列才是正確選擇。很多同學(xué)盲目用了最新版導(dǎo)致編譯失敗折騰半天還以為是代碼問題。另一個(gè)坑是子模塊依賴問題尤其是在多模塊項(xiàng)目中。畢設(shè)階段一般不用拆多個(gè)模塊一個(gè)Spring Boot工程結(jié)構(gòu)就夠用了按包名劃分功能controller、service、mapper、pojo、config等會(huì)更加清晰、不容易出錯(cuò)。4.2 數(shù)據(jù)庫連接與字符集亂碼處理數(shù)據(jù)庫連接不上最常見的是URL里的時(shí)區(qū)問題和驅(qū)動(dòng)類名問題。MySQL 8.0用com.mysql.cj.jdbc.DriverMySQL 5.x系列用com.mysql.jdbc.Driver如果寫錯(cuò)啟動(dòng)必報(bào)錯(cuò)。URL里必須加上serverTimezoneAsia/Shanghai否則連接會(huì)被判定失敗因?yàn)楫?dāng)前系統(tǒng)的時(shí)區(qū)與MySQL默認(rèn)時(shí)區(qū)不一致。中文亂碼是另一個(gè)高頻問題。排查思路按照這個(gè)順序走數(shù)據(jù)庫表字段字符集是否utf8mb4連接URL里是否有characterEncodingutf8頁面編碼是否UTF-8。有時(shí)候數(shù)據(jù)庫設(shè)置了utf8mb4但連接URL沒指定編碼程序里寫入的中文會(huì)變成問號(hào)。這三個(gè)環(huán)節(jié)都檢查一遍亂碼基本能解決。還有一個(gè)容易忽略的是修改了數(shù)據(jù)庫表結(jié)構(gòu)后實(shí)體類沒有同步更新導(dǎo)致MyBatis Plus查詢出來的字段為空。開發(fā)時(shí)改表結(jié)構(gòu)是家常便飯但一定要記得同步修改實(shí)體類字段建議在改動(dòng)表結(jié)構(gòu)后養(yǎng)成檢查實(shí)體類的習(xí)慣。4.3 端口占用與跨域問題的快速排查方法啟動(dòng)springboot項(xiàng)目時(shí)如果報(bào)端口被占用直接在Windows命令行執(zhí)行netstat -ano | findstr 8080查看占用端口的進(jìn)程PID然后taskkill /PID 進(jìn)程號(hào) /F強(qiáng)行結(jié)束。如果不想每次手工清理也可以在配置里換一個(gè)端口比如server.port8081??缬騿栴}只在前后端分離方案里出現(xiàn)。如果你的Vue前端是localhost:8080springboot后端跑在localhost:9090直接發(fā)ajax請(qǐng)求會(huì)被瀏覽器的同源策略攔截。解決辦法是后端加一個(gè)全局Cors配置類WebMvcConfigurer允許所有來源跨域請(qǐng)求或者用CrossOrigin注解加到Controller類上。很多人遇到跨域問題時(shí)第一反應(yīng)是前端代理或者瀏覽器插件其實(shí)后端配置一行就能解決這個(gè)排查方向要先想清楚。4.4 數(shù)據(jù)庫表、功能模塊的“雞肋感”該怎么避免有些同學(xué)做的系統(tǒng)會(huì)被老師說“功能很單薄”“看不出工作量”這就是所謂的“雞肋感”。幾個(gè)原因表太少模塊太簡單列表頁就是幾個(gè)字段的展示沒有任何聯(lián)動(dòng)邏輯。驗(yàn)收的時(shí)候老師一眼看出沒有業(yè)務(wù)閉環(huán)系統(tǒng)自然顯得單薄。要避免這個(gè)問題建議做系統(tǒng)的過程中問自己幾個(gè)問題登錄之后不同角色看到的內(nèi)容是不是不一樣每個(gè)列表頁是不是都可以精確查詢和分頁新增一條銷售記錄后車輛狀態(tài)有沒有變化刪除一條客戶記錄時(shí)如果他有訂單要不要提示這些細(xì)節(jié)都做了系統(tǒng)的完整度和業(yè)務(wù)深度就真正立起來了。還有一個(gè)小技巧加一個(gè)“數(shù)據(jù)統(tǒng)計(jì)儀表盤”或者“最近待辦事項(xiàng)”這樣的首頁把今日銷售、待處理工單、庫存預(yù)警這些關(guān)鍵信息匯總展示系統(tǒng)完成度立馬不一樣。4.5 快速生成一套完整項(xiàng)目結(jié)構(gòu)的建議如果一個(gè)項(xiàng)目從零開始手工建包、建類和配置文件不僅效率低還容易漏東西。我在實(shí)操中一般用以下流程快速生成一套可運(yùn)行的項(xiàng)目結(jié)構(gòu)第一用Spring Initializr初始化項(xiàng)目骨架勾選Web、MySQL驅(qū)動(dòng)、Thymeleaf或不用、Lombok。第二引入MyBatis Plus依賴配置好數(shù)據(jù)源。第三建好數(shù)據(jù)庫表結(jié)構(gòu)后使用MyBatis Plus的代碼生成器生成實(shí)體類和Mapper。第四寫好一個(gè)簡單的登錄頁面和登錄接口先跑通整個(gè)鏈路。第五在此基礎(chǔ)上一個(gè)模塊一個(gè)模塊地往上面加功能。這個(gè)流程的核心思想是先跑起來再擴(kuò)展不要試圖一次性把系統(tǒng)建好。微小的進(jìn)展加持續(xù)迭代比憋大招要靠譜得多。5. 文檔撰寫與答辯準(zhǔn)備的實(shí)戰(zhàn)經(jīng)驗(yàn)5.1 論文結(jié)構(gòu)、圖表占位與查重注意事項(xiàng)畢設(shè)不只拼代碼文檔的權(quán)重甚至更高。論文結(jié)構(gòu)一般包含摘要、緒論、需求分析、系統(tǒng)設(shè)計(jì)、系統(tǒng)實(shí)現(xiàn)、系統(tǒng)測試、總結(jié)這幾個(gè)部分。核心是哪兩章系統(tǒng)設(shè)計(jì)和系統(tǒng)實(shí)現(xiàn)。系統(tǒng)設(shè)計(jì)里要重點(diǎn)畫E-R圖、用例圖、系統(tǒng)架構(gòu)圖和數(shù)據(jù)庫表結(jié)構(gòu)系統(tǒng)實(shí)現(xiàn)里要結(jié)合代碼截圖和界面截圖一步步講清楚主要功能的實(shí)現(xiàn)邏輯。很多同學(xué)的論文寫得像流水賬大量的文字描述軟件界面但其實(shí)老師更想看到的是設(shè)計(jì)邏輯為什么數(shù)據(jù)庫表要這樣設(shè)計(jì)這個(gè)接口的參數(shù)為什么是這些功能之間的數(shù)據(jù)又是怎么流傳的如果你能在文檔里把這些“為什么”講清楚論文質(zhì)量直接就上去了。頁面截圖要帶核心數(shù)據(jù)不要只截一個(gè)空表單最好是帶著操作結(jié)果、驗(yàn)證信息的界面旁邊配文字說明才顯得真實(shí)可信。查重方面摘要、緒論這些大段文字盡量自己寫不要直接復(fù)制教材概念。凡是從參考論文里借鑒的表述要用自己的話重新組織一遍。代碼一般不參與查重但代碼中的注釋如果有大段文字復(fù)制還是有可能被誤判的。5.2 答辯高頻問題與應(yīng)對(duì)思路答辯環(huán)節(jié)不緊張的前提是準(zhǔn)備充分。老師最愛問的問題我整理了一個(gè)高頻清單為什么用springboot而不是SSH回答要點(diǎn)簡化配置、內(nèi)置容器、spring生態(tài)主流方向、適合快速開發(fā)。MyBatis Plus和MyBatis的區(qū)別是什么回答要點(diǎn)MP是增強(qiáng)工具內(nèi)置通用Mapper和常用CRUD方法復(fù)雜SQL還是自定義XML寫。數(shù)據(jù)庫表之間的關(guān)聯(lián)關(guān)系有哪些隨便挑兩張表舉例說清楚外鍵和業(yè)務(wù)含義。為什么這里用了事務(wù)注解回答要點(diǎn)多表寫入可能出現(xiàn)部分成功部分失敗事務(wù)保證原子性。系統(tǒng)的安全性怎么考慮的回答要點(diǎn)登錄攔截器過濾請(qǐng)求、密碼加密存儲(chǔ)、SQL預(yù)編譯防注入。你自己覺得系統(tǒng)還有哪些可以改進(jìn)的地方回答要點(diǎn)可以加Redis緩存熱點(diǎn)數(shù)據(jù)、可以引入消息隊(duì)列應(yīng)對(duì)高并發(fā)、可以加Spring Security做更細(xì)粒度權(quán)限。注意不要說自己性能已經(jīng)非常完善要給一個(gè)謙虛但有思考的回答?;卮鸬臅r(shí)候盡量引導(dǎo)到你熟悉的領(lǐng)域。比如設(shè)計(jì)表時(shí)做了什么考慮、寫某個(gè)模塊時(shí)遇到問題怎么調(diào)試的這些是你真正做過的東西說的時(shí)候比較具體、經(jīng)得起追問。這也是為什么我反復(fù)強(qiáng)調(diào)要在開發(fā)過程中多留意一些細(xì)節(jié)和踩坑記錄只有經(jīng)歷過的內(nèi)容答辯時(shí)才有底氣。5.3 如何識(shí)破網(wǎng)上的“全套源碼文檔”質(zhì)量這個(gè)標(biāo)題里寫著“全套源碼文檔遠(yuǎn)程調(diào)試”。有一點(diǎn)必須提醒各位網(wǎng)上交易源碼和文檔的項(xiàng)目質(zhì)量差異非常大。拿到手之后第一件事不是看代碼而是先把項(xiàng)目跑起來。如果解壓后連啟動(dòng)都啟動(dòng)不了后面的一切都免談。第二件事是檢查代碼里有沒有垃圾代碼、硬編碼的數(shù)據(jù)庫密碼或敏感信息。第三件事是對(duì)照文檔看代碼論文里的表結(jié)構(gòu)是否和源碼里的數(shù)據(jù)庫腳本一致如果文檔和代碼都對(duì)不上說明是東拼西湊的答辯的時(shí)候老師對(duì)照論文拷問源碼你就會(huì)非常被動(dòng)。畢設(shè)可以借助別人的源碼作參考但建議還是在理解的基礎(chǔ)上自己敲一遍、改一遍。哪怕只是改了某個(gè)模塊的業(yè)務(wù)邏輯、換了一套前端風(fēng)格、新增了一個(gè)報(bào)表接口整個(gè)系統(tǒng)的掌控感都會(huì)完全不一樣。拿著別人寫的項(xiàng)目去答辯最怕的就是老師隨機(jī)抽一個(gè)頁面讓你講實(shí)現(xiàn)思路你支支吾吾半天說不出來場面會(huì)很尷尬。6. 完整目錄與角色權(quán)限配置建議6.1 菜單目錄的規(guī)劃與頁面原型一個(gè)典型農(nóng)用車4S店管理系統(tǒng)的菜單目錄按角色來區(qū)分會(huì)非常清晰。管理員看到所有菜單系統(tǒng)管理下的員工管理、角色權(quán)限、數(shù)據(jù)字典業(yè)務(wù)管理下的客戶管理、車輛庫存、銷售訂單、售后工單、配件管理、統(tǒng)計(jì)報(bào)表。銷售員角色看得到客戶管理、車輛庫存、銷售訂單維修工角色看得到售后工單和配件管理。頁面共享的邏輯是菜單根據(jù)角色動(dòng)態(tài)生成。實(shí)際操作時(shí)我青睞直接用Thymeleaf模板加sec:authorize之類的標(biāo)簽控制菜單展示。不過既然用了攔截器也可以在后端根據(jù)登錄用戶角色拼菜單數(shù)據(jù)然后前端循環(huán)輸出。簡單地說用戶在查詢列表頁能統(tǒng)一展示但在執(zhí)行新增、修改、刪除等敏感操作時(shí)后臺(tái)校驗(yàn)登錄用戶的角色權(quán)限這樣安全性會(huì)好很多。頁面排版上導(dǎo)航欄放在頂部右側(cè)左側(cè)做菜單欄右側(cè)主體內(nèi)容區(qū)。列表頁上面做搜索欄關(guān)鍵詞Search、下拉篩選、日期區(qū)間下面做表格和分頁。表單頁盡量用模態(tài)框展示填完提交刷新列表交互體驗(yàn)上比跳轉(zhuǎn)單獨(dú)頁面要好。前后端分離方案的話UI組件用Element UI或Ant Design都行選一個(gè)用熟練就好。6.2 角色權(quán)限與按鈕級(jí)控制的落地實(shí)現(xiàn)后臺(tái)管理系統(tǒng)的權(quán)限應(yīng)該細(xì)化到按鈕級(jí)別而不僅僅是菜單。比如普通銷售員能看客戶列表但不能刪除客戶維修工能看工單列表但不能調(diào)整工單價(jià)格。實(shí)現(xiàn)方式可以用一個(gè)權(quán)限碼來控制比如customer:delete、order:price:update然后通過自定義權(quán)限注解加AOP切面校驗(yàn)或者直接在模板里判斷。畢設(shè)階段用模板判斷就夠用了例如Thymeleaf的sec:hasRole控制按鈕顯示隱藏后端再校驗(yàn)一次。隱藏按鈕只是界面遮擋安全校驗(yàn)一定放在后端。比如刪除客戶的方法里先判斷當(dāng)前登錄用戶的角色如果不是管理員就直接拋異?;蚍祷亟y(tǒng)一提示保證接口不能越權(quán)操作。這個(gè)思路在簡歷和面試?yán)锒寄苤v出來。6.3 首頁駕駛艙與提醒功能的加分設(shè)計(jì)如果想讓系統(tǒng)更有亮點(diǎn)首頁建議做成一個(gè)簡易駕駛艙。進(jìn)入首頁后展示今日銷售訂單數(shù)、今日銷售額、待處理維修工單、庫存預(yù)警數(shù)量這四個(gè)指標(biāo)的卡片一目了然。下面再放一張最近7天銷售趨勢圖用ECharts畫或者最近10條待辦工單列表讓使用者一打開系統(tǒng)就能掌握關(guān)鍵信息。提醒功能也是加分項(xiàng)。比如車輛庫存低于某個(gè)閾值就列為預(yù)警保養(yǎng)日期快臨近的客戶系統(tǒng)自動(dòng)生成提醒任務(wù)。這些功能看起來不大但體現(xiàn)了你真正理解用戶場景。農(nóng)用車的保養(yǎng)是有季節(jié)性的春耕前或者秋收后是保養(yǎng)高峰期提醒功能恰恰是實(shí)際業(yè)務(wù)中最需要的。本項(xiàng)目做完了以后聯(lián)調(diào)測試的環(huán)節(jié)也別忘了。自己注冊(cè)一個(gè)測試賬號(hào)把采購入庫、銷售出庫、開維修單、配件出入庫、報(bào)表查詢這條主鏈路完整走一遍發(fā)現(xiàn)Bug及時(shí)修復(fù)。端到端流程穩(wěn)定、邏輯閉環(huán)這套系統(tǒng)的完成度才算真正合格。我個(gè)人在做這類項(xiàng)目時(shí)最大的體會(huì)是表面上像是在開發(fā)一套軟件實(shí)際上是在梳理一個(gè)真實(shí)行業(yè)的業(yè)務(wù)流程。應(yīng)屆生在面試的時(shí)候如果能講清楚這個(gè)系統(tǒng)解決了農(nóng)用車經(jīng)銷商的哪些痛點(diǎn)比單純說“我用了Spring Boot”要打動(dòng)人得多。最后分享一個(gè)調(diào)試的小經(jīng)驗(yàn)。在你每個(gè)Service方法執(zhí)行關(guān)鍵的增刪改時(shí)可以臨時(shí)把SQL日志打開就像前面application.yml里配過的StdOutImpl那樣控制臺(tái)會(huì)打印出MyBatis Plus實(shí)際執(zhí)行的SQL語句。這樣做的好處是一旦你的數(shù)據(jù)更新結(jié)果不符合直覺你看一眼SQL就能定位是條件寫錯(cuò)了還是參數(shù)傳錯(cuò)了。很多同學(xué)遇到問題想半天其實(shí)控制臺(tái)日志早就告訴你答案了。保持這個(gè)習(xí)慣排查問題的能力會(huì)有一個(gè)很大提升。