設(shè)計與實現(xiàn))
馬拉松報名這種場景放在微信小程序里做其實非常典型。跑團需要報名、賽事方需要管理報名數(shù)據(jù)、選手要查號碼簿和比賽信息一個報名系統(tǒng)要同時面對這三類角色。我最近剛陪一個做畢設(shè)的朋友把這個項目從0到1完整走了一遍從需求梳理到數(shù)據(jù)庫設(shè)計從前端頁面到后端接口中間踩了不少坑也總結(jié)出一套可以復(fù)用的實現(xiàn)思路。這篇就圍繞“基于微信小程序的馬拉松報名系統(tǒng)”這個題目把項目里真正值得花時間的部分拆開講清楚產(chǎn)品流程、表結(jié)構(gòu)、支付對接、號碼簿生成、論文寫法以及那些不實際做一遍根本發(fā)現(xiàn)不了的問題。如果你是計算機相關(guān)專業(yè)的學(xué)生正準(zhǔn)備做這類“小程序報名”方向的畢設(shè)或課設(shè)這篇可以直接當(dāng)項目實施參考。如果只是對小程序開發(fā)感興趣想了解一個完整業(yè)務(wù)系統(tǒng)長什么樣也可以看到從用戶點擊報名到訂單支付的完整鏈路。1. 報名系統(tǒng)到底在解決什么問題先說業(yè)務(wù)。馬拉松報名和普通的電商下單有本質(zhì)區(qū)別它賣的不是實物商品而是一個參賽名額還附帶參賽項目選擇、參賽者信息填報、支付、號碼簿分配、報名數(shù)據(jù)統(tǒng)計這一整條鏈路。這就決定了系統(tǒng)必須有兩個核心身份普通跑者和賽事管理員。1.1 業(yè)務(wù)角色與基本流程梳理普通跑者端的典型流程是打開小程序看賽事列表進入賽事詳情頁了解比賽時間、地點、項目和費用選擇自己報名的項目填寫姓名、身份證號、手機號、緊急聯(lián)系人、衣服尺碼等信息提交訂單并支付支付成功后在小程序里查看報名狀態(tài)和號碼簿。管理員端則是另一套邏輯創(chuàng)建賽事、配置參賽項目全馬、半馬、歡樂跑、維護賽事介紹和公告、查看報名人數(shù)、導(dǎo)出報名名單、發(fā)布比賽相關(guān)通知。把這兩個角色的流程畫出來整個系統(tǒng)的主線就清楚了。后端核心是處理“報名訂單”這條數(shù)據(jù)流前端核心是讓跑者用盡可能少的步驟完成報名。做需求分析時最容易漏掉的是“名額限制”和“未支付訂單超時釋放”這兩個隱性需求后面我會專門講實現(xiàn)方案。1.2 功能模塊劃分與小程序頁面地圖我最終把功能分成四個模塊賽事模塊展示賽事列表、賽事詳情、參賽項目列表支持分頁加載和賽事公告。報名模塊報名表單、參賽項目選擇、尺碼選擇、訂單創(chuàng)建、在線支付。訂單模塊訂單列表、訂單詳情、支付狀態(tài)、取消訂單、號碼簿查看。個人中心模塊用戶信息展示、頭像昵稱修改、我的報名記錄、關(guān)于賽事的信息。對應(yīng)的微信小程序頁面結(jié)構(gòu)大致是pages/index/index賽事列表首頁pages/event/detail賽事詳情頁pages/apply/apply報名表單頁pages/order/list我的報名記錄列表pages/order/detail訂單詳情頁pages/user/user個人中心頁頁面不多但每個頁面之間的數(shù)據(jù)流轉(zhuǎn)關(guān)系需要注意。比如賽事詳情頁要能直接跳轉(zhuǎn)報名頁并把賽事ID和項目ID帶過去報名成功后要能跳轉(zhuǎn)訂單詳情頁而不是簡單彈一個“報名成功”的提示。這些交互細(xì)節(jié)做得順暢整體體驗才會加分。1.3 技術(shù)選型我為什么選原生小程序而不是uni-app現(xiàn)在做微信小程序繞不開一個選擇用原生開發(fā)者工具寫還是用uni-app這類跨端框架。很多項目都會在這上面糾結(jié)。uni-app的優(yōu)勢是“一套代碼多端復(fù)用”同一套代碼可以編譯到微信小程序、支付寶小程序還能打包成Android和iOS的App。如果你的項目有后續(xù)多端上線的計劃選uni-app是合理的。但代價是調(diào)試鏈路變長很多微信原生能力比如某些隱私接口、實時日志需要通過條件編譯去兼容遇到問題排查成本會高不少。我做這個項目用的是原生小程序開發(fā)。原因很簡單這個項目只看微信一個端用原生框架能直接吃到微信開發(fā)者工具的全部調(diào)試能力和最新的API支持比如頭像昵稱填寫能力、wx.requestPayment支付、onReachBottom分頁加載等。更關(guān)鍵的是項目的論文里在寫“技術(shù)選型”時原生開發(fā)能給出更直接的論據(jù)不需要引入額外框架開發(fā)調(diào)試路徑短后續(xù)維護成本低。如果是在校生做畢設(shè)我更建議選原生。答辯時老師大概率會問“為什么不用uni-app”這時候可以回答uniapp適合跨端需求本項目只面向微信生態(tài)采用原生開發(fā)可以充分利用微信提供的原生能力和調(diào)試工具降低依賴復(fù)雜度。這個回答既客觀又能體現(xiàn)你的思考。2. 數(shù)據(jù)庫設(shè)計與核心接口約定數(shù)據(jù)庫設(shè)計決定這個項目能做多深。很多人的報名系統(tǒng)做出來像“玩具項目”很大程度上是因為表設(shè)計太簡單只有一張用戶表加一張訂單表賽事信息寫死在頁面里。但一個真正能用的馬拉松報名系統(tǒng)賽事、參賽項目、訂單必須是分表的還要考慮號碼簿、公告這些擴展能力。2.1 核心數(shù)據(jù)表設(shè)計我最終設(shè)計了六張核心表用戶表、賽事表、參賽項目表、報名訂單表、號碼簿表、公告表。用戶表主要字段字段類型說明idbigint主鍵openidvarchar微信openid唯一nicknamevarchar用戶昵稱avatarvarchar頭像URLmobilevarchar手機號created_atdatetime創(chuàng)建時間updated_atdatetime更新時間openid是用戶在小程序體系里的唯一身份標(biāo)識后端登錄時通過wx.login拿到code再調(diào)用微信的接口換成openid。這里有個容易被坑的地方一個微信用戶在不同小程序里openid不同如果后續(xù)要跨小程序共享用戶數(shù)據(jù)需要引入unionid普通報名場景用openid就夠了。賽事表和參賽項目表是我特別想強調(diào)的部分因為很多第一次做的人會把“馬拉松賽事”和“參賽項目”混在一起直接在賽事表里放一個“全程馬拉松”“半程馬拉松”的字符串字段。這會導(dǎo)致后面按項目統(tǒng)計報名人數(shù)、按項目分配號碼簿時非常痛苦。我的做法是拆成兩張表。賽事表存比賽的基本信息比賽名稱、封面圖、介紹、舉辦時間、舉辦地點、賽事狀態(tài)、總名額限制。參賽項目表存每個賽事下的具體項目與賽事是主從關(guān)系字段包括項目名稱全馬/半馬/歡樂跑、距離、報名費、報名開始時間、報名截止時間、項目名額限制、當(dāng)前已報名人數(shù)。訂單表的字段是重頭戲直接關(guān)系到支付流程能否走通。我的訂單表核心字段包括訂單號、用戶ID、賽事ID、參賽項目ID、報名聯(lián)系人姓名、身份證號、手機號、緊急聯(lián)系人、衣服尺碼、訂單狀態(tài)、報名費金額單位分、支付時間、創(chuàng)建時間、更新時間。這里強調(diào)一個字段設(shè)計細(xì)節(jié)金額一律用“分”存儲用整數(shù)類型。很多新手用decimal(10,2)存微信支付的金額結(jié)果回調(diào)金額比較時因為精度問題對不上很折磨人。微信支付的金額單位本身就是分后臺存儲保持一致轉(zhuǎn)成元做展示就行。2.2 報名訂單狀態(tài)機訂單狀態(tài)是整個系統(tǒng)的核心每個狀態(tài)轉(zhuǎn)換都要有明確觸發(fā)條件。我的狀態(tài)定義如下PENDING_PAY待支付。用戶提交報名信息后生成。PAID已支付。支付回調(diào)成功后進入。CANCELLED已取消。用戶主動取消或超時未支付自動取消。REFUNDING退款中。用戶需要退賽時申請。REFUNDED已退款。退款完成后進入。狀態(tài)機圖如果用文字描述就是待支付可以走向已支付和已取消已支付可以走向退款中退款中最終走向已退款。已退款和已取消都是終態(tài)不允許再回到可支付狀態(tài)。業(yè)務(wù)邏輯上要特別注意“超時未支付釋放名額”這個動作。用戶在報名頁填完信息、提交訂單后如果一直不支付訂單不能一直占著名額。常用的策略是15分鐘或30分鐘未支付自動取消訂單并釋放報名名額。這個動作可以用后端定時任務(wù)掃描實現(xiàn)后面我會講具體實現(xiàn)。2.3 后端核心接口設(shè)計后端接口采用RESTful風(fēng)格返回統(tǒng)一的JSON結(jié)構(gòu)格式大致是{code, message, data}。接口按模塊劃分賽事模塊GET /api/event/list賽事分頁列表入?yún)age和sizeGET /api/event/{id}賽事詳情同時返回該賽事下的參賽項目列表報名模塊POST /api/order/create創(chuàng)建報名訂單POST /api/pay/params/{orderNo}獲取微信支付參數(shù)GET /api/order/detail/{orderNo}訂單詳情GET /api/order/list我的報名訂單列表POST /api/order/cancel取消訂單用戶模塊GET /api/user/info獲取用戶信息PUT /api/user/info更新用戶信息號碼簿模塊GET /api/user/bib/{orderNo}查看訂單對應(yīng)號碼簿接口設(shè)計里有個關(guān)鍵點需要用戶登錄態(tài)的接口后端在請求頭里約定一個Authorization字段存放登錄憑證。小程序端每次請求時帶上這個憑證后端通過攔截器統(tǒng)一校驗。不要在每個接口里去判斷登錄狀態(tài)那樣代碼會散得到處都是。3. 小程序端核心功能的實現(xiàn)細(xì)節(jié)小程序端的實現(xiàn)質(zhì)量直接影響用戶對系統(tǒng)的第一印象。這一節(jié)挑幾個最有代表性的功能點展開都是可以真正落地到代碼里的經(jīng)驗。3.1 賽事列表分頁加載與緩存策略賽事列表頁是用戶打開小程序看到的第一屏需要同時處理兩個問題列表數(shù)據(jù)量大了之后不能一次性加載全部以及用戶反復(fù)進入頁面時不能每次都重新請求接口。分頁加載用小程序原生的onReachBottom配合頁碼實現(xiàn)。初始page1每次請求返回數(shù)據(jù)和hasMore標(biāo)記。當(dāng)頁面滾動到底部觸發(fā)onReachBottom時判斷hasMore且當(dāng)前不在加載中就把page1再去請求。這里有個小細(xì)節(jié)請求期間要加一個loading標(biāo)志防止用戶快速滾動時重復(fù)觸發(fā)請求。等請求回來再拼接到原有列表后面。緩存策略上我對賽事列表做了5分鐘緩存。緩存的實現(xiàn)不是簡單的wx.setStorageSync存數(shù)據(jù)而是存一個帶過期時間的對象const CACHE_KEY event_list_cache const EXPIRE_TIME 5 * 60 * 1000 function getEventListCache() { const cache wx.getStorageSync(CACHE_KEY) if (!cache || !cache.expireTime) return null if (Date.now() cache.expireTime) { wx.removeStorageSync(CACHE_KEY) return null } return cache.data } function setEventListCache(data) { wx.setStorageSync(CACHE_KEY, { data, expireTime: Date.now() EXPIRE_TIME }) }這個做法在論文里能當(dāng)一個小亮點寫上通過本地緩存減少不必要的網(wǎng)絡(luò)請求優(yōu)化用戶體驗。3.2 報名表單信息校驗與尺碼選擇報名表單是收集用戶信息的關(guān)鍵頁面。馬拉松報名必須收集的信息包括姓名、身份證號、手機號、緊急聯(lián)系人、參賽項目、衣服尺碼。我還在表單里加了“本人已閱讀并同意《參賽聲明》”的勾選這個是線下賽事報名的基本要求。身份證號校驗這里要提一句不要只做正則的長度和格式判斷真正有校驗?zāi)芰Φ氖巧矸葑C第18位校驗碼算法。簡單說就是前17位乘上對應(yīng)權(quán)重求和再對11取模得到校驗碼。這個算法網(wǎng)上有公開的標(biāo)準(zhǔn)實現(xiàn)用一小段函數(shù)就能校驗身份證號真?zhèn)?。答辯時如果老師問起身份證校驗怎么做能說出這個算法是很大的加分項。參賽項目在報名頁用radio-group實現(xiàn)每個項目顯示名稱、距離和價格。衣服尺碼用按鈕組實現(xiàn)讓用戶點選。這里有個交互細(xì)節(jié)進入頁面時先通過賽事詳情接口把項目列表拉下來緩存到頁面data里用戶選好項目后價格自動聯(lián)動顯示。注意不能把項目列表寫死在代碼里因為不同賽事的項目配置完全不同。在用戶點擊“提交訂單”時前端要做一次完整的表單校驗。校驗規(guī)則至少包括姓名不能為空、身份證號格式正確、手機號符合11位規(guī)則、緊急聯(lián)系人和手機號不能為空、已勾選同意聲明。校驗通過后再調(diào)用創(chuàng)建訂單接口。后端接口里也要再校驗一遍因為前端校驗可以被繞過后端必須作為安全邊界。3.3 支付流程從下單到支付回調(diào)支付是整個系統(tǒng)里最容易被卡住的環(huán)節(jié)。完整流程是這樣的第一步用戶在前端提交報名信息前端調(diào)用POST /api/order/create后端生成訂單狀態(tài)為PENDING_PAY返回訂單號。第二步前端拿到訂單號后請求POST /api/pay/params/{orderNo}。后端調(diào)用微信支付的“統(tǒng)一下單”接口傳入appid、商戶號、openid、訂單號、金額單位分、商品描述、回調(diào)通知地址等參數(shù)。微信返回prepay_id后后端再按微信規(guī)范生成二次簽名把timeStamp、nonceStr、package、signType、paySign這幾個參數(shù)返回給前端。第三步前端拿到參數(shù)后調(diào)用wx.requestPayment拉起收銀臺。第四步用戶支付成功后微信服務(wù)器會異步通知你配置的回調(diào)地址。后端在回調(diào)接口里對簽名做驗簽驗簽通過后更新訂單狀態(tài)為PAID同時在同一個事務(wù)里生成號碼簿記錄。這里有一個極容易踩坑的點支付回調(diào)不是只通知一次微信會重試多次而且回調(diào)的到達(dá)順序不一定和用戶支付順序一致。所以回調(diào)處理必須是冪等的。我的實現(xiàn)方式是在回調(diào)里先查訂單當(dāng)前狀態(tài)如果已經(jīng)是PAID就直接返回成功不再重復(fù)更新。還可以在訂單表上加一個唯一索引來兜底防止并發(fā)重復(fù)更新。另一個容易踩坑的點是前端不能用wx.requestPayment的返回值判斷支付結(jié)果因為用戶可以在收銀臺里直接關(guān)閉頁面這時候requestPayment會報錯但訂單可能已經(jīng)支付成功了。正確的做法是支付完成后前端主動跳到訂單詳情頁由后端根據(jù)訂單狀態(tài)決定展示“待支付”還是“已支付”。我在項目里做的是支付回調(diào)發(fā)起后延遲一秒前端輪詢訂單詳情接口拿到最新狀態(tài)再刷新頁面體驗比較穩(wěn)。3.4 我的報名訂單列表與號碼簿展示“我的報名”本質(zhì)上是一個訂單列表按時間倒序展示用戶的所有報名記錄。每條記錄顯示賽事名稱、參賽項目、訂單狀態(tài)、報名費。點擊可以進入訂單詳情頁。訂單詳情頁除了顯示訂單信息外還有一個關(guān)鍵功能已支付訂單要展示號碼簿。號碼簿樣式模擬線下馬博會領(lǐng)取的參賽號碼布上面顯示選手姓名、參賽項目和號碼。號碼的生成邏輯放在后端生成時機是支付成功的回調(diào)里這樣可以保證號碼在用戶支付成功的瞬間就已經(jīng)分配好用戶刷新訂單詳情就能看到。訂單狀態(tài)在頁面上的展示需要做狀態(tài)文案映射。比如待支付顯示“去支付”按鈕已支付顯示“已報名”狀態(tài)標(biāo)簽已取消顯示“已取消”。這里不要在前端寫死狀態(tài)判斷可以把狀態(tài)碼和文案的映射關(guān)系放在一個統(tǒng)一的工具文件里后面維護起來省事。4. 后端能力與管理員側(cè)實現(xiàn)很多畢設(shè)項目把后端寫成“接口轉(zhuǎn)發(fā)器”這是很吃虧的。一個報名系統(tǒng)如果要有競爭力必須在后端體現(xiàn)業(yè)務(wù)邏輯比如名額管理、訂單超時處理、號碼簿生成、報名數(shù)據(jù)統(tǒng)計。這些都可以成為論文里的核心章節(jié)。4.1 后端工程結(jié)構(gòu)與技術(shù)選擇我個人做這個項目用的后端是Spring Boot MyBatis-Plus數(shù)據(jù)庫是MySQLRedis用作緩存和分布式鎖。微信支付相關(guān)邏輯用官方SDK封裝成WechatPayService。工程目錄按模塊分包src/main/java/com/example/marathon ├── controller // 接口層 ├── service // 業(yè)務(wù)邏輯層 ├── mapper // 數(shù)據(jù)訪問層 ├── entity // 數(shù)據(jù)庫實體 ├── dto // 請求和響應(yīng)對象 ├── config // 全局配置、微信支付配置 ├── common // 統(tǒng)一返回、異常處理 ├── task // 定時任務(wù) └── utils // 工具類分包清晰至少有兩個好處一是寫論文時可以畫工程架構(gòu)圖二是改代碼時不會出現(xiàn)“所有代碼都在一個類里”的窘境。4.2 心血管級并發(fā)名額扣減與超時釋放馬拉松報名有一個很現(xiàn)實的并發(fā)問題熱門賽事名額有限大量跑者同時報名系統(tǒng)不能超賣。常規(guī)做法有兩種。第一種是數(shù)據(jù)庫樂觀鎖思路在參賽項目表上維護一個current_enrolled字段更新時帶上名額判斷UPDATE event_item SET current_enrolled current_enrolled 1 WHERE id #{itemId} AND current_enrolled max_enrolled如果更新返回的影響行數(shù)為1說明扣減成功如果影響行數(shù)為0說明名額已經(jīng)被搶完。這個SQL本身就是原子操作不需要額外加鎖。第二種是Redis Lua腳本扣減適合更大并發(fā)場景。但一個畢設(shè)項目用數(shù)據(jù)庫的原子更新其實已經(jīng)足夠了把current_enrolled max_enrolled這個條件寫在SQL里是性價比最高的方案。我在代碼實現(xiàn)里用的就是第一種。超時未支付釋放名額的做法是訂單表在創(chuàng)建時記錄expire_time字段值等于當(dāng)前時間加15分鐘。后端用定時任務(wù)每兩分鐘掃描一次找出所有狀態(tài)為PENDING_PAY且expire_time小于當(dāng)前時間的訂單將其置為CANCELLED同時把參賽項目的current_enrolled扣回去。扣回去的SQL是反向操作UPDATE event_item SET current_enrolled current_enrolled - 1 WHERE id #{itemId} AND current_enrolled 0這里要注意釋放名額和取消訂單需要放在同一個事務(wù)里避免出現(xiàn)訂單取消了但名額沒釋放的數(shù)據(jù)不一致問題。4.3 號碼簿生成規(guī)則號碼簿是一個有儀式感的功能實現(xiàn)起來也不復(fù)雜。我的生成規(guī)則是賽事編碼 項目代碼 四位序列號。比如賽事編碼是M2025全馬項目代碼是A第一位通過報名的全馬選手號碼就是M2025A0001。具體實現(xiàn)是在支付回調(diào)成功的事務(wù)里查出當(dāng)前項目和賽事的編碼信息查該項目下已有的報名人數(shù)然后加1生成新的號碼。號碼生成后寫入號碼簿表以后用戶查詢直接讀這張表就行。號碼簿還有一個細(xì)節(jié)在生成時順帶生成一個二維碼鏈接內(nèi)容是查號碼的頁面地址。線下賽事時工作人員掃碼可以核對選手信息。這個功能可以寫進論文作為系統(tǒng)亮點比單純的“增刪改查”項目高級不少。4.4 管理員統(tǒng)計與導(dǎo)出管理員端的核心價值是數(shù)據(jù)統(tǒng)計和導(dǎo)出。統(tǒng)計包括總報名人數(shù)、各項目報名人數(shù)、每日新增報名趨勢、訂單支付率。導(dǎo)出功能可以把報名名單導(dǎo)出為Excel方便賽事方線下使用字段包括姓名、身份證號、手機號、緊急聯(lián)系人、參賽項目、衣服尺碼、號碼簿號碼。導(dǎo)出用EasyExcel或者POI都可以。實現(xiàn)邏輯很簡單查詢訂單列表把數(shù)據(jù)映射成Excel的每一行輸出到流。關(guān)鍵是導(dǎo)出條件要給夠管理員可以按賽事、按項目、按支付狀態(tài)篩選后導(dǎo)出。5. 論文怎么寫才像“自己的”項目源碼做完以后論文說明是另一個大頭。很多人代碼跑通了論文卻寫得像“說明書”或者“百度百科詞條”答辯直接翻車。這里分享一些寫論文的經(jīng)驗。5.1 論文的章節(jié)框架我建議按這個結(jié)構(gòu)寫第一章緒論。寫選題背景和意義、國內(nèi)外研究現(xiàn)狀、主要研究內(nèi)容和工作安排。注意“研究現(xiàn)狀”一定要結(jié)合具體文獻(xiàn)寫不要空談。第二章相關(guān)技術(shù)介紹。介紹微信小程序、Spring Boot、MySQL、微信支付相關(guān)技術(shù)但要結(jié)合本項目說明為什么用這些技術(shù)不要寫成教科書。第三章需求分析。寫業(yè)務(wù)需求、功能需求、非功能需求配上用例圖。第四章系統(tǒng)設(shè)計。寫總體架構(gòu)設(shè)計、功能模塊設(shè)計、數(shù)據(jù)庫設(shè)計、界面設(shè)計。數(shù)據(jù)庫設(shè)計要包含ER圖和核心表結(jié)構(gòu)。第五章系統(tǒng)實現(xiàn)。寫客戶端各功能模塊的實現(xiàn)、服務(wù)端的實現(xiàn)、微信支付集成。這一章要配界面截圖和核心代碼片段。第六章系統(tǒng)測試。寫測試環(huán)境、功能測試用例、測試結(jié)果分析。最后一章總結(jié)與展望??偨Y(jié)項目成果和不足展望未來可以擴展的功能比如人臉識別檢錄入場、成績實時查詢等。這個框架是標(biāo)準(zhǔn)的軟件工程論文框架老師看了不會挑大問題。5.2 圖表和代碼排版經(jīng)驗論文里圖的力量遠(yuǎn)大于文字。你至少需要準(zhǔn)備這些圖系統(tǒng)總體架構(gòu)圖、功能模塊圖、業(yè)務(wù)流程圖報名流程、數(shù)據(jù)庫ER圖、支付時序圖、每個核心頁面的截圖。這些圖全部自己畫、自己截圖別從網(wǎng)上隨便找。時序圖這里不用專業(yè)的繪圖工具畫在Word里用文本框和箭頭就能完成。支付時序圖要著重表現(xiàn)用戶、小程序前端、后端服務(wù)、微信支付平臺四個角色之間的消息傳遞順序。這張圖畫好了答辯時講支付流程就非常省力。代碼部分不要大段貼在描述核心算法、關(guān)鍵業(yè)務(wù)邏輯時貼10到20行就夠了完整源碼可以放附錄。特別注意排版時中文標(biāo)點的一致性以及代碼塊的字號和等寬字體設(shè)置。很多老師會直接翻論文排版格式不統(tǒng)一的印象分很低。6. 常見問題與避坑記錄做這個項目時踩了不少坑這里整理一個排查手冊供你直接參考。6.1 真機調(diào)試、合法域名與HTTPS問題小程序開發(fā)工具里請求接口默認(rèn)會報“url not in domain list”之類的錯誤。本地開發(fā)階段可以在開發(fā)者工具右上角“詳情-本地設(shè)置”里勾選“不校驗合法域名”這樣能用HTTP的本地IP調(diào)試。但真機預(yù)覽時如果不校驗會連不上而且一旦正式上線必須配置登錄微信公眾平臺在小程序后臺的“開發(fā)管理-開發(fā)設(shè)置-服務(wù)器域名”里配置request合法域名域名必須是已備案的HTTPS域名。我遇到過一種情況配置了合法域名但真機還是請求失敗排查后發(fā)現(xiàn)是SSL證書是自簽發(fā)的微信不認(rèn)。正式環(huán)境一定要用正規(guī)CA機構(gòu)簽發(fā)的證書云廠商提供的免費證書也夠用。6.2 微信支付相關(guān)的問題最經(jīng)典的坑有三個。第一個是金額單位。微信支付接口里所有金額都是“分”比如報名費50元傳參時是5000不是0.01。我在聯(lián)調(diào)時就因為前端傳了元、后端按分處理導(dǎo)致金額少了100倍還好及時發(fā)現(xiàn)。第二個是回調(diào)處理不冪等?;卣{(diào)接口被微信多次調(diào)用后如果每次都把狀態(tài)從“已支付”變成“已完成”頁面狀態(tài)會錯亂。實現(xiàn)里必須加狀態(tài)判斷。第三個是微信支付要求商戶號要求小程序主體是企業(yè)或個體工商戶。個人主體的小程序沒法直接開通微信支付。畢設(shè)階段可以做一個“模擬支付”開關(guān)后端配置里增加mockPaytrue當(dāng)處于模擬模式時前端不調(diào)wx.requestPayment而是直接請求接口把訂單置為已支付。這個開關(guān)保留在代碼里答辯演示時也不會尷尬。6.3 小程序?qū)徍伺c類目如果這個系統(tǒng)真的要上線要提前確認(rèn)小程序的類目。運動和賽事報名通常對應(yīng)“生活服務(wù)-體育”類目可能需要提供相應(yīng)的資質(zhì)文件。審核時特別容易被拒的內(nèi)容包括誘導(dǎo)分享比如分享得獎品、收集身份證號但沒有隱私保護說明。解決辦法是在小程序后臺填寫用戶隱私保護指引聲明收集身份證號、手機號等信息的用途并在用戶首次使用時彈出隱私授權(quán)彈窗。還有年審的問題。認(rèn)證的小程序每年需要做一次年審認(rèn)證費用一般是300元。如果你只是做畢設(shè)不需要管這些但論文里如果寫上“系統(tǒng)上線需要考慮合規(guī)認(rèn)證與年審”會顯得你考慮得很全面。6.4 報名并發(fā)下的數(shù)據(jù)一致性第4節(jié)講過名額扣減SQL這里再補充一個真實場景。我在測試時用兩臺手機同時提交最后一個名額結(jié)果兩個訂單都顯示待支付但SQL扣減只成功一個。這說明“創(chuàng)建訂單成功”和“名額扣減成功”必須放在同一個后端事務(wù)里。正確流程是后端收到創(chuàng)建訂單請求時先執(zhí)行名額扣減SQL扣減成功再插入訂單記錄整個操作在Transactional事務(wù)內(nèi)。如果扣減失敗直接返回“名額已滿”不生成訂單。6.5 小程序端的體驗細(xì)節(jié)坑幾個看起來不起眼但影響體驗的細(xì)節(jié)自定義頂部導(dǎo)航欄時狀態(tài)欄高度獲取接口已從wx.getSystemInfoSync逐步遷移到wx.getWindowInfo舊接口在基礎(chǔ)庫新版本上會告警。報名表單里的單選框點擊區(qū)域要大避免用戶誤觸。列表加載更多時在底部放一個“加載中”提示沒有更多數(shù)據(jù)時顯示“沒有更多了”不然用戶會一直往下滑。我個人在實際操作中的體會是做這類“小程序報名支付”的項目最值得先花時間的是把訂單狀態(tài)機和數(shù)據(jù)庫字段定清楚。狀態(tài)機理清楚前后端聯(lián)調(diào)會順利很多字段設(shè)計好后面做統(tǒng)計和導(dǎo)出都不會返工。還有一個容易被忽略的點身份證號是敏感信息數(shù)據(jù)庫里不能明文存儲至少要做加密答辯時把這個點講出來老師會認(rèn)為你有安全意識。最后給個特別實在的建議代碼從第一天開始就放到Git倉庫里隨時提交我見過不止一個同學(xué)在答辯前一周發(fā)現(xiàn)代碼沒了那種絕望是真的不想再體驗第二次。