源碼:從架構(gòu)到部署完整解析)
簡(jiǎn)介面向畢業(yè)設(shè)計(jì)場(chǎng)景的微信小程序開發(fā)完整資料包以家庭大廚點(diǎn)餐/菜品管理為業(yè)務(wù)主線適合Java方向?qū)W生或初級(jí)開發(fā)者參考學(xué)習(xí)。項(xiàng)目采用SSM框架MySQL數(shù)據(jù)庫(kù)微信開發(fā)者工具實(shí)現(xiàn)覆蓋小程序端與后臺(tái)管理端管理員可維護(hù)用戶、店鋪、菜品信息、菜品分類、購(gòu)買菜品及訂單行等模塊店鋪和用戶登錄后可管理菜品與訂單系統(tǒng)具備較強(qiáng)的實(shí)用性與完整性。包體共1251個(gè)文件壓縮后17.31MB核心類型包括Java源碼、Vue前端頁(yè)面、JS邏輯、JSON配置、WXML/WXSS小程序頁(yè)面等同時(shí)包含png/svg/jpg圖片素材、SQL數(shù)據(jù)庫(kù)腳本、開題報(bào)告、論文、PPT及使用說(shuō)明文檔目錄結(jié)構(gòu)清晰便于按模塊查閱。目前已有98人學(xué)習(xí)下載尤其適合需要完整畢業(yè)設(shè)計(jì)案例、快速搭建運(yùn)行環(huán)境并理解SSM微信小程序前后端交互流程的讀者。1. 家庭大廚微信小程序?yàn)槭裁词且惶淄暾?Java 畢設(shè)而不是一個(gè) Demo家庭大廚微信小程序這個(gè)題目在畢業(yè)設(shè)計(jì)里屬于典型的“業(yè)務(wù)閉環(huán)不大、數(shù)據(jù)表七八張、前端頁(yè)面十來(lái)頁(yè)”的項(xiàng)目。它不像商城那樣要處理復(fù)雜的訂單流轉(zhuǎn)也不像博客那樣只有增刪改查菜譜展示、分類篩選、收藏、評(píng)論、用戶登錄剛好把小程序端、Java 后端、MySQL 數(shù)據(jù)庫(kù)串成一條能講清楚的數(shù)據(jù)鏈路。標(biāo)題里標(biāo)注的是全套 Java 開源畢業(yè)設(shè)計(jì)源碼附帶數(shù)據(jù)庫(kù)、開題報(bào)告、論文、PPT 和使用說(shuō)明這套資料的核心價(jià)值不在于下載完能跑而在于代碼跟文檔能對(duì)上。真正到了答辯現(xiàn)場(chǎng)老師不會(huì)照著 PPT 問(wèn)只會(huì)順著你演示的功能往下追。所以這篇文章按“小程序端怎么寫、Java 后端怎么接、數(shù)據(jù)庫(kù)怎么建、部署演示怎么收尾”的順序把這個(gè)題目背后的一整套方案拆開講清楚。2. 微信小程序 Java 后端的架構(gòu)先把數(shù)據(jù)鏈路定下來(lái)拿到這套家庭大廚源碼第一件事不是打開微信開發(fā)者工具而是先確認(rèn)三個(gè)端的分工小程序只負(fù)責(zé)渲染頁(yè)面和收集用戶操作Java 后端負(fù)責(zé)接口和業(yè)務(wù)邏輯MySQL 負(fù)責(zé)落庫(kù)。這個(gè)分工決定了后面所有代碼的組織方式也決定了答辯時(shí)你能把項(xiàng)目講到什么深度。2.1 為什么選微信小程序而不是 uniapp選技術(shù)棧時(shí)原生微信小程序是這套畢業(yè)設(shè)計(jì)最穩(wěn)的選擇。uniapp 的微信小程序語(yǔ)法上接近 Vue上手快但調(diào)試時(shí)它要經(jīng)過(guò)編譯、打包、預(yù)覽一層轉(zhuǎn)換報(bào)錯(cuò)棧會(huì)先落在 uni 的封裝層對(duì)不熟悉編譯鏈的同學(xué)來(lái)說(shuō)很難在答辯時(shí)把“這一行報(bào)錯(cuò)為什么指向這里”講清楚。原生微信小程序由 WXML、WXSS、JS 三件套組成頁(yè)面結(jié)構(gòu)就是 app.json 注冊(cè)的那幾個(gè)路由哪里報(bào)錯(cuò)直接指向具體頁(yè)面文件演示現(xiàn)場(chǎng)出了狀況也容易救回來(lái)。另一個(gè)必須留意的點(diǎn)是微信小程序頂部導(dǎo)航欄高度。默認(rèn)導(dǎo)航欄由微信客戶端自己渲染不同機(jī)型高度不一樣。如果項(xiàng)目里某個(gè)頁(yè)面用了自定義導(dǎo)航欄布局就會(huì)因?yàn)闋顟B(tài)欄高度不同而整體錯(cuò)位。常見做法是先執(zhí)行wx.getMenuButtonBoundingClientRect()拿到膠囊按鈕的位置再動(dòng)態(tài)計(jì)算導(dǎo)航欄高度。這是小程序開發(fā)里的一個(gè)經(jīng)典坑也是答辯時(shí)容易被追問(wèn)的細(xì)節(jié)。2.2 Spring Boot 是 Java 后端源碼的穩(wěn)妥骨架后端框架不需要花哨Spring Boot 是目前 Java 畢業(yè)設(shè)計(jì)里的主流選擇。它內(nèi)嵌 Tomcat不用打 war 包丟進(jìn)外部容器mvn spring-boot:run一條命令就能起服務(wù)演示前省去大量環(huán)境配置時(shí)間。ORM 層用 MyBatis-Plus分頁(yè)、邏輯刪除、條件構(gòu)造器都是現(xiàn)成的比手寫 JDBC 代碼量小也比 Hibernate 更容易向答辯老師解釋“SQL 是怎么來(lái)的”。家庭大廚源碼里如果給的是 Spring Boot 工程通常會(huì)帶一個(gè)application.yml核心配置如下server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/family_chef?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0server.port是后端服務(wù)端口小程序端 request 的 URL 必須和它對(duì)上。數(shù)據(jù)庫(kù) URL 里用了utf8mb4字符集和Asia/Shanghai時(shí)區(qū)前者是為了能存 emoji 和生僻字后者避免日期時(shí)間字段在 JDBC 層出現(xiàn) 8 小時(shí)偏移。邏輯刪除這一段是 MyBatis-Plus 的特性deleted字段默認(rèn) 0 正常、1 刪除菜譜被刪除之后數(shù)據(jù)還在表里查詢時(shí)框架自動(dòng)帶上deleted 0條件不用每個(gè) SQL 都手工拼接。這套畢設(shè)里所有表都應(yīng)該預(yù)留這個(gè)字段答辯時(shí)老師問(wèn)“刪除怎么做”可以直接拿它回答。2.3 數(shù)據(jù)鏈路一次點(diǎn)擊怎么變成一條 SQL整個(gè)家庭大廚小程序的請(qǐng)求路徑可以歸納成一句話小程序wx.request發(fā)請(qǐng)求Nginx 轉(zhuǎn)發(fā)Spring Boot 的 Controller 接住Service 處理業(yè)務(wù)Mapper 操作 MySQL數(shù)據(jù)再按原路返回。不用流程圖也能講清楚微信開發(fā)者工具里的 Network 面板看到的是小程序到后端的 HTTP 請(qǐng)求后端日志里看到的是一條條 MyBatis 打印的 SQL把這兩頭對(duì)上了整個(gè)鏈路的調(diào)試就完成了一半。按業(yè)務(wù)模塊劃分這套項(xiàng)目的接口和數(shù)據(jù)表大概是下面這個(gè)對(duì)應(yīng)關(guān)系業(yè)務(wù)模塊數(shù)據(jù)表核心接口對(duì)應(yīng)小程序頁(yè)面用戶登錄userPOST /api/user/login登錄頁(yè)菜譜分類categoryGET /api/category/list首頁(yè)分類入口菜譜列表recipeGET /api/recipe/list菜譜列表頁(yè)菜譜詳情recipeGET /api/recipe/detail詳情頁(yè)收藏favoritePOST /api/favorite/do詳情頁(yè)操作評(píng)論commentGET/POST /api/comment詳情頁(yè)評(píng)論區(qū)這個(gè)表格就是整個(gè)開源源碼的骨架。做畢設(shè)的時(shí)候不要拿著一頁(yè)頁(yè)代碼去背先記住這張表每張數(shù)據(jù)表對(duì)應(yīng)一個(gè) Java 實(shí)體類每個(gè)接口對(duì)應(yīng)一個(gè) Controller 方法每個(gè)頁(yè)面綁定一組請(qǐng)求。后面看源碼、改代碼、寫論文都是圍繞這張表展開。3. 小程序端從 app.json 到菜譜頁(yè)面的落地搭建微信小程序的流程入門第一步永遠(yuǎn)是app.json。它是全局配置文件決定小程序啟動(dòng)后先打開哪個(gè)頁(yè)面、底部有哪些 tab、窗口呈現(xiàn)什么樣式。家庭大廚的頁(yè)面骨架并不復(fù)雜典型的首頁(yè)、菜譜列表、菜譜詳情、個(gè)人中心四塊。3.1 app.json 配置頁(yè)面路由與 tabBar一個(gè)最小可運(yùn)行的app.json長(zhǎng)這樣{ pages: [ pages/index/index, pages/recipe/list, pages/recipe/detail, pages/user/profile, pages/user/login ], window: { navigationBarTitleText: 家庭大廚, navigationBarBackgroundColor: #f6f6f6, navigationBarTextStyle: black, backgroundColor: #f6f6f6 }, tabBar: { color: #999999, selectedColor: #ff6b35, list: [ { pagePath: pages/index/index, text: 首頁(yè) }, { pagePath: pages/recipe/list, text: 菜譜 }, { pagePath: pages/user/profile, text: 我的 } ] }, style: v2, sitemapLocation: sitemap.json }pages數(shù)組的第一個(gè)元素是啟動(dòng)頁(yè)這套項(xiàng)目里就是首頁(yè)。tabBar里配置的頁(yè)面必須已經(jīng)存在pages中否則編譯直接報(bào)錯(cuò)。selectedColor是 tab 選中態(tài)的顏色家庭大廚這類美食主題的項(xiàng)目一般用暖橙色或者食欲色避免用純黑配紅這種沖突感很強(qiáng)的組合。如果不想設(shè)計(jì) tab 圖標(biāo)直接純文字 tab 也是允許的少一套圖標(biāo)資源界面依然干凈。3.2 封裝 request 工具把 wx.request 變成 Promise原生wx.request是回調(diào)寫法每個(gè)頁(yè)面都寫 success/fail 會(huì)非常啰嗦。我一般會(huì)在utils/request.js里把它包成 Promise順帶統(tǒng)一處理 token 和錯(cuò)誤提示const BASE_URL http://localhost:8080; function request({ url, method GET, data {} }) { return new Promise((resolve, reject) { const token wx.getStorageSync(token); wx.request({ url: BASE_URL url, method, data, header: { Content-Type: application/json, Authorization: token ? Bearer ${token} : }, success(res) { if (res.statusCode 200 res.data.code 200) { resolve(res.data.data); } else if (res.statusCode 401) { wx.removeStorageSync(token); wx.navigateTo({ url: /pages/user/login }); reject(new Error(登錄過(guò)期)); } else { wx.showToast({ title: res.data.msg || 請(qǐng)求失敗, icon: none }); reject(new Error(res.data.msg)); } }, fail(err) { wx.showToast({ title: 網(wǎng)絡(luò)異常, icon: none }); reject(err); } }); }); } module.exports request;BASE_URL是后端服務(wù)地址本地開發(fā)用localhost:8080真機(jī)調(diào)試時(shí)改成電腦的局域網(wǎng) IP不然手機(jī)訪問(wèn)不到。Authorization字段是后端識(shí)別用戶身份的憑證token 在登錄成功后寫入本地緩存。401 表示登錄態(tài)失效直接清掉本地 token 跳登錄頁(yè)這是小程序里最常見的會(huì)話處理方式。后端返回的數(shù)據(jù)結(jié)構(gòu)約定為{ code, msg, data }code 200才走到成功分支這樣業(yè)務(wù)錯(cuò)誤和網(wǎng)絡(luò)錯(cuò)誤可以分開處理。3.3 菜譜列表頁(yè)下拉刷新、上拉加載、搜索一起做菜譜列表頁(yè)是本套源碼里最值得復(fù)用的頁(yè)面它同時(shí)涉及分頁(yè)、搜索、刷新三個(gè)高頻操作。核心邏輯放在fetchList方法里const request require(../../utils/request); Page({ data: { list: [], page: 1, size: 10, hasMore: true, keyword: }, onLoad() { this.fetchList(); }, onPullDownRefresh() { this.setData({ page: 1, hasMore: true, list: [] }); this.fetchList(() wx.stopPullDownRefresh()); }, onReachBottom() { if (this.data.hasMore) { this.setData({ page: this.data.page 1 }); this.fetchList(); } }, fetchList(callback) { request({ url: /api/recipe/list, data: { page: this.data.page, size: this.data.size, keyword: this.data.keyword } }).then((res) { const list this.data.page 1 ? res.records : this.data.list.concat(res.records); this.setData({ list, hasMore: this.data.page res.pages }); callback callback(); }); } });page和size是后端約定的分頁(yè)參數(shù)res.records和res.pages對(duì)應(yīng)后端 MyBatis-Plus 分頁(yè)返回的 JSON 字段。onReachBottom翻頁(yè)時(shí)用concat追加而不是替換避免用戶滾到下面內(nèi)容突然跳變。onPullDownRefresh重置分頁(yè)條件再重新拉第一頁(yè)這里必須調(diào)用wx.stopPullDownRefresh()關(guān)閉頂部刷新動(dòng)畫否則加載指示器會(huì)一直轉(zhuǎn)。搜索功能不單獨(dú)寫邏輯只是把keyword傳給后端由 Java 后端拼模糊查詢條件。頁(yè)面要支持下拉刷新還需要在pages/recipe/list.json里開啟{ usingComponents: {}, enablePullDownRefresh: true, backgroundTextStyle: dark }backgroundTextStyle只有dark和light兩個(gè)值控制下拉刷新時(shí)頂部小圓點(diǎn)的顏色深色背景配 dark 才看得清。4. Java 后端源碼與 MySQL 數(shù)據(jù)庫(kù)核心模塊怎么搭后端部分如果把每個(gè)類都過(guò)一遍很容易陷進(jìn)去。作為數(shù)據(jù)庫(kù)課程設(shè)計(jì)視角來(lái)看最先應(yīng)該看的是建表語(yǔ)句和三層結(jié)構(gòu)MySQL 里表怎么建Java 里 Controller、Service、Mapper 怎么分層微信登錄的 token 怎么簽發(fā)。4.1 建表recipe 和 comment 兩張核心表菜譜表是家庭大廚的心臟設(shè)計(jì)時(shí)要考慮后面查詢和擴(kuò)展CREATE TABLE recipe ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主鍵, title varchar(100) NOT NULL COMMENT 菜名, cover varchar(255) DEFAULT COMMENT 封面圖URL, category_id bigint DEFAULT NULL COMMENT 分類ID, ingredients text COMMENT 食材列表JSON數(shù)組, steps text COMMENT 步驟列表JSON數(shù)組, difficulty tinyint DEFAULT 1 COMMENT 難度1簡(jiǎn)單 2中等 3困難, view_count int DEFAULT 0 COMMENT 瀏覽量, user_id bigint DEFAULT NULL COMMENT 發(fā)布人ID, deleted tinyint DEFAULT 0 COMMENT 邏輯刪除0正常 1刪除, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 創(chuàng)建時(shí)間, PRIMARY KEY (id), KEY idx_category_id (category_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT菜譜表;ingredients和steps用 JSON 字符串存儲(chǔ)而不是拆成食材子表、步驟子表。原因是每道菜的食材數(shù)量和步驟數(shù)不固定拆表意味著每次查詢都要 JOIN 兩到三張表代碼量翻倍。用 JSON 存Java 后端讀出來(lái)用 Jackson 解析成 List小程序端拿到數(shù)組直接渲染簡(jiǎn)單直接。deleted字段對(duì)應(yīng) 2.2 節(jié)的邏輯刪除配置所有業(yè)務(wù)表都保留它。idx_category_id是分類查詢的索引沒有這個(gè)索引分類篩選會(huì)全表掃描。評(píng)論表比菜譜表簡(jiǎn)單得多CREATE TABLE comment ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主鍵, recipe_id bigint NOT NULL COMMENT 菜譜ID, user_id bigint NOT NULL COMMENT 評(píng)論用戶ID, content varchar(500) NOT NULL DEFAULT COMMENT 評(píng)論內(nèi)容, deleted tinyint DEFAULT 0 COMMENT 邏輯刪除, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 創(chuàng)建時(shí)間, PRIMARY KEY (id), KEY idx_recipe_id (recipe_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT評(píng)論表;注意這里沒有真正創(chuàng)建FOREIGN KEY外鍵約束只用普通索引關(guān)聯(lián)。這不是偷懶而是很多公司實(shí)際開發(fā)中默認(rèn)不用物理外鍵外鍵約束在刪除主表記錄時(shí)會(huì)阻止操作或級(jí)聯(lián)誤刪性能也有損耗。業(yè)務(wù)層面的關(guān)聯(lián)靠 Java 代碼維護(hù)這也是答辯時(shí)值得主動(dòng)講出來(lái)的一點(diǎn)。4.2 Controller-Service-Mapper以一個(gè)菜譜列表接口為例家庭大廚的后端三層結(jié)構(gòu)很標(biāo)準(zhǔn)。Controller 只負(fù)責(zé)接收參數(shù)和返回結(jié)果Service 寫業(yè)務(wù)邏輯Mapper 操作數(shù)據(jù)庫(kù)。以菜譜列表接口為例RestController RequestMapping(/api/recipe) public class RecipeController { Autowired private RecipeService recipeService; GetMapping(/list) public Result list(RequestParam(defaultValue 1) Integer page, RequestParam(defaultValue 10) Integer size, RequestParam(required false) String keyword, RequestParam(required false) Long categoryId) { LambdaQueryWrapperRecipe wrapper new LambdaQueryWrapper(); wrapper.like(StringUtils.hasText(keyword), Recipe::getTitle, keyword) .eq(categoryId ! null, Recipe::getCategoryId, categoryId) .orderByDesc(Recipe::getCreateTime); return Result.ok(recipeService.page(new Page(page, size), wrapper)); } }LambdaQueryWrapper是 MyBatis-Plus 的條件構(gòu)造器like第一個(gè)參數(shù)是布爾表達(dá)式為 false 時(shí)該條件不生效這樣搜索關(guān)鍵字為空時(shí)不會(huì)拼出多余的WHERE。.eq同理。Page對(duì)象封裝了當(dāng)前頁(yè)和每頁(yè)條數(shù)返回結(jié)果里自帶records、pages、total等字段正好對(duì)應(yīng) 3.3 節(jié)小程序端用到的字段名。Service 實(shí)現(xiàn)類里不寫復(fù)雜 SQL更多是簡(jiǎn)單的字段更新邏輯Service public class RecipeServiceImpl extends ServiceImplRecipeMapper, Recipe implements RecipeService { Override public void addViewCount(Long id) { Recipe recipe this.getById(id); if (recipe ! null) { recipe.setViewCount(recipe.getViewCount() 1); this.updateById(recipe); } } }getById和updateById都是 MyBatis-Plus 內(nèi)置方法updateById只更新非 null 字段不會(huì)把create_time等字段覆蓋掉。view_count瀏覽量在用戶打開詳情頁(yè)時(shí)調(diào)用一次雖然并發(fā)下會(huì)有精度損失但畢業(yè)設(shè)計(jì)這個(gè)量級(jí)完全夠用。如果老師追問(wèn)并發(fā)問(wèn)題可以說(shuō)生產(chǎn)環(huán)境會(huì)改用 Redis 計(jì)數(shù)再異步落庫(kù)這個(gè)回答可以體現(xiàn)知識(shí)面。4.3 wx.login 換 openid再簽發(fā)自己的 token微信登錄是這套畢設(shè)里最容易被追問(wèn)的環(huán)節(jié)。流程是小程序wx.login拿到臨時(shí)code傳給后端后端拿 code 去微信接口換openid再用自己的 token 機(jī)制給小程序發(fā)一張登錄憑證。Java 后端核心實(shí)現(xiàn)PostMapping(/login) public Result login(RequestBody MapString, String body) { String code body.get(code); String url https://api.weixin.qq.com/sns/jscode2session?appid appid secret secret js_code code grant_typeauthorization_code; String wxResponse restTemplate.getForObject(url, String.class); JSONObject jo JSON.parseObject(wxResponse); String openid jo.getString(openid); User user userMapper.selectByOpenid(openid); if (user null) { user new User(); user.setOpenid(openid); user.setNickname(微信用戶); userMapper.insert(user); } String token UUID.randomUUID().toString().replace(-, ); tokenStore.put(token, user.getId()); return Result.ok(token); }code是小程序wx.login返回的臨時(shí)憑證5 分鐘有效且只能使用一次所以小程序端要盡快把它發(fā)給后端。jscode2session接口返回openid和session_key其中openid是用戶在當(dāng)前小程序下的唯一標(biāo)識(shí)。第一次登錄的用戶自動(dòng)注冊(cè)后續(xù)每次登錄都復(fù)用同一條 user 記錄這樣就完成了“微信授權(quán)登錄”的最小實(shí)現(xiàn)。簽發(fā) token 之后后續(xù)請(qǐng)求通過(guò)攔截器從Authorization頭里解析出用戶 ID鑒權(quán)問(wèn)題閉環(huán)。這套源碼里如果配置了家庭成員的偏好比如口味選擇小程序端可以用radio-group收集單選項(xiàng)提交到后端的 profile 接口對(duì)應(yīng)一張user_profile表。這個(gè)功能雖然不大但數(shù)據(jù)表、接口、頁(yè)面三個(gè)維度都齊全很適合寫進(jìn)論文的功能模塊里。5. 部署、驗(yàn)證與答辯演示讓開源畢設(shè)源碼跑成作品源碼下載是一回事在自己電腦上跑起來(lái)是另一回事。這一步把環(huán)境錯(cuò)誤全部暴露出來(lái)也順便把使用說(shuō)明里描述不清的地方補(bǔ)齊。5.1 本地跑通的最小命令順序拿到源碼后按下面的順序操作每一步確認(rèn)通過(guò)再進(jìn)下一步# 第一步導(dǎo)入數(shù)據(jù)庫(kù) mysql -uroot -p family_chef docs/sql/family_chef.sql # 第二步啟動(dòng) Java 后端 cd family-chef-server mvn spring-boot:run # 第三步微信開發(fā)者工具導(dǎo)入 miniprogram 目錄數(shù)據(jù)庫(kù)導(dǎo)入失敗時(shí)先確認(rèn) MySQL 版本和 root 密碼application.yml里的password必須和本機(jī)一致。后端啟動(dòng)失敗時(shí)看控制臺(tái)第一行報(bào)錯(cuò)九成是端口被占用或者數(shù)據(jù)庫(kù)連接被拒。這一步涉及的 JDK 環(huán)境變量配置、Maven settings 鏡像都是在給后面的答辯排雷——環(huán)境越干凈演示越不容易翻車。5.2 真機(jī)預(yù)覽時(shí)的網(wǎng)絡(luò)邊界開發(fā)者工具里能通不代表手機(jī)能通。本地調(diào)試時(shí)在微信開發(fā)者工具的“詳情-本地設(shè)置”里勾選“不校驗(yàn)合法域名”才能訪問(wèn)http://localhost:8080。真機(jī)調(diào)試時(shí)把request.js里的BASE_URL從localhost改成電腦局域網(wǎng) IP兩者必須在同一個(gè) Wi-Fi 下。提示不校驗(yàn)合法域名只用于開發(fā)調(diào)試。小程序正式上線后端接口必須配置 HTTPS 域名并且把域名加入微信公眾平臺(tái)的服務(wù)器域名白名單。如果項(xiàng)目部署到了云服務(wù)器常見做法是用 Nginx 做反向代理把/api/前綴轉(zhuǎn)發(fā)到本機(jī)的 Java 服務(wù)server { listen 443 ssl; server_name api.familychef.example.com; location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }這段配置的意思是所有以/api/開頭的請(qǐng)求都轉(zhuǎn)發(fā)到本機(jī) 8080 端口小程序端只需要把BASE_URL改成https://api.familychef.example.com不需要關(guān)心后端跑在哪臺(tái)機(jī)器上。答辯現(xiàn)場(chǎng)如果網(wǎng)絡(luò)條件不允許真機(jī)演示可以提前錄一段演示視頻作為備份很多學(xué)校的答辯環(huán)境網(wǎng)絡(luò)受限這是最保險(xiǎn)的方案。5.3 答辯演示路線與高頻追問(wèn)演示不要從頭到尾把頁(yè)面點(diǎn)一遍要有側(cè)重。推薦按下面的順序走每個(gè)演示動(dòng)作背后都藏著一個(gè)技術(shù)知識(shí)點(diǎn)演示動(dòng)作演示內(nèi)容答辯可能追問(wèn)1. 微信登錄點(diǎn)擊登錄進(jìn)入首頁(yè)openid 怎么獲取token 過(guò)期怎么辦2. 搜索菜譜輸入關(guān)鍵字點(diǎn)搜索分頁(yè)參數(shù)怎么定的為什么用 JSON 存步驟3. 打開詳情并評(píng)論瀏覽詳情、寫一條評(píng)論評(píng)論表怎么設(shè)計(jì)刪除是物理刪除還是邏輯刪除4. 收藏操作點(diǎn)收藏再看收藏列表favorite 表怎么關(guān)聯(lián) recipe 和 user這些追問(wèn)基本和 Java 面試題、小程序八股高度重合答好一個(gè)模塊比背完整篇論文有用得多。演示后記得在開發(fā)者工具的 Network 面板里截圖一張 login 請(qǐng)求的響應(yīng)數(shù)據(jù)論文中放進(jìn)去能直觀展示“小程序-后端-數(shù)據(jù)庫(kù)”的完整鏈路已打通。本文還有配套的精品資源點(diǎn)擊獲取