療保險(xiǎn)管理系統(tǒng)實(shí)戰(zhàn):從業(yè)務(wù)建模到部署全流程)
總有些人以為Spring Boot 校園醫(yī)療保險(xiǎn)就是個(gè)學(xué)生信息表的增刪改查配個(gè) Bootstrap 后臺(tái)模板就能交差。但真正上手做這個(gè)題的人都知道坑在業(yè)務(wù)規(guī)則、角色流轉(zhuǎn)、數(shù)據(jù)庫(kù)狀態(tài)機(jī)甚至在你以為萬(wàn)無(wú)一失的打包部署環(huán)節(jié)。這篇就完整還原一套可運(yùn)行的校園醫(yī)療保險(xiǎn)管理系統(tǒng)的落地過(guò)程從業(yè)務(wù)建模、技術(shù)選型、數(shù)據(jù)庫(kù)設(shè)計(jì)到報(bào)銷(xiāo)審核流轉(zhuǎn)、部署排錯(cuò)和論文材料準(zhǔn)備全程基于 Spring Boot 2.7 MyBatis-Plus MySQL 8.0 Redis 這套目前課設(shè)最穩(wěn)妥的組合。不管你是自己寫(xiě)、拿到源碼后二次開(kāi)發(fā)還是正在頭疼畢業(yè)設(shè)計(jì)按這個(gè)思路走至少能少熬夜兩個(gè)星期。1. 這個(gè)題最難的從來(lái)不是 Spring Boot而是把醫(yī)保業(yè)務(wù)捋清楚很多拿到校園醫(yī)療保險(xiǎn)管理系統(tǒng)題目的同學(xué)第一步就直接開(kāi) IDE 建項(xiàng)目這基本就輸了。醫(yī)保業(yè)務(wù)和普通的宿舍管理系統(tǒng)完全不同它最核心的不是增刪改查而是審核狀態(tài)的流轉(zhuǎn)和報(bào)銷(xiāo)金額的計(jì)算規(guī)則。這兩塊沒(méi)想清楚后面寫(xiě)多少代碼都是在打補(bǔ)丁。1.1 角色與流程先畫(huà)人再寫(xiě)代碼一個(gè)完整的校園醫(yī)保系統(tǒng)至少要有四類(lèi)角色缺一個(gè)答辯的時(shí)候都會(huì)被老師問(wèn)住學(xué)生參保人注冊(cè)登錄、填寫(xiě)參保信息、提交報(bào)銷(xiāo)申請(qǐng)、上傳發(fā)票病歷、查看審核進(jìn)度。校醫(yī)院/衛(wèi)生所初審角色審核學(xué)生提交的報(bào)銷(xiāo)材料是否符合門(mén)診、住院的基本要求材料不全直接駁回。醫(yī)保辦/資助中心復(fù)審角色核定報(bào)銷(xiāo)金額確認(rèn)是否進(jìn)入打款環(huán)節(jié)。這個(gè)角色在多數(shù)課設(shè)里容易被忽略但它決定了系統(tǒng)有沒(méi)有完整閉環(huán)。系統(tǒng)管理員用戶(hù)管理、角色分配、報(bào)銷(xiāo)規(guī)則參數(shù)配置起付線、比例、封頂線、數(shù)據(jù)統(tǒng)計(jì)。對(duì)應(yīng)的主流程就是學(xué)生參保登記 → 管理員審核參保資格 → 學(xué)生提交報(bào)銷(xiāo)申請(qǐng) → 校醫(yī)院初審 → 醫(yī)保辦復(fù)審 → 生成報(bào)銷(xiāo)結(jié)果 → 學(xué)生查看反饋。這條鏈路里審核不是一個(gè)布爾字段而是要有狀態(tài)機(jī)。我在實(shí)際做這個(gè)系統(tǒng)的時(shí)候把報(bào)銷(xiāo)單狀態(tài)定義成了 10 個(gè)草稿、待初審、初審?fù)ㄟ^(guò)/駁回、待復(fù)審、復(fù)審?fù)ㄟ^(guò)/駁回、待打款、已打款、已歸檔。有人覺(jué)得 10 個(gè)太多但等你寫(xiě)完論文第六章系統(tǒng)測(cè)試時(shí)就會(huì)發(fā)現(xiàn)狀態(tài)越細(xì)測(cè)試用例越好寫(xiě)答辯演示的時(shí)候也越有的講。1.2 報(bào)銷(xiāo)計(jì)算規(guī)則一處小改動(dòng)牽動(dòng)全系統(tǒng)報(bào)銷(xiāo)金額計(jì)算是這個(gè)系統(tǒng)的業(yè)務(wù)核心很多同學(xué)直接寫(xiě)死在 Service 里比如if (type 1) ratio 0.7。看著能跑但有個(gè)致命缺陷校醫(yī)院的人改報(bào)銷(xiāo)比例時(shí)難道要找你改代碼重新部署所以規(guī)則必須可配置化。我采用的方案是設(shè)計(jì)一張reimburse_rule規(guī)則表字段包括就診類(lèi)型門(mén)診/住院/大病門(mén)診、起付線、報(bào)銷(xiāo)比例、單次封頂、年度累計(jì)封頂、生效時(shí)間。計(jì)算報(bào)銷(xiāo)金額時(shí)一次性把規(guī)則取出來(lái)做匹配并記錄本次計(jì)算用的是哪條規(guī)則快照。舉個(gè)例子某校的規(guī)則是門(mén)診每次起付線 300 元超出部分報(bào)銷(xiāo) 70%年度累計(jì)報(bào)銷(xiāo)上限 2000 元住院起付線 800 元報(bào)銷(xiāo) 80%年度上限 20 萬(wàn)。那么門(mén)診報(bào)銷(xiāo)金額的計(jì)算邏輯就是報(bào)銷(xiāo)金額 (本次總費(fèi)用 - 起付線) x 70%同時(shí)還要判斷這個(gè)人今年已經(jīng)報(bào)銷(xiāo)了多少超額部分自動(dòng)截?cái)?。這在 MySQL 里不算復(fù)雜但要注意并發(fā)問(wèn)題如果學(xué)生同時(shí)提交兩筆報(bào)銷(xiāo)申請(qǐng)年度累計(jì)額度就可能被重復(fù)計(jì)算。穩(wěn)妥的做法是在事務(wù)里加鎖或者先查詢(xún)已通過(guò)審核且進(jìn)入打款環(huán)節(jié)的報(bào)銷(xiāo)單總額再和規(guī)則比較。課設(shè)里不需要做太重的分布式鎖但要保證單機(jī)事務(wù)一致性和重要字段的樂(lè)觀鎖版本控制。1.3 系統(tǒng)交付邊界哪些功能必須有哪些是加分項(xiàng)功能模塊直接決定了論文的大綱和工作量我用一個(gè)表格說(shuō)明我當(dāng)時(shí)劃分的交付范圍功能模塊核心功能建議等級(jí)用戶(hù)與權(quán)限注冊(cè)、登錄、密碼加密、角色路由、菜單權(quán)限必須有參保管理學(xué)生參保信息登記、資格審核、參保記錄查詢(xún)必須有報(bào)銷(xiāo)管理申請(qǐng)?zhí)峤?、材料附件、審核流、金額計(jì)算、進(jìn)度查詢(xún)必須有規(guī)則配置報(bào)銷(xiāo)比例、起付線、封頂線的后臺(tái)維護(hù)必須有通知公告報(bào)銷(xiāo)結(jié)果通知、政策公告發(fā)布建議有數(shù)據(jù)統(tǒng)計(jì)按學(xué)院/年度統(tǒng)計(jì)報(bào)銷(xiāo)金額、參保人數(shù)圖表加分項(xiàng)導(dǎo)出功能Excel 導(dǎo)出報(bào)銷(xiāo)清單、參保名單加分項(xiàng)如果你拿到手的源代碼資源包只給了前三項(xiàng)那其實(shí)是正常的核心版本但建議至少自己補(bǔ)上一個(gè)規(guī)則配置頁(yè)面。因?yàn)榇疝q評(píng)閱時(shí)老師最?lèi)?ài)問(wèn)的問(wèn)題就是報(bào)銷(xiāo)比例如果要改怎么辦如果你答案不優(yōu)雅前半小時(shí)的辛苦演示都會(huì)白費(fèi)。2. 技術(shù)選型與開(kāi)發(fā)環(huán)境夠用、好調(diào)試、答辯扛得住技術(shù)選型是很多人忽略但實(shí)際影響開(kāi)發(fā)效率的環(huán)節(jié)。校園醫(yī)療系統(tǒng)這類(lèi)課設(shè)項(xiàng)目不需要上微服務(wù)、不需要容器化編排更不需要什么 Distributed Transaction選一套主流、資料多、代碼量適中的棧才是正道。2.1 完整技術(shù)棧清單與版本對(duì)應(yīng)關(guān)系我最終用的是這套組合不敢說(shuō)最優(yōu)但勝在穩(wěn)定和資料多后端框架Spring Boot 2.7.18這里提醒一下不要上 Spring Boot 3.x。3.x 依賴(lài) JDK 17而且很多課設(shè)用的 MyBatis-Plus 版本和 Java 代碼兼容性問(wèn)題會(huì)把你折磨瘋。2.7 團(tuán)隊(duì)里用得多、報(bào)錯(cuò)搜得到答案選它不丟人。持久層MyBatis-Plus 3.5.3配合TableLogic邏輯刪除、MetaObjectHandler自動(dòng)填充 createTime/updateTime能省 30% 的重復(fù)代碼。數(shù)據(jù)庫(kù)MySQL 8.0字符集 utf8mb4排序規(guī)則 utf8mb4_unicode_ci。連接池Druid監(jiān)控頁(yè)面druid/index.html在答辯演示時(shí)很加分。權(quán)限鑒權(quán)Sa-Token 或 Spring Security JWT。我更推薦 Sa-Token因?yàn)樗鼪](méi)有 Spring Security 那么多過(guò)濾器鏈的概念課設(shè)工期緊張時(shí)學(xué)起來(lái)快得多。緩存Redis主要用來(lái)存登錄 Token、報(bào)銷(xiāo)規(guī)則緩存和部分熱點(diǎn)數(shù)據(jù)不是必須但建議有。工具庫(kù)Hutool、EasyExcel導(dǎo)出用、Lombok。開(kāi)發(fā)環(huán)境我用的是 JDK 8 Maven 3.6.3 IDEA 2023.2Windows 10。這里有一個(gè)值得注意的建議IDEA 的 Lombok 插件一定要裝并開(kāi)啟注解處理否則代碼一編譯就莫名報(bào)找不到getter/setter你還會(huì)以為是自己代碼寫(xiě)錯(cuò)了。2.2 開(kāi)發(fā)環(huán)境初始化的三個(gè)容易忽略的配置第一個(gè)是 Maven 倉(cāng)庫(kù)鏡像。國(guó)內(nèi)網(wǎng)絡(luò)環(huán)境下載 Spring Boot 相關(guān)依賴(lài)時(shí)默認(rèn)中央倉(cāng)庫(kù)速度不穩(wěn)定我直接在settings.xml里配了阿里云鏡像spring-boot-starter-parent的依賴(lài)基本一分鐘內(nèi)全部拉完。第二個(gè)是application.yml里的數(shù)據(jù)庫(kù)連接串。MySQL 8.0 的驅(qū)動(dòng)類(lèi)名是com.mysql.cj.jdbc.Driver連接串里必須加上serverTimezoneAsia/Shanghai同時(shí)建議顯式聲明useUnicodetruecharacterEncodingutf8mb4。不寫(xiě) timezone 會(huì)導(dǎo)致查出來(lái)的時(shí)間比實(shí)際少 8 小時(shí)甚至有項(xiàng)目直接啟動(dòng)報(bào)錯(cuò)The server time zone value 亂碼 is unrecognized。第三個(gè)是數(shù)據(jù)源自動(dòng)配置的問(wèn)題。如果你項(xiàng)目里同時(shí)引入了 Spring Boot 的spring-boot-starter-data-jpa和 MyBatis-Plus啟動(dòng)時(shí)可能因?yàn)閮蓚€(gè)持久層框架自動(dòng)配置沖突而報(bào)Invalid bean definition。我個(gè)人的做法是項(xiàng)目只用一個(gè)持久層框架。這個(gè)系統(tǒng)完全用 MyBatis-Plus 就夠了別貪多同時(shí)引用 JPA。2.3 為什么強(qiáng)烈建議拆分 dev/prod 兩套配置我在拿到課設(shè)題目的第一周就拆出了三個(gè)文件application.yml公共配置、application-dev.yml本地開(kāi)發(fā)、application-prod.yml服務(wù)器部署。開(kāi)發(fā)環(huán)境用本地的 MySQL賬號(hào) root、密碼隨意Redis 也默認(rèn)本地 6379生產(chǎn)環(huán)境則通過(guò)啟動(dòng)參數(shù)切換java -jar xx.jar --spring.profiles.activeprod。這樣做的好處一是本地調(diào)試不會(huì)被服務(wù)器配置干擾二是部署到服務(wù)器時(shí)不用重新改代碼只需改 yml 里的連接信息即可。這種細(xì)節(jié)在論文的系統(tǒng)部署章節(jié)里也是很好的素材。就算你不打算真的部署到云服務(wù)器在論文中把這個(gè)過(guò)程寫(xiě)清楚整個(gè)論文的完整度會(huì)提升一大截。3. 數(shù)據(jù)庫(kù)設(shè)計(jì)12 張核心表怎么落才不返工數(shù)據(jù)庫(kù)設(shè)計(jì)是這個(gè)系統(tǒng)里最容易返工的部分。我見(jiàn)過(guò)一個(gè)同學(xué)把報(bào)銷(xiāo)附件直接存成longblob字段塞進(jìn)報(bào)銷(xiāo)單表結(jié)果一張發(fā)票 5MB整張表膨脹到幾百 MB查一次列表卡 3 秒。附件的正確做法是單獨(dú)建表只存文件名、存儲(chǔ)路徑、關(guān)聯(lián)的業(yè)務(wù) ID。3.1 核心表結(jié)構(gòu)與字段設(shè)計(jì)整個(gè)系統(tǒng)我設(shè)計(jì)了 12 張表核心表如下表名用途關(guān)鍵字段sys_user用戶(hù)表統(tǒng)一放所有登錄賬號(hào)id, username, password, salt, role_id, status, create_timesys_role角色表id, role_code, role_namestudent_info學(xué)生參保信息id, user_id, student_no, name, college, grade, phone, id_card(加密), insurance_statusinsurance_record參保記錄/續(xù)保歷史id, student_id, academic_year, policy_no, insured_date, expire_datereimburse_application報(bào)銷(xiāo)申請(qǐng)主表id, student_id, medical_type, hospital, total_amount, apply_date, status, rule_snapshotreimburse_detail報(bào)銷(xiāo)費(fèi)用明細(xì)id, application_id, item_name, item_category, amount, invoice_noaudit_record審核記錄表id, application_id, auditor_id, audit_action, audit_comment, audit_timereimburse_rule報(bào)銷(xiāo)規(guī)則配置表id, medical_type, deductible, ratio, single_cap, annual_cap, effective_dateattachment附件表發(fā)票、病歷id, biz_type, biz_id, file_name, file_path, file_sizesys_config系統(tǒng)參數(shù)配置id, config_key, config_value, description這里有一個(gè)關(guān)鍵設(shè)計(jì)原則報(bào)銷(xiāo)金額計(jì)算不能直接改規(guī)則表里的當(dāng)前值而是要在報(bào)銷(xiāo)單里冗余一份rule_snapshot。因?yàn)橐?guī)則會(huì)變學(xué)生 3 月份提交申請(qǐng)時(shí)用的是 70% 比例5 月份學(xué)校調(diào)成了 65%如果審核時(shí)實(shí)時(shí)讀規(guī)則表之前的申請(qǐng)就會(huì)被錯(cuò)誤地按新規(guī)則計(jì)算??煺兆侄挝矣?JSON 格式存儲(chǔ)計(jì)算當(dāng)時(shí)的規(guī)則對(duì)象一勞永逸地規(guī)避了這個(gè)爭(zhēng)議問(wèn)題。3.2 報(bào)銷(xiāo)狀態(tài)機(jī)的落表方式狀態(tài)機(jī)我用的方案是主表有一個(gè)status字段另外單獨(dú)建audit_record表記錄每一次流轉(zhuǎn)的痕跡。有人覺(jué)得重復(fù)有人覺(jué)得沒(méi)必要但最后的效果是每一條報(bào)銷(xiāo)單都能完整追溯誰(shuí)在什么時(shí)間做了什么動(dòng)作、寫(xiě)了什么意見(jiàn)。這在系統(tǒng)測(cè)試和答辯時(shí)是非常好的談資老師一看就知道你考慮到了審計(jì)需求。具體實(shí)現(xiàn)上Service 層不要直接對(duì)著status字段隨意 set而是封裝一個(gè)auditRimbursement(applicationId, auditAction, auditComment, auditorId)方法內(nèi)部用樂(lè)觀鎖 狀態(tài)校驗(yàn)初審只能操作待初審的單子復(fù)審只能操作初審?fù)ㄟ^(guò)的單子學(xué)生只能撤回草稿或待初審的單子已打款的單子不可再修改。3.3 數(shù)據(jù)冗余與聯(lián)表查詢(xún)的取舍學(xué)生個(gè)人信息、學(xué)院信息、報(bào)銷(xiāo)單列表之間是典型的一對(duì)多關(guān)系。查詢(xún)報(bào)銷(xiāo)列表的時(shí)候如果每次都要student_info表 join 一次雖然也能跑但列表頁(yè)字段一多就會(huì)顯得慢。我在reimburse_application表里冗余了student_no、student_name、college這幾個(gè)只讀字段提交報(bào)銷(xiāo)申請(qǐng)時(shí)從學(xué)生檔案一次性快照過(guò)來(lái)。這樣做的好處是列表頁(yè)不需要 join查詢(xún)效率高壞處是如果學(xué)生畢業(yè)后改了學(xué)院名稱(chēng)歷史數(shù)據(jù)會(huì)有不一致。但對(duì)于課設(shè)系統(tǒng)這個(gè)規(guī)模讀多寫(xiě)少、以展示為主的場(chǎng)景冗余帶來(lái)的收益遠(yuǎn)大于風(fēng)險(xiǎn)。你也可以在論文里專(zhuān)門(mén)寫(xiě)一小段反范式設(shè)計(jì)的理由反而顯得有思考深度。4. 關(guān)鍵功能模塊的實(shí)現(xiàn)從登錄到報(bào)銷(xiāo)審核流轉(zhuǎn)這個(gè)章節(jié)直接對(duì)應(yīng)論文的系統(tǒng)實(shí)現(xiàn)也是你能不能把代碼跑通的關(guān)鍵。4.1 登錄、鑒權(quán)與角色路由的設(shè)計(jì)密碼存儲(chǔ)不要用明文更不要只用 MD5。我一直用 BCryptSpring Security 里的BCryptPasswordEncoder可以直接拿來(lái)用。前臺(tái)密碼加密傳輸這塊課設(shè)不用搞太復(fù)雜HTTPS 一般用不上但至少要做到數(shù)據(jù)庫(kù)泄露后密碼不裸奔。使用 Sa-Token 做登錄時(shí)登錄成功后返回 token前端請(qǐng)求頭加satoken字段。每個(gè)接口用SaCheckRole(admin)這類(lèi)注解控制角色權(quán)限。值得注意的是前端路由也要做角色控制管理員登錄后菜單顯示規(guī)則配置和用戶(hù)管理學(xué)生登錄后只顯示參保登記和報(bào)銷(xiāo)申請(qǐng)。不然學(xué)生直接在瀏覽器輸入 URL 訪問(wèn)管理頁(yè)面雖然后端權(quán)限攔截了但用戶(hù)體驗(yàn)很差答辯時(shí)也容易被挑毛病。4.2 報(bào)銷(xiāo)審核流轉(zhuǎn)的實(shí)現(xiàn)細(xì)節(jié)這一塊是最容易出現(xiàn)并發(fā)問(wèn)題的。兩個(gè)審核員同時(shí)審核同一個(gè)報(bào)銷(xiāo)單如果都讀了 status 為待初審一個(gè)改為通過(guò)、一個(gè)改為駁回后提交的會(huì)把前一個(gè)結(jié)果覆蓋掉。我當(dāng)時(shí)的解決方案是加了個(gè)樂(lè)觀鎖版本號(hào)字段version更新時(shí)執(zhí)行 SQLUPDATE reimburse_application SET status 初審?fù)ㄟ^(guò), version version 1 WHERE id #{id} AND status 待初審 AND version #{version}如果更新影響行數(shù)為 0說(shuō)明狀態(tài)已經(jīng)被別人改過(guò)直接拋出報(bào)銷(xiāo)單已被處理的提示。這套邏輯不復(fù)雜但對(duì)項(xiàng)目完整性非常重要論文測(cè)試用例中也可以專(zhuān)門(mén)提一條并發(fā)審核場(chǎng)景。4.3 文件上傳與敏感信息處理學(xué)生在提交報(bào)銷(xiāo)單時(shí)要上傳發(fā)票照片、病歷掃描件后端接收MultipartFile后先做類(lèi)型白名單校驗(yàn)jpg、png、pdf 三種格式大小限制 5MB。文件命名規(guī)則我采用UUID 原始文件名存儲(chǔ)路徑按日期分目錄例如uploads/20250307/uuid.jpg。數(shù)據(jù)庫(kù)里只存路徑不存 Base64。還有一塊敏感內(nèi)容是學(xué)生的身份證號(hào)。我在student_info表中對(duì)身份證號(hào)做了加密存儲(chǔ)展示時(shí)用工具類(lèi)脫敏成110***********1234。這個(gè)點(diǎn)雖小但寫(xiě)進(jìn)論文的數(shù)據(jù)安全設(shè)計(jì)里會(huì)顯得你考慮問(wèn)題很全面。畢竟現(xiàn)在個(gè)人信息保護(hù)是熱點(diǎn)話題很多評(píng)閱老師都會(huì)留意。4.4 統(tǒng)計(jì)報(bào)表與 Excel 導(dǎo)出報(bào)表功能我用了 Hutool 的PoiWriter或 EasyExcel。最常用的三個(gè)維度是按學(xué)院統(tǒng)計(jì)當(dāng)前年度參保人數(shù)按月份統(tǒng)計(jì)報(bào)銷(xiāo)申請(qǐng)數(shù)量和報(bào)銷(xiāo)金額按報(bào)銷(xiāo)類(lèi)型統(tǒng)計(jì)門(mén)診/住院的占比。后端接口返回ListMapString, Object前端用 ECharts 畫(huà)餅圖和柱狀圖。這里有一個(gè)易踩坑的地方ECharts 依賴(lài)的數(shù)據(jù)字段名在 JS 里是駝峰而后端 Java 返回的是下劃線字段比如totalAmount對(duì)應(yīng)數(shù)據(jù)庫(kù)的total_amount。使用 MyBatis-Plus 時(shí)先在全局配置map-underscore-to-camel-case: true否則前端拿到一堆帶下劃線的 JSON 字段圖表渲染出來(lái)標(biāo)簽全是亂的。5. 調(diào)試部署全流程實(shí)錄從本地跑通到服務(wù)器上線課設(shè)題目里寫(xiě)了調(diào)試部署開(kāi)發(fā)環(huán)境所以這節(jié)直接說(shuō)實(shí)戰(zhàn)中最容易浪費(fèi)時(shí)間的幾個(gè)環(huán)節(jié)。5.1 本地啟動(dòng)必須檢查的四件事拿到源碼或者自己寫(xiě)完第一版后啟動(dòng)失敗的 80% 原因集中在四個(gè)方面JDK 版本與 Spring Boot 版本不匹配Spring Boot 2.7 用 JDK 8 和 11 都沒(méi)問(wèn)題但如果你電腦默認(rèn) JDK 17編譯會(huì)報(bào)Unsupported class file major version或者 Lombok 崩潰。MySQL 服務(wù)沒(méi)有啟動(dòng)很多人報(bào)錯(cuò)Communications link failure不是代碼問(wèn)題是 MySQL 服務(wù)壓根沒(méi)開(kāi)或者端口被改了。數(shù)據(jù)庫(kù)沒(méi)有初始化如果項(xiàng)目連了數(shù)據(jù)庫(kù)但忘記執(zhí)行項(xiàng)目里的sql文件啟動(dòng)時(shí)會(huì)出現(xiàn)Table xx.reimburse_application doesnt exist。Redis 未啟動(dòng)如果登錄用到了 Sa-Token 的 Redis 集成而本機(jī)沒(méi)啟動(dòng) Redis會(huì)報(bào)Unable to connect to Redis。這個(gè)錯(cuò)誤表面上是連接失敗實(shí)際是環(huán)境缺服務(wù)。我建議在跑任何代碼前先寫(xiě)一個(gè)簡(jiǎn)單的curl http://localhost:8080再配合后端控制臺(tái)日志逐行看不要一上來(lái)就懷疑框架配錯(cuò)了。5.2 打包含依賴(lài)的坑jar 包一跑就掛Fine你本地 IDEA 點(diǎn)擊運(yùn)行一切正常但執(zhí)行mvn package后java -jar一跑就no main manifest attribute或報(bào)告找不到主類(lèi)。這個(gè)坑十個(gè)人里有八個(gè)人會(huì)遇到。原因是 Spring Boot 項(xiàng)目必須用spring-boot-maven-plugin插件來(lái) repackage否則打出來(lái)的只是普通 jar不是 fat jar。正確配置是確保 pom.xml 里有build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId version2.7.18/version /plugin /plugins /build打完包后用java -jar target/xxx.jar --spring.profiles.activeprod啟動(dòng)。如果報(bào)端口被占用就用nohup java -jar xxx.jar --server.port8081換一個(gè)端口。5.3 服務(wù)器部署Nginx 反向代理與 MySQL 初始化如果你有一臺(tái)云服務(wù)器騰訊云/阿里云輕量服務(wù)器都行部署思路是這樣服務(wù)器安裝 JDK 8、MySQL 8.0、Redis可選把本地導(dǎo)出的 SQL 文件在服務(wù)器上執(zhí)行一遍用scp或 GitHub 把 jar 包傳到服務(wù)器寫(xiě)一個(gè)簡(jiǎn)單的start.shnohup java -jar xxx.jar --spring.profiles.activeprod app.log 21 配置 Nginx 反向代理 80 端口到 8080 端口前端靜態(tài)資源放 Nginx。安全組記得開(kāi)放 3306 端口只給特定 IP不然是個(gè)人都能連你的數(shù)據(jù)庫(kù)。這個(gè)問(wèn)題我在好幾篇課設(shè)項(xiàng)目里反復(fù)提醒過(guò)因?yàn)楹芏嗤瑢W(xué)圖方便把數(shù)據(jù)庫(kù)賬號(hào)密碼裸寫(xiě)在 yml 里然后直接上傳服務(wù)器如果安全組設(shè)置不當(dāng)數(shù)據(jù)庫(kù)很快會(huì)被惡意掃描拖走。5.4 常見(jiàn)異常對(duì)照表異?,F(xiàn)象常見(jiàn)原因處理思路Access denied for user rootlocalhost密碼或權(quán)限問(wèn)題檢查 yml 密碼MySQL 8 用caching_sha2_password時(shí)注意驅(qū)動(dòng)版本Invalid bound statement (not found)Mapper XML 掃描路徑不對(duì)檢查MapperScan和 XML 的 namespace 是否對(duì)應(yīng)Failed to configure a DataSource未配置數(shù)據(jù)源或配置錯(cuò)誤檢查spring.datasource.url是否符合規(guī)范Table doesnt exist沒(méi)有執(zhí)行 SQL 初始化腳本用 Navicat 或命令行初始化數(shù)據(jù)庫(kù)Whitelabel Error Page 404Controller 路徑或靜態(tài)資源放錯(cuò)位置檢查RequestMapping與前端請(qǐng)求路徑是否一致中文查詢(xún)結(jié)果亂碼連接串或表字符集不統(tǒng)一統(tǒng)一 utf8mb4連接串加 characterEncoding6. 論文寫(xiě)作與項(xiàng)目論證一萬(wàn)字文檔的骨架標(biāo)題里提到論文文檔 1 萬(wàn)字以上很多同學(xué)把論文和開(kāi)發(fā)分開(kāi)來(lái)最后再熬夜拼湊過(guò)程非常痛苦。實(shí)際上論文的章節(jié)對(duì)應(yīng)系統(tǒng)的開(kāi)發(fā)過(guò)程是天然的同構(gòu)關(guān)系。6.1 論文大綱與系統(tǒng)開(kāi)發(fā)的對(duì)應(yīng)關(guān)系完整系統(tǒng)論文通常用這個(gè)框架第一章緒論。寫(xiě)研究背景、國(guó)內(nèi)外發(fā)展現(xiàn)狀、研究?jī)?nèi)容。開(kāi)題的時(shí)候就要確定為什么做這個(gè)系統(tǒng)我的推薦寫(xiě)法是先用一個(gè)真實(shí)的校園場(chǎng)景切入從大學(xué)生醫(yī)保報(bào)銷(xiāo)流程繁瑣說(shuō)起再分析目前常見(jiàn)線上化系統(tǒng)的不足最后引出本系統(tǒng)的目標(biāo)。第二章相關(guān)技術(shù)介紹。寫(xiě) Spring Boot、MyBatis-Plus、MySQL、Redis、Vue 或 Thymeleaf。這里不要長(zhǎng)篇大論的復(fù)制概念要結(jié)合系統(tǒng)用到的場(chǎng)景描述比如MyBatis-Plus 的 LambdaQueryWrapper 在報(bào)銷(xiāo)單列表的分頁(yè)查詢(xún)中提高了開(kāi)發(fā)效率。第三章需求分析。包括可行性分析經(jīng)濟(jì)、技術(shù)、操作功能性需求用例圖和用例說(shuō)明非功能需求性能、安全、可靠性。第四章系統(tǒng)設(shè)計(jì)??傮w架構(gòu)圖、功能模塊圖、數(shù)據(jù)庫(kù)設(shè)計(jì)ER 圖、表結(jié)構(gòu)說(shuō)明重點(diǎn)把報(bào)銷(xiāo)審核狀態(tài)流轉(zhuǎn)畫(huà)清楚。第五章系統(tǒng)實(shí)現(xiàn)。這是最操蛋但最好寫(xiě)的一章把關(guān)鍵頁(yè)面截圖貼上去配核心代碼片段說(shuō)明實(shí)現(xiàn)邏輯。用什么技術(shù)就寫(xiě)什么不要抄大段無(wú)意義的代碼。第六章系統(tǒng)測(cè)試。測(cè)試環(huán)境、測(cè)試用例表、測(cè)試結(jié)果和分析。每個(gè)功能模塊至少寫(xiě) 5 條測(cè)試用例包含正常流程和異常流程比如提交未上傳附件的報(bào)銷(xiāo)單系統(tǒng)應(yīng)提示材料不完整。第七章總結(jié)與展望??偨Y(jié)系統(tǒng)完成的功能和不足展望未來(lái)的移動(dòng)端版本或消息推送優(yōu)化。6.2 截圖、表格、ER 圖怎么準(zhǔn)備才能讓老師無(wú)話可說(shuō)多的不說(shuō)這幾條是我從答辯教室走出來(lái)以后才徹底想明白的截圖不要只在本地 IDEA 里截。把系統(tǒng)部署起來(lái)用瀏覽器訪問(wèn) 8080 端口用真實(shí)流程走一遍再截圖。首頁(yè)、登錄頁(yè)、報(bào)銷(xiāo)申請(qǐng)頁(yè)、審核列表頁(yè)、統(tǒng)計(jì)頁(yè)每一張都要有清晰的數(shù)據(jù)展示。要注意的是頁(yè)面上別留測(cè)試數(shù)據(jù)123這種明顯敷衍的臟數(shù)據(jù)用一個(gè)聽(tīng)上去真實(shí)的示例賬號(hào)比如2023501001 張三。數(shù)據(jù)表格要和系統(tǒng)截圖對(duì)應(yīng)論文里設(shè)計(jì)的字段如果頁(yè)面里看不到老師心里會(huì)嘀咕。ER 圖最好用專(zhuān)業(yè)工具Navicat 或者 PowerDesigner生成不要手畫(huà)。數(shù)據(jù)庫(kù)每個(gè)字段加注釋論文表結(jié)構(gòu)描述就能直接從注釋里抄。6.3 答辯前要背熟的三句話經(jīng)過(guò)幾十次模擬答辯我發(fā)現(xiàn)老師問(wèn)來(lái)問(wèn)去就那么幾個(gè)切入點(diǎn)提前準(zhǔn)備好標(biāo)準(zhǔn)回答比臨時(shí)翻筆記靠譜報(bào)銷(xiāo)比例怎么配置的——回答我設(shè)計(jì)了reimburse_rule規(guī)則表管理員在后臺(tái)可以動(dòng)態(tài)調(diào)整起付線、報(bào)銷(xiāo)比例和封頂線計(jì)算時(shí)讀取生效規(guī)則并做快照所以規(guī)則變更不影響歷史報(bào)銷(xiāo)單。如果兩個(gè)審核員同時(shí)審核同一單怎么辦——回答我在數(shù)據(jù)庫(kù)表加了 version 字段采用樂(lè)觀鎖機(jī)制更新時(shí)校驗(yàn)版本號(hào)版本不一致就提示已被處理。系統(tǒng)安全性上做了什么——回答密碼使用 BCrypt 加密身份證號(hào)脫敏展示上傳文件做了類(lèi)型和大小限制后臺(tái)接口按角色做了權(quán)限攔截。這三句話你要是能流暢地說(shuō)出來(lái)至少能擋住 90% 的常規(guī)追問(wèn)。我自己做完這個(gè)項(xiàng)目的最大體會(huì)是這類(lèi)管理系統(tǒng)真正的交付物不止是一個(gè)能跑的 jar而是一套能講清楚業(yè)務(wù)閉環(huán)的邏輯。代碼只是把規(guī)則和流程固化成界面和接口論文只是把你踩過(guò)的坑和想清楚的方案記錄下來(lái)。先把業(yè)務(wù)當(dāng)業(yè)務(wù)來(lái)理解再去寫(xiě)代碼整個(gè)項(xiàng)目就會(huì)順很多。最后分享一個(gè)實(shí)用小技巧在application-dev.yml里把日志級(jí)別調(diào)成debug只看 Hibernate/MyBatis 的 SQL 輸出。當(dāng)年我排查審核狀態(tài)不更新的問(wèn)題就是靠日志發(fā)現(xiàn) UPDATE 語(yǔ)句根本沒(méi)帶 status 條件才修好的。多留一行 debug 日志少熬一夜。