扶貧數(shù)據(jù)收集平臺搭建實(shí)戰(zhàn))
簡介面向畢業(yè)設(shè)計(jì)場景的精準(zhǔn)扶貧數(shù)據(jù)收集小程序完整項(xiàng)目包以微信小程序?yàn)榍岸恕ava為后端實(shí)現(xiàn)貧困對象精準(zhǔn)畫像、幫扶記錄管理、政策新聞?wù)故镜群诵臉I(yè)務(wù)覆蓋“互聯(lián)網(wǎng)精準(zhǔn)扶貧”的典型需求適合計(jì)算機(jī)相關(guān)專業(yè)學(xué)生用于課程設(shè)計(jì)或畢設(shè)二次開發(fā)。壓縮包共含503個(gè)文件主要有Java源碼、class編譯文件、jar依賴庫小程序端的wxml、wxss、js、json頁面與組件以及jpg/png圖片、gif動圖、SQL數(shù)據(jù)庫腳本、docx設(shè)計(jì)文檔、pptx答辯PPT、mp4操作演示視頻等另有少量html、properties等輔助預(yù)覽與配置資源整體大小約106.62MB目錄層次清晰便于按前后端和資源類型檢索。目前已有229人學(xué)習(xí)下載。項(xiàng)目在代碼層面提供了DateUtil、StringUtil、ExportExcel等工具類ApiController、PkryController、BfjlController、BfsrController、ArticleController等業(yè)務(wù)控制器以及BaseDAO數(shù)據(jù)訪問層能夠直觀展現(xiàn)微信小程序調(diào)用Java接口完成扶貧數(shù)據(jù)錄入、查詢、統(tǒng)計(jì)與導(dǎo)出的完整鏈路配合可導(dǎo)入的SQL數(shù)據(jù)庫和演示視頻可顯著降低環(huán)境搭建與成果展示門檻是一套可直接參考的畢業(yè)設(shè)計(jì)實(shí)現(xiàn)方案。1. 為什么這個(gè)「被做爛了」的畢業(yè)設(shè)計(jì)反而值得從頭寫一遍“基于微信小程序的精準(zhǔn)扶貧數(shù)據(jù)收集小程序平臺”——這個(gè)題目在校內(nèi)畢設(shè)選題里出現(xiàn)頻率極高同學(xué)之間互相傳的往往是同一個(gè) zipjava 后端 微信小程序 數(shù)據(jù)庫 演示視頻。聽起來像被做爛了但正因?yàn)樽龅娜硕嗫釉缇捅徊绕搅?。這個(gè)平臺本質(zhì)上是一個(gè)數(shù)據(jù)收集系統(tǒng)走訪人員在小程序里錄入幫扶對象基本信息、入戶走訪記錄和幫扶措施隨手拍照留證數(shù)據(jù)通過 Java 接口落到數(shù)據(jù)庫后臺按戶查臺賬。適合正在選題、或者手里有一個(gè)跑不起來的源碼包的同學(xué)。這篇筆記按我實(shí)際搭過的方案講把架構(gòu)、表結(jié)構(gòu)、核心代碼、聯(lián)調(diào)翻車點(diǎn)和演示視頻錄制技巧一次說清。2. 先畫數(shù)據(jù)流再寫代碼小程序、Java 接口層和數(shù)據(jù)表怎么分工2.1 數(shù)據(jù)收集場景的三種角色和一條數(shù)據(jù)流先把最容易被忽略的事說清楚這個(gè)題目叫“數(shù)據(jù)收集平臺”核心不是管理后臺多花哨而是「小程序端把數(shù)據(jù)收上來」這一條鏈路。業(yè)務(wù)上通常有三類角色管理員負(fù)責(zé)建賬號和維護(hù)基礎(chǔ)數(shù)據(jù)走訪人員拿著手機(jī)入戶填表、拍照、提交后臺管理人員查臺賬、看走訪覆蓋情況。絕大部分畢設(shè)做的是后兩種角色管理員用 Web 頁面實(shí)現(xiàn)其實(shí)就夠用了。數(shù)據(jù)流一條線就能說清走訪人員打開小程序 → 選擇幫扶對象或新建對象 → 填寫走訪表單、拍現(xiàn)場照片 → 小程序把圖片先上傳拿到 URL → 表單數(shù)據(jù)和圖片 URL 一起提交到 Java 接口 → 接口用事務(wù)把主表和明細(xì)表一起寫入 MySQL → 后臺管理系統(tǒng)按戶查出來。這條鏈路里最值得花時(shí)間的是中間兩環(huán)圖片上傳的時(shí)序以及主表和明細(xì)表的一致性。這兩處也是答辯時(shí)老師最喜歡追問的地方。如果你手里已經(jīng)有源碼包先別急著改頁面把這條數(shù)據(jù)流在后端代碼里走通后面所有問題都好排查。2.2 后端用 Java 而不是 Node/PHP 的理由給畢業(yè)設(shè)計(jì)答辯留余地選題雖然是小程序但難度主要在 Java 后端。常見做法是用 Spring Boot MyBatis-Plus MySQL這也是課程設(shè)計(jì)和畢設(shè)源碼包里最常見的組合。答辯時(shí)一定會被問“為什么選 Java 不用 Node/PHP”不能只回一句“學(xué)校教的”要有幾句話能接住。能想到的實(shí)在理由有三條。第一類型約束走訪數(shù)據(jù)里身份證號、手機(jī)號、金額、日期都是強(qiáng)類型字段Java 的實(shí)體類和 DTO 可以在編譯期擋住一部分臟數(shù)據(jù)PHP/JS 這類弱類型語言要到運(yùn)行期才發(fā)現(xiàn)問題。第二事務(wù)成熟度提交走訪記錄要同時(shí)寫幫扶對象表、走訪記錄表、圖片表Spring 的 Transactional 聲明式事務(wù)比手寫回滾可靠。第三部署簡單一個(gè) Spring Boot 的 fat jar 扔到服務(wù)器上就能跑和前端同學(xué)聯(lián)調(diào)時(shí)最省事。對比一下常見選型給要做技術(shù)選型答辯的同學(xué)做個(gè)參考技術(shù)棧優(yōu)點(diǎn)明顯的坑Spring Boot MyBatis-Plus MySQL資料多、答辯好講、事務(wù)可靠JDK 版本和 Spring Boot 版本要匹配SSMSpring SpringMVC MyBatis老項(xiàng)目多網(wǎng)上源碼多配置繁瑣XML 寫起來痛苦微信原生小程序 uniapp 開發(fā)原生上手快uniapp 能一稿多端原生代碼沒法復(fù)用打包成 Android/iOS 和鴻蒙時(shí)兼容性要額外處理Node.js Express輕量、寫起來快事務(wù)和類型約束弱答辯容易被追問小程序端建議用原生因?yàn)檫@個(gè)畢設(shè)只需要跑微信一個(gè)端沒必要上 uniapp 多端。如果老師問“為什么不用 uniapp 開發(fā)”可以回答題目只要求微信小程序原生 API 更直接調(diào)試時(shí)小程序開發(fā)者工具的支持也最好。這個(gè)說法通常能過關(guān)。2.3 數(shù)據(jù)庫表設(shè)計(jì)幫扶對象主表、走訪記錄表、幫扶措施表的關(guān)聯(lián)數(shù)據(jù)收集平臺的表結(jié)構(gòu)比電商、聊天類小程序簡單但有一個(gè)特別容易犯的錯(cuò)把所有字段塞進(jìn)一張大表。不少源碼包就是一張 resident 表搞定走訪次數(shù)多的戶同一戶信息被重復(fù)錄了好幾遍臺賬對不上。正確做法是拆成主表和流水表。至少要有這幾張基礎(chǔ)表用戶表sys_user、幫扶對象主表resident、走訪記錄表visit_record、幫扶措施表help_item以及一張圖片附件表attachment。下面是核心建表 SQL按 MySQL 8 寫-- 幫扶對象主表一個(gè)幫扶對象一條記錄 CREATE TABLE resident ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 主鍵, name VARCHAR(30) NOT NULL COMMENT 姓名, id_card VARCHAR(18) NOT NULL COMMENT 身份證號, phone VARCHAR(11) DEFAULT NULL COMMENT 手機(jī)號, family_addr VARCHAR(200) DEFAULT NULL COMMENT 家庭地址, household_type VARCHAR(20) DEFAULT NULL COMMENT 戶類型, status TINYINT NOT NULL DEFAULT 1 COMMENT 狀態(tài)1正常 0歸檔, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_id_card (id_card) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT幫扶對象主表; -- 走訪記錄表每次入戶一條流水 CREATE TABLE visit_record ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 主鍵, resident_id BIGINT NOT NULL COMMENT 關(guān)聯(lián)對象主鍵, visitor_id BIGINT NOT NULL COMMENT 走訪人用戶ID, visit_date DATE NOT NULL COMMENT 走訪日期, income_amt DECIMAL(10,2) DEFAULT NULL COMMENT 家庭月收入, live_status VARCHAR(255) DEFAULT NULL COMMENT 生活狀況描述, remark VARCHAR(500) DEFAULT NULL COMMENT 備注, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_resident (resident_id), KEY idx_visit_date (visit_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT走訪記錄表; -- 幫扶措施表走訪后要落實(shí)的具體措施 CREATE TABLE help_item ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 主鍵, visit_id BIGINT NOT NULL COMMENT 關(guān)聯(lián)走訪記錄, item_name VARCHAR(100) NOT NULL COMMENT 措施名稱, item_detail VARCHAR(500) DEFAULT NULL COMMENT 措施內(nèi)容, finish_flag TINYINT NOT NULL DEFAULT 0 COMMENT 完成標(biāo)記 0未完成 1已完成, PRIMARY KEY (id), KEY idx_visit (visit_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT幫扶措施表;三個(gè)關(guān)鍵點(diǎn)說明一下。第一id_card 用 varchar(18) 而不是數(shù)值類型身份證超過 19 位精度會崩這是個(gè)經(jīng)典坑后文還會展開。第二visit_record 的 resident_id 建了索引因?yàn)楹笈_最常見的查詢是“某個(gè)幫扶對象的所有走訪記錄”。第三income_amt 用 DECIMAL(10,2)金額字段絕不能用 float/Double二進(jìn)制浮點(diǎn)存金額會有精度誤差答辯老師看到 DECIMAL 反而會加分。圖片附件表比較簡單字段就是 id、visit_id、file_url、create_time一個(gè)走訪記錄對應(yīng)多張圖片。關(guān)聯(lián)關(guān)系resident 1—N visit_recordvisit_record 1—N help_itemvisit_record 1—N attachment。這套結(jié)構(gòu)對畢設(shè)夠用了。如果手里源碼包是單表存儲建議花半天自己拆一下這是答辯時(shí)實(shí)打?qū)嵉牧咙c(diǎn)。3. 小程序端把「收集」做順表單校驗(yàn)、圖片上傳和離線草稿小程序端是整個(gè)平臺的排面演示視頻里八成鏡頭都在拍它。這一章不講頁面布局只講三個(gè)直接影響數(shù)據(jù)質(zhì)量的功能點(diǎn)表單校驗(yàn)、圖片證據(jù)上傳、離線草稿箱。3.1 入戶走訪表單的組件選型與校驗(yàn)邏輯走訪表單字段不少但涉及文本、日期、單選、金額、多行文本。微信小程序沒有 HTML form 那種自動提交機(jī)制每個(gè)字段都要自己綁定 value 和事件。常見做法是姓名、手機(jī)號、身份證號用 input分別配 typetext、number、idcard戶類型、生活狀況等枚舉字段用 radio-group 做單選框避免手輸造成的臟數(shù)據(jù)家庭月收入這種數(shù)值字段用 input typedigit保證只能輸入數(shù)字和小數(shù)點(diǎn)備注用 textarea。校驗(yàn)建議在提交函數(shù)里統(tǒng)一做而不是每個(gè) input 的 blur 事件里各寫一套。模糊校驗(yàn)容易出現(xiàn)“邊輸邊報(bào)錯(cuò)”的干擾體驗(yàn)統(tǒng)一校驗(yàn)還可以把錯(cuò)誤信息集中起來一次提示。參考邏輯// pages/visit/visit.js 提交前的統(tǒng)一校驗(yàn) function validateForm(form) { const errors []; if (!form.name) errors.push(姓名不能為空); if (!/^\d{17}[\dXx]$/.test(form.idCard)) errors.push(身份證號格式不正確); if (form.phone !/^1[3-9]\d{9}$/.test(form.phone)) errors.push(手機(jī)號格式不正確); if (form.income !/^\d(\.\d{1,2})?$/.test(form.income)) errors.push(金額最多兩位小數(shù)); return errors; }核心校驗(yàn)就三條身份證號 18 位且末位允許 X手機(jī)號以 1[3-9] 開頭共 11 位金額最多兩位小數(shù)。正則放在一起的好處是演示時(shí)故意輸錯(cuò)錯(cuò)誤提示清晰老師會認(rèn)為你考慮了數(shù)據(jù)質(zhì)量。小程序端有“掃描身份證自動識別”的方案但不是題目必需不做不影響完成度先把手輸校驗(yàn)做扎實(shí)更穩(wěn)。3.2 圖片證據(jù)采集chooseMedia 的坑與上傳時(shí)序走訪記錄配現(xiàn)場照片這是“數(shù)據(jù)收集平臺”區(qū)別于普通表單的核心。圖片功能有兩個(gè)容易翻車的地方API 版本用錯(cuò)以及圖片和表單提交的時(shí)序錯(cuò)誤。取圖接口現(xiàn)在用 wx.chooseMedia老項(xiàng)目里的 wx.chooseImage 在基礎(chǔ)庫較新時(shí)已經(jīng)不建議使用。chooseMedia 常用參數(shù)wx.chooseMedia({ count: 3, // 最多選3張 mediaType: [image], // 只允許圖片不需要視頻 sourceType: [camera, album], // 拍照或相冊都允許 sizeType: [compressed], // 取壓縮圖原圖上傳容易被網(wǎng)絡(luò)卡死 success: (res) { const files res.tempFiles.map(f f.tempFilePath); this.setData({ images: files }); } });sizeType 選 compressed 是關(guān)鍵。在校內(nèi)用 Wi-Fi 傳大圖看不出問題真機(jī)在鄉(xiāng)鎮(zhèn)網(wǎng)絡(luò)差的時(shí)候原圖上傳直接卡死。如果小程序基礎(chǔ)庫版本偏低沒有 chooseMedia需要降級到 wx.chooseImage兩個(gè)接口的 success 返回結(jié)構(gòu)不同做兼容時(shí)注意 tempFiles 的字段差異。圖片和表單的提交順序建議先傳圖片、后交表單。用戶點(diǎn)“提交”后小程序先把選中的圖片逐張傳給 Java 的 /api/file/upload拿到服務(wù)器返回的 URL 列表再把 URL 拼到表單里一起提交。這樣做的好處是走訪記錄主表和圖片附件在同一個(gè)事務(wù)里寫入不會出現(xiàn)“記錄存了但圖片丟了一半”。// 先逐張上傳圖片拿到 URL 列表后再提交表單 function uploadImages(tempFiles) { const tasks tempFiles.map((file) { return new Promise((resolve, reject) { wx.uploadFile({ url: app.globalData.baseUrl /api/file/upload, filePath: file.tempFilePath, // chooseMedia 拿到的臨時(shí)路徑 name: file, // 后端接收的字段名必須和Controller參數(shù)一致 success: (res) { const resp JSON.parse(res.data); if (resp.code 0) resolve(resp.data.url); else reject(new Error(上傳失敗 resp.message)); }, fail: reject }); }); }); return Promise.all(tasks); // 全部成功才繼續(xù)模擬先圖后主 }注意uploadFile 的 name 參數(shù)必須和后端 RequestParam(file) 的參數(shù)名一致否則后端拿到空文件。Promise.all 是“一張失敗整體失敗”的語義正好符合“證據(jù)必須齊”的業(yè)務(wù)要求。3.3 離線草稿箱沒信號時(shí)數(shù)據(jù)不丟的實(shí)現(xiàn)入戶走訪經(jīng)常在鄉(xiāng)鎮(zhèn)和村里信號差是常態(tài)。這個(gè)題目最值得加分的設(shè)計(jì)就是本地草稿箱沒網(wǎng)絡(luò)時(shí)不阻塞錄入等有網(wǎng)再提交。實(shí)現(xiàn)不復(fù)雜用小程序本地存儲接口就能完成。// 保存草稿把整份表單塞進(jìn)本地緩存 function saveDraft(key, formData) { // wx.setStorageSync 是同步接口數(shù)據(jù)量小寫完后立刻可讀 wx.setStorageSync(draft_${key}, { data: formData, savedAt: Date.now() // 記錄保存時(shí)間方便后面做過期清理 }); } // 提交時(shí)先檢測網(wǎng)絡(luò)類型無網(wǎng)則落草稿箱 function ensureNetwork() { return new Promise((resolve) { wx.getNetworkType({ success: (res) resolve(res.networkType ! none), fail: () resolve(false) }); }); }草稿箱業(yè)務(wù)邏輯就三件事提交前檢測網(wǎng)絡(luò)沒網(wǎng)就寫緩存并提示“已存為草稿”有網(wǎng)時(shí)把草稿列表逐條提交成功后刪除對應(yīng)緩存設(shè)置緩存時(shí)間7 天以上的草稿標(biāo)記過期提示補(bǔ)錄。這個(gè)功能答辯時(shí)很好講一句“針對走訪場景的網(wǎng)絡(luò)不可用做了離線兜底”就值回票價(jià)。在微信小程序項(xiàng)目實(shí)例里能把離線草稿做成閉環(huán)的不多多數(shù)只是寫死了一個(gè) setStorageSync看到本地緩存就結(jié)束了。4. Java 后端從零搭到能跑依賴、接口和數(shù)據(jù)庫落地后端是評閱老師真正會看代碼的部分。這一章按“骨架 → 接口 → 數(shù)據(jù)落地”三步走每一步都給可以直接抄的配置和代碼。4.1 Spring Boot 項(xiàng)目骨架與依賴選型老一點(diǎn)的畢設(shè)源碼包經(jīng)常是 SSM 項(xiàng)目要配一堆 XML跑起來很折騰。如果從零寫直接用 Spring Boot 更省事。注意版本配對JDK 8 配 Spring Boot 2.xJDK 17 配 Spring Boot 3.x。很多源碼包跑不起來的第一個(gè)原因就是裝了新 JDK 跑舊項(xiàng)目先記住一句話先看 pom.xml 里 spring-boot-starter-parent 的版本再決定裝哪個(gè) JDK。pom.xml 核心依賴如下parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.18/version relativePath/ /parent dependencies !-- Web 接口層 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- ORM 框架MyBatis-Plus 省去手寫大量單表 CRUD -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency !-- MySQL 驅(qū)動8.x 驅(qū)動類名和 5.x 不同 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency !-- 默認(rèn)連接池 HikariCPSpring Boot 2.x 內(nèi)置 -- dependency groupIdcom.zaxxer/groupId artifactIdHikariCP/artifactId /dependency !-- Lombok 減少實(shí)體類樣板代碼 -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependencies幾個(gè)選擇說下原因。MyBatis-Plus 是畢設(shè)標(biāo)配它把單表 CRUD 的 SQL 省了分頁插件也成熟答辯時(shí)可以少背很多 XMLHikariCP 是 Spring Boot 默認(rèn)連接池不需要額外引入 Druid除非老師點(diǎn)名要看監(jiān)控頁面Lombok 必須裝 IDE 插件否則代碼里瘋狂報(bào)錯(cuò)這點(diǎn)容易被忽略。4.2 三個(gè)核心接口的設(shè)計(jì)登錄鑒權(quán)、提交走訪數(shù)據(jù)、圖片上傳后端接口不要貪多把三個(gè)做扎實(shí)就夠登錄鑒權(quán)、提交走訪數(shù)據(jù)、圖片上傳。接口方法路徑說明登錄POST/api/user/login賬號密碼登錄返回 token提交走訪數(shù)據(jù)POST/api/visit/submit主表明細(xì)表圖片URL一次提交圖片上傳POST/api/file/upload單圖上傳返回 URL登錄鑒權(quán)畢設(shè)階段用簡單 Token 就可以不需要引入 Spring Security 全家桶。提交走訪數(shù)據(jù)是一個(gè)典型事務(wù)場景核心 Service 代碼Service public class VisitService { Resource private VisitRecordMapper visitRecordMapper; Resource private HelpItemMapper helpItemMapper; Resource private AttachmentMapper attachmentMapper; /** * 提交走訪數(shù)據(jù)主表 措施明細(xì) 圖片地址要么全成功要么全回滾。 */ Transactional(rollbackFor Exception.class) public Long submitVisit(VisitSubmitDTO dto) { // 1. 插入走訪主表 VisitRecord record new VisitRecord(); record.setResidentId(dto.getResidentId()); record.setVisitorId(dto.getVisitorId()); record.setVisitDate(dto.getVisitDate()); record.setIncomeAmt(dto.getIncomeAmt()); record.setLiveStatus(dto.getLiveStatus()); record.setRemark(dto.getRemark()); visitRecordMapper.insert(record); // 2. 批量插入幫扶措施一對多 if (CollectionUtils.isNotEmpty(dto.getHelpItems())) { for (HelpItemDTO item : dto.getHelpItems()) { HelpItem entity new HelpItem(); entity.setVisitId(record.getId()); entity.setItemName(item.getItemName()); entity.setItemDetail(item.getItemDetail()); entity.setFinishFlag(0); helpItemMapper.insert(entity); } } // 3. 批量插入圖片附件URL 是小程序先上傳拿到的 if (CollectionUtils.isNotEmpty(dto.getImageUrls())) { for (String url : dto.getImageUrls()) { Attachment att new Attachment(); att.setVisitId(record.getId()); att.setFileUrl(url); attachmentMapper.insert(att); } } return record.getId(); } }這個(gè)方法的邏輯分三步先插主表拿到自增主鍵再依次插措施表和附件表。關(guān)鍵在 Transactional(rollbackFor Exception.class)它保證任何一步拋異常前面的插入全部回滾。這就是 Java 后端最有說頭的地方數(shù)據(jù)一致性靠事務(wù)而不是靠代碼里 if-else 兜底。面試常問的“Java 怎么保證數(shù)據(jù)一致性”在這個(gè)接口上就能答出實(shí)際案例。4.3 數(shù)據(jù)庫連接池與事務(wù)批量保存走訪明細(xì)連接池參數(shù)直接決定演示時(shí)會不會出現(xiàn)“幾個(gè)人同時(shí)提交就卡死”。application.yml 里 HikariCP 常用配置spring: datasource: url: jdbc:mysql://localhost:3306/poverty_data?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver hikari: maximum-pool-size: 10 minimum-idle: 2 connection-timeout: 30000 idle-timeout: 600000參數(shù)說明maximum-pool-size 設(shè) 10 夠畢設(shè)場景太小了演示時(shí)連自己在內(nèi)幾個(gè)賬號同時(shí)提交會排隊(duì)connection-timeout 30 秒超過就報(bào)錯(cuò)而不是無限等serverTimezoneAsia/Shanghai 必須加否則 MySQL 8 默認(rèn)時(shí)區(qū)會給時(shí)間字段帶來 8 小時(shí)偏差。MySQL 8 的驅(qū)動類名是 com.mysql.cj.jdbc.Driver老項(xiàng)目里的 com.mysql.jdbc.Driver 在新驅(qū)動下會直接報(bào)錯(cuò)這也是源碼包常見翻車點(diǎn)。5. 聯(lián)調(diào)和答辯前避坑畢業(yè)設(shè)計(jì)最常見的 6 個(gè)翻車點(diǎn)這一章全是實(shí)際跑畢設(shè)踩過的坑每條按“現(xiàn)象 → 原因 → 解決”寫可以直接對照排查。5.1 真機(jī)預(yù)覽時(shí) request 域名校驗(yàn)失敗現(xiàn)象小程序開發(fā)者工具里接口調(diào)得好好的掃碼真機(jī)預(yù)覽所有請求全部失敗報(bào) url not in domain list。原因微信小程序?qū)?request 合法域名校驗(yàn)很嚴(yán)格開發(fā)者工具勾了“不校驗(yàn)合法域名”能跑真機(jī)上這個(gè)選項(xiàng)無效域名必須是備案過的 HTTPS。很多畢設(shè)源碼包接口地址寫的是 localhost 或局域網(wǎng) IP真機(jī)上必掛。解決只做校內(nèi)答辯演示的話常見做法是把后端部署到一臺有公網(wǎng) HTTPS 域名的服務(wù)器在小程序后臺的“開發(fā)管理-開發(fā)設(shè)置”里把 request 合法域名配上。實(shí)在沒有域名可以用真機(jī)調(diào)試模式配合開發(fā)者工具臨時(shí)繞過但只限開發(fā)者本人正式演示有風(fēng)險(xiǎn)。更省事的方案直接用開發(fā)者工具錄演示視頻答辯時(shí)說明這是本地開發(fā)環(huán)境很多學(xué)校是接受的。5.2 圖片上傳成功但拿不到服務(wù)器返回的 URL現(xiàn)象wx.uploadFile 返回了 200但 res.data 怎么拿都不是對象取 url 一直是 undefined。原因uploadFile 的返回 data 是字符串而不是 JSON 對象教程直接寫 res.data.url字符串上取屬性自然是 undefined。這是后端封裝成 {code, message, data} 結(jié)構(gòu)時(shí)最經(jīng)典的配對失誤。解決拿到返回先 JSON.parse 再取字段const resp JSON.parse(res.data); if (resp.code 0) { const url resp.data.url; // 現(xiàn)在才是真正的文件URL }另外注意后端返回的 URL 要能被小程序訪問。如果返回的是 “upload/images/xxx.jpg” 這種相對路徑小程序 image 組件解析不出完整 http 地址后端要拼上域名前綴再返回。5.3 身份證號、手機(jī)號字段精度丟失現(xiàn)象數(shù)據(jù)庫里身份證號變成科學(xué)計(jì)數(shù)法或者手機(jī)號末位變成 0。原因建表時(shí)把 id_card 和 phone 建成了數(shù)值類型Java 里用 Long 接收身份證。身份證 18 位超過安全精度范圍手機(jī)號 11 位如果走了 Excel 導(dǎo)入單元格格式會把長數(shù)字轉(zhuǎn)成科學(xué)計(jì)數(shù)法。演示時(shí)這類問題特別容易被老師當(dāng)場指出來。解決數(shù)據(jù)庫一律用 varchar 存Java 實(shí)體類用 String。順帶檢查一下 MyBatis-Plus 實(shí)體類字段類型類型寫錯(cuò)時(shí)插入階段就可能報(bào)錯(cuò)算運(yùn)氣好運(yùn)氣不好就是靜默丟精度查臺賬怎么都對不上。5.4 MySQL 時(shí)區(qū)導(dǎo)致時(shí)間差 8 小時(shí)現(xiàn)象小程序提交的走訪日期顯示正常create_time 比北京時(shí)間慢了 8 個(gè)小時(shí)。原因MySQL 8 默認(rèn)時(shí)區(qū)是 UTCJDBC 連接串沒帶時(shí)區(qū)參數(shù)時(shí)驅(qū)動按服務(wù)器時(shí)區(qū)解釋時(shí)間戳。本地開發(fā)機(jī)器系統(tǒng)時(shí)區(qū)如果是 Asia/Shanghai插入和查詢各差 8 小時(shí)看起來像“時(shí)間穿越”。解決JDBC URL 上加 serverTimezoneAsia/Shanghai同時(shí)確認(rèn) MySQL 服務(wù)端時(shí)區(qū)SHOW VARIABLES LIKE %time_zone%; 如果 Global time zone 是 SYSTEM執(zhí)行 SET GLOBAL time_zone 08:00;。Java 實(shí)體類的 create_time 建議用 LocalDateTime默認(rèn)映射行為更可控。5.5 演示視頻里最常見的翻車?yán)鋯硬椴坏綌?shù)據(jù)現(xiàn)象錄演示視頻時(shí)小程序白屏轉(zhuǎn)圈接口超時(shí)后臺臺賬列表是空的。原因后端沒啟動、數(shù)據(jù)庫沒導(dǎo)入、或者小程序里配置的 baseURL 指向了已失效的地址。很多源碼包把接口地址寫死在某臺臨時(shí)服務(wù)器上作者把服務(wù)器一關(guān)代碼就變廢包。演示前一天還正常答辯當(dāng)天掛多半是環(huán)境沒起全。解決錄視頻前走一遍檢查清單。第一步確認(rèn) MySQL 服務(wù)在跑root 能連上。第二步啟動后端看控制臺有沒有數(shù)據(jù)源報(bào)錯(cuò)。第三步小程序開發(fā)者工具里確認(rèn) baseURL 指向本機(jī)局域網(wǎng) IP真機(jī)調(diào)試時(shí)手機(jī)和電腦要在同一網(wǎng)絡(luò)。第四步隨便提一條測試數(shù)據(jù)去數(shù)據(jù)庫 SELECT 一下確認(rèn)物理落庫后再開錄。這四步花五分鐘能避開九成演示翻車。5.6 源碼包里的數(shù)據(jù)庫腳本導(dǎo)入失敗現(xiàn)象拿到一個(gè) zip 源碼包導(dǎo)入 .sql 時(shí)直接報(bào)錯(cuò)或者后端啟動提示連接被拒絕。原因三個(gè)常見來源。一是 SQL 文件是高版本 MySQL 導(dǎo)出的本地版本低遇到新字符集或約束語法直接報(bào)錯(cuò)二是腳本里寫了 USE 某個(gè)自定義庫名本地沒有這個(gè)庫三是 MySQL 8 默認(rèn)認(rèn)證插件和舊驅(qū)動不兼容。解決先看 SQL 文件開頭手動建好同名數(shù)據(jù)庫再導(dǎo)入。導(dǎo)入報(bào)錯(cuò)時(shí)用文本編輯器打開定位到第一條報(bào)錯(cuò)語句刪掉不兼容的語法再試。驅(qū)動版本低于 8.0 就把項(xiàng)目換成 mysql-connector-java 8.x。密碼認(rèn)證問題可以執(zhí)行 ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 你的密碼; 再用舊驅(qū)動連。字符集記得統(tǒng)一 utf8mb4避免中文亂碼和數(shù)據(jù)導(dǎo)入半截。6. 演示視頻的錄制腳本從「能跑」到「像樣」的三個(gè)技巧畢設(shè) zip 里如果演示視頻是隨手錄的印象分會打折。錄制前先寫腳本按“登錄 → 走訪填單 → 圖片上傳 → 后臺臺賬”四段串每段留兩秒停頓方便剪輯。技巧一數(shù)據(jù)要預(yù)置。演示時(shí)最忌諱從空庫開始錄每條表單要填十幾個(gè)字段老師在旁邊等著一緊張就填錯(cuò)。預(yù)先在數(shù)據(jù)庫里插入幾戶幫扶對象走訪記錄也留幾條視頻里演示的是“新增一條走訪記錄”而不是“從零開始錄入一個(gè)對象”。這一步看起來小錄出來的節(jié)奏完全不同。技巧二錄屏?xí)r把證據(jù)鏈錄進(jìn)去。小程序端錄制時(shí)旁邊開一個(gè)小窗顯示后端日志或者錄完小程序立刻切到 Navicat 查詢新插入的記錄。這樣做能向老師證明數(shù)據(jù)真的落庫了不是前端假數(shù)據(jù)。不用多復(fù)雜Navicat 查詢結(jié)果窗口往屏幕右下角一放錄進(jìn)去十秒就夠。截圖放進(jìn)論文文檔也是同一個(gè)素材一舉兩得。技巧三給演示視頻加關(guān)鍵停頓和簡單字幕。老師可能靜音看視頻把操作步驟和關(guān)鍵提示做成字幕壓在底部填了什么字段、為什么這樣校驗(yàn)、上傳成功后 URL 返回到哪里。字幕不用多每段一句控制節(jié)奏。我用過的笨辦法是后期在剪映里加放大特效突出表單校驗(yàn)彈窗讓老師看清彈窗內(nèi)容和觸發(fā)時(shí)機(jī)。如果視頻里必須展示真機(jī)預(yù)覽先把 5.1 里的域名問題解決否則真機(jī)上接口不通整段視頻都是廢的。我個(gè)人的習(xí)慣是開發(fā)者工具錄主流程真機(jī)錄一個(gè)十秒的操作特寫兩段拼起來。當(dāng)年我答辯時(shí)因?yàn)橐曨l里校驗(yàn)彈窗一閃而過被追問“這個(gè)校驗(yàn)到底怎么觸發(fā)的”現(xiàn)場又重新演示才講清。從那以后我錄視頻都會在關(guān)鍵彈窗處停兩秒再繼續(xù)操作。這個(gè)教訓(xùn)寫在這里希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取