校园美食推荐微信小程序毕设实战:云开发到部署上线全流程
发布时间:2026/9/10 19:26:55来源:尧图网络
每个学期一到毕设开题季校园类微信小程序就会成为计算机专业学生扎堆选择的方向。校园美食推荐小程序更是常年热门因为它场景足够真实功能模块清晰既能体现完整的前后端设计思路又不会复杂到让人半途放弃。这篇文章我想直接把这个项目从技术选型、数据库设计、核心代码到部署上线的全过程拆开揉碎讲一遍包括我带着学生做这类项目时踩过的坑和落地的细节。如果你正准备做小程序方向的毕设或者想做一个能真正跑起来的美食推荐产品这篇内容应该能帮你省掉一大半自己摸索的时间。这个项目的核心诉求很明确让在校师生快速找到想吃的、口碑好的美食。所以它不能只是一个简单的美食列表还需要具备用户登录、分类筛选、搜索、推荐、收藏、评价这些完整的功能闭环。从毕设答辩的角度看功能完整度、技术落地程度、数据建模合理性这三块是最容易被评委追问的。我下面的所有设计都是围绕这三点展开的。1. 项目整体设计与技术选型思路1.1 为什么校园美食场景天然适合小程序先聊聊场景本身。校园里的餐饮消费决策有几个特点高频、轻度、强地理位置关联、决策时间短。学生中午下课到食堂打饭从“不知道吃什么”到“决定吃什么”往往只有几分钟。这种场景下用户不愿意下载一个App也不愿意打开浏览器搜索最顺手的方式就是打开微信里的一个小程序。另外一个很现实的原因是微信小程序对毕设来说几乎是性价比最高的技术载体。它不需要做安卓和iOS两套不需要处理复杂的应用商店上架流程小程序审核周期相对可控而且开发者工具里自带模拟器、调试器、云开发环境一个人就能完成从前端到后端的全部工作。对毕设来说这意味着一套代码就能搞定所有交付物。1.2 技术方案对比原生小程序云开发 vs 传统前后端分离很多人在选题后会纠结技术栈。我直接给结论做这类校园美食小程序首选原生微信小程序 微信云开发。这不是因为我不会Spring Boot而是这个方案对毕设场景来说综合成本最低、最不容易在中途卡住。对比维度原生小程序 云开发传统前后端分离服务器成本云开发自带免费额度基本够用需要自己购买云服务器或本地部署域名与HTTPS云开发自动处理无需备案和配置证书小程序要求HTTPS正式域名需要备案后端开发量云函数直接写Node.js无需单独搭服务需要完整写Controller/Service/DAO上线难度云开发环境开通后自动同步需要单独部署后端并保证公网可访问答辩展示云函数前端一套代码即可完整演示需要同时展示后端接口文档和数据库我用“合适度”来排序的话云开发方案在毕设场景下能覆盖90%以上的需求。唯一的短板是它不够“传统”——有些评委老师会期待看到你写了RESTful API、用了JWT鉴权、设计了MySQL表。这个问题的解法我后面会说就是在云函数里用规范的接口分层写法并且在数据库设计阶段把关系型建模的思维体现出来答辩时一样能讲得很清楚。2. 从零搭建开发环境与项目骨架2.1 注册小程序账号与安装开发者工具这一步看起来基础但每年都有学生在这里卡住因为AppID和云开发环境的配对关系没搞清楚。我用的是步骤化流程先到微信公众平台注册一个小程序账号。注意这里选的主体类型个人主体和高校主体都行个人主体能用的接口权限少一点但做校园美食推荐小程序完全够用。注册时选择“小程序”不要选“订阅号”或“服务号”填完邮箱、激活、登记信息之后在后台的“开发管理-开发设置”里能看到自己的AppID。然后下载微信开发者工具安装时选择稳定版不要选Beta版。这个工具有个容易忽略的点首次启动会让你扫码登录你必须用注册小程序账号的微信扫码否则后面没法在工具里绑定这个AppID。我见过有人用别人的工具账号导入项目结果AppID对不上云开发环境也打不开折腾了两个小时才发现是登录身份的问题。安装好后在工具里选择“小程序-导入项目”把AppID填进去选择不使用模板直接创建一个空项目。这个过程中如果提示“未绑定开发者”去小程序后台的“成员管理”里把你的微信号添加为项目成员即可。2.2 开通云开发并创建云环境空项目创建完成后工具栏上方会有一个“云开发”按钮点进去选择开通云开发。这里系统会让你创建环境环境名称建议直接用字符串比如“food-dev”不要带中文。云开发环境创建后会自动生成环境ID后面所有云函数、数据库、存储都挂在这个环境底下。这个步骤里有三个容易踩的坑我提前说一下第一每个小程序账号默认有免费的基础额度但环境数量有限一般是一个环境就够用不要反复创建环境。第二云开发控制台里有“环境设置”需要把默认的“所有用户可读”改成更合理的权限这个我在数据库设计部分展开讲。第三项目里如果只是前端调用云数据库不需要配置任何域名白名单如果以后接了自己的后端API才需要去小程序后台配置request合法域名。初始化云环境的代码写在app.js里App({ onLaunch: function () { if (!wx.cloud) { console.error(请使用 2.2.3 或以上的基础库以使用云能力) } else { wx.cloud.init({ env: food-dev, traceUser: true }) } }, globalData: { userInfo: null, openid: } })这里的关键点是traceUser: true这个字段会把用户访问记录写入云开发控制台的用户管理列表方便后续做用户维度的数据分析。调试时如果发现云函数调用报错找不到环境八成是这里的env值和你实际创建的环境ID不一致。2.3 项目目录结构与全局配置文件项目骨架我习惯这样组织模块清晰后期扩展也方便├── app.js // 全局初始化云开发配置 ├── app.json // 全局配置页面路由、窗口样式 ├── app.wxss // 全局公共样式 ├── pages/ │ ├── index/ // 首页推荐美食列表 │ ├── category/ // 分类页按菜系/食堂筛选 │ ├── search/ // 搜索页 │ ├── detail/ // 美食详情页 │ ├── profile/ // 个人中心收藏与评价管理 │ └── login/ // 登录与用户授权页 ├── components/ │ ├── food-card/ // 美食卡片组件列表页复用 │ └── rating-star/ // 评分星级组件 ├── cloudfunctions/ │ ├── login/ // 获取openid并维护用户表 │ ├── getRecommendList/ // 获取推荐列表 │ ├── getFoodDetail/ // 获取指定美食详情 │ ├── addFavorite/ // 收藏 │ ├── getFavorites/ // 获取收藏列表 │ ├── addComment/ // 添加评价 │ └── getComments/ // 获取评价列表 └── images/ // 静态图片资源app.json是全局配置的核心文件这里有几个配置项需要特别说明{ pages: [ pages/index/index, pages/category/category, pages/search/search, pages/detail/detail, pages/profile/profile, pages/login/login ], window: { navigationBarBackgroundColor: #ff6b35, navigationBarTitleText: 校园美食, navigationBarTextStyle: white, backgroundColor: #f5f5f5 }, permission: { scope.userLocation: { desc: 你的位置信息将用于美食推荐排序 } }, style: v2, sitemapLocation: sitemap.json }这里的permission.scope.userLocation一定要配置因为要做距离排序和附近美食推荐肯定要获取用户位置。如果你不配这段后面调用wx.getLocation会直接报错。另外style: v2表示启用新版组件样式这个会让button、switch这些基础组件的外观看上去更现代不用自己手写一堆兼容样式。3. 核心功能模块设计与实现3.1 用户登录与身份绑定先捋清微信小程序登录的完整逻辑这块是毕设答辩时的高频问题。用户打开小程序后前端调用wx.login()拿到一个临时凭证code这个code的有效期大约5分钟。然后把code传给后端后端拿到code去微信的接口换取openid和session_key。openid是用户在当前小程序下的唯一标识session_key则用于后续解密用户信息。在云开发方案里这个过程被大大简化了。你不需要自己去请求微信的接口云函数里可以直接通过cloud.getWXContext()拿到当前调用者的OPENID。所以登录云函数的核心逻辑就变成了const cloud require(wx-server-sdk) cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) const db cloud.database() exports.main async (event, context) { const wxContext cloud.getWXContext() const openid wxContext.OPENID const users db.collection(users) // 检查用户是否已存在 const existed await users.where({ openid }).get() if (existed.data.length 0) { await users.add({ data: { openid, nickname: , avatarUrl: , createdAt: db.serverDate() } }) } return { openid } }前端登录页的逻辑就是在onLoad里调用这个云函数拿到openid后存到globalData里同时尝试获取用户的头像和昵称。这里要特别提醒一点小程序早期版本用wx.getUserProfile就能弹出授权窗口获取头像昵称但后来微信调整了策略这个接口已经不能直接用了。现在的方案是用button的open-typechooseAvatar来获取头像用input的typenickname来获取昵称。这段代码是登录页的典型实现view classlogin-container button classavatar-wrapper open-typechooseAvatar bind:chooseavataronChooseAvatar image classavatar src{{avatarUrl}} modeaspectFill/image /button input typenickname classnickname-input placeholder请输入昵称 bind:bluronNicknameInput/ button classlogin-btn bindtaponLogin授权登录/button /viewPage({ data: { avatarUrl: /images/default-avatar.png, nickname: , canLogin: false }, onChooseAvatar(e) { this.setData({ avatarUrl: e.detail.avatarUrl }) }, onNicknameInput(e) { this.setData({ nickname: e.detail.value }) }, async onLogin() { const openid await getOpenid() const user await getUserByOpenid(openid) // 更新用户表的昵称和头像 await updateUserInfo(openid, { nickname: this.data.nickname, avatarUrl: this.data.avatarUrl }) wx.setStorageSync(userInfo, { openid, nickname: this.data.nickname, avatarUrl: this.data.avatarUrl }) wx.switchTab({ url: /pages/index/index }) } })毕设答辩时关于登录这块老师必问的一个问题是“openid和session_key的区别是什么”。你要能答出来openid是用户的唯一标识相当于身份证号同一个用户在不同小程序下的openid不同session_key是会话密钥用于解密微信返回的敏感数据有效期随登录态变化。这两个概念搞清楚了登录部分就不会被问倒。3.2 美食信息流展示与分类筛选首页是这个小程序的门面也是用户停留时间最长的页面。我做这个项目时首页采用了“顶部轮播图分类快捷入口推荐美食列表”三段式布局。轮播图用于展示校园美食节、食堂新菜品等运营位信息。分类快捷入口则是一组固定图标包括“食堂精选”“川湘风味”“面食烘焙”“轻食简餐”“奶茶饮品”等分类。用户点击某个分类后会跳转到分类页面并自动带上对应的分类参数。美食信息流是首页的主体采用纵向卡片列表每个卡片展示菜品图片、名称、所属食堂窗口、评分、价格、标签比如“微辣”“量大实惠”和收藏按钮。这里我用了一个自定义组件food-card这样分类页、搜索结果页都能复用同一个卡片组件避免重复代码。分类筛选的实现思路是这样的每个美食文档里都存一个category字段和tags数组前端在分类页点击某个分类时把分类名传给数据获取函数在数据库查询时做精确匹配async function getFoodsByCategory(category) { const db wx.cloud.database() const foods db.collection(foods) const res await foods.where({ category }).get() return res.data }如果数据量超过20条云数据库的默认查询限制会让你只取到前面一部分记录。这时候有两种处理方式一是用.limit(20).skip(20)做分页简单粗暴二是用.count()先取总数再通过循环把所有数据拉下来。这里我建议用分页的写法而且在小程序端的onReachBottom事件里做触底加载体验更好。3.3 搜索功能与推荐算法的落地搜索功能是另一个容易被问到“为什么这样实现”的模块。我对接的是数据库的RegExp查询用户在搜索框输入关键词后小程序端直接调用云数据库用正则匹配菜品名称和所属食堂名称。getFoodsByKeyword的实现大概是这样async function searchFoods(keyword) { const db wx.cloud.database() const _ db.command const foods db.collection(foods) const reg db.RegExp({ regexp: keyword, options: i }) const res await foods .where(_.or([{ name: reg }, { canteen: reg }])) .get() return res.data }这种方式在数据量不大时完全够用而且代码量极少。当然你也可以选用云函数配合db.command的search能力但那是基于数据库索引的全文检索对学生项目来说杀鸡用牛刀了。接下来是推荐算法的设计。很多人看到“推荐”两个字会觉得要上机器学习其实校园场景下有一个更务实、更容易讲清楚的思路我称之为“标签匹配热度加权”的混合推荐。具体的流程是维护每个美食的标签比如“川菜”“不辣”“高性价比”“适合自习后补充能量”用户的偏好标签从两个地方获取一是用户在个人中心主动选择的兴趣标签二是用户的历史收藏和评价中美食标签的聚合计算候选美食与用户偏好的匹配度公式为匹配度 命中的标签数量 / 美食标签总数再乘以一个热度系数热度系数 0.6 * 平均评分 0.3 * 评论数归一化 0.1 * 距离因子这里的距离因子就用到用户的地理位置了。前端通过wx.getLocation拿到用户经纬度与美食所属食堂窗口的经纬度计算距离用类似下面的函数做简单的球面距离计算function getDistance(lat1, lng1, lat2, lng2) { const radLat1 (lat1 * Math.PI) / 180 const radLat2 (lat2 * Math.PI) / 180 const a radLat1 - radLat2 const b ((lng1 - lng2) * Math.PI) / 180 const s 2 * Math.asin( Math.sqrt( Math.pow(Math.sin(a / 2), 2) Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2) ) ) return s * 6371 * 1000 // 单位米 }推荐列表的最终排序分数就好算多了const rankScore tagMatchScore * 0.5 ratingScore * 0.3 commentCountScore * 0.15 distanceScore * 0.05然后按分数从高到低取前20条作为首页推荐列表。这个算法虽然简单但它是可解释的答辩时能讲清楚每一个权重的含义也能说明为什么这样设计。对于毕设来说“讲得明白”比“算法复杂”重要得多。3.4 收藏、评价与个人中心收藏和评价是用户UGC的两个最基础功能也直接关联到推荐算法的数据来源。收藏这个动作在美食卡片和详情页都有入口点击收藏按钮时调用addFavorite云函数把openid、foodId和当前时间写入favorites集合。如果用户已经收藏了同一个美食就提醒“已经收藏过了”避免重复数据。评价功能放在美食详情页底部用户可以选择评分1-5星填写评论内容同时可以给美食打标签。这里有一个交互细节评分组件用了自定义的rating-star组件而不是直接用微信的slider因为星级评分对美食场景来说更加直观也好看。个人中心页面把用户收藏列表、发表过的评价、授权信息统一管理起来。收藏列表是一个典型的列表页从favorites集合中查出当前用户的收藏记录再根据foodId联查美食详情。云开发里没有数据库外键的概念联查是手动做的const favoriteRes await favorites.where({ openid }).get() const foodIds favoriteRes.data.map(item item.foodId) const foodsRes await db.collection(foods) .where({ _id: _.in(foodIds) }) .get()注意这里in操作符一次最多支持100条数据如果用户收藏超过100个不太可能但也不是不可能就需要做分批查询。这个细节在答辩时如果被问到你能脱口说出来老师会认为你真的动手做了。4. 数据库设计与云函数封装4.1 数据集合结构与权限控制云开发数据库是文档型的用集合组织数据。这个项目的集合设计我列一下foods集合字段名类型说明_idstring自动生成菜品唯一标识namestring菜品名称categorystring分类如“食堂精选”tagsarray标签数组如[川菜, 微辣]pricenumber价格单位元ratingnumber平均评分0-5commentCountnumber评论数imagestring菜品图片的云存储fileIDcanteenstring所属食堂或窗口名称locationobject食堂经纬度如{lat, lng}users集合字段为openid、nickname、avatarUrl、preferredTags用户主动选择的兴趣标签、createdAt。favorites集合字段为userId用openid、foodId、createTime。这里给userId和foodId建了索引方便按用户查询和检查重复。comments集合字段为userId、foodId、content、rating、tags用户打的美食标签、createTime。权限控制是云开发被问烂了但也是最容易出错的地方。打开云开发控制台进入数据库对每个集合设置权限规则。我的设置方式是foods所有用户可读仅管理端可写通过云函数写云函数默认有管理员权限不受权限规则限制users仅创建者可读写字段匹配openidfavorites仅创建者可读写comments所有用户可读仅创建者可写在小程序端直接调用数据库时权限规则会拦截不符合条件的读写操作。比如一个用户如果通过前端直接修改users集合里另一条记录会被拒绝。这里的关键点是云函数拥有管理端权限绕过这些规则。所以凡是要写数据的操作我都建议走云函数一是为了权限安全二是可以统一做参数校验。4.2 云函数的正确打开方式云函数的目录结构、部署方式和调用方式需要说清楚。在微信开发者工具中cloudfunctions目录下的每个子目录是一个独立的云函数右键点击该目录选择“创建并部署云端安装依赖”工具会自动把云函数上传到云端并安装依赖。云函数内部用一个exports.main入口函数接收event参数。前端调用云函数时通过wx.cloud.callFunction({ name: xxx, data: {...} })来传参。我把这个项目的云函数做了分层让代码不只是一个裸的请求处理而是有“路由”的感觉exports.main async (event, context) { const { action, data } event switch (action) { case ADD: return await addFavorite(data) case LIST: return await getFavorites(data) case REMOVE: return await removeFavorite(data) default: return { code: -1, msg: 未知操作 } } }这种写法最大的好处是一个功能模块的多个数据库操作可以收敛到一个云函数里不用为每个增删改查单独建一个云函数。不然光收藏功能就要建addFavorite、removeFavorite、getFavorites、checkFavorite四个函数管理起来很累。在云函数里要注意错误处理。一个常见的坑是如果云函数内部抛出异常前端拿到的结果可能是errMsg而不是你想返回的数据。所以每个云函数我都习惯用try-catch包起来并且统一返回格式try { const data await doSomething() return { code: 0, data } } catch (err) { console.error(err) return { code: -1, msg: err.message } }前端在调用云函数时只用判断result.code 0就行这样整个项目的数据交互风格是一致的可读性也好。4.3 一个完整的云函数最佳实践获取推荐列表getRecommendList是这个项目里最综合的云函数我从设计到编码完整讲一遍。这个云函数接收用户偏好标签、经纬度、分页参数返回按推荐分数排好序的美食列表const cloud require(wx-server-sdk) cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) const db cloud.database() const _ db.command function calcScore(food, userTags, location) { let tagMatch 0 if (userTags.length 0) { const matched food.tags.filter(tag userTags.includes(tag)) tagMatch matched.length / food.tags.length } const ratingScore food.rating / 5 const commentScore Math.min(food.commentCount / 50, 1) // 50条评论算满分热度 let distanceScore 1 if (location) { const dist getDistance(location.lat, location.lng, food.location.lat, food.location.lng) distanceScore Math.max(0, 1 - dist / 2000) // 2公里内有效 } return tagMatch * 0.5 ratingScore * 0.3 commentScore * 0.15 distanceScore * 0.05 } exports.main async (event) { const { userTags [], location null, page 1, pageSize 10 } event const wxContext cloud.getWXContext() const openid wxContext.OPENID const foods await db.collection(foods) .skip((page - 1) * pageSize) .limit(pageSize) .get() const ranked foods.data .map(food ({ ...food, score: calcScore(food, userTags, location) })) .sort((a, b) b.score - a.score) // 记录用户本次浏览行为用于后续偏好标签聚合 await db.collection(user_behavior).add({ data: { openid, action: getRecommend, timestamp: db.serverDate() } }) return { code: 0, data: ranked } }这个云函数里我刻意加了一个行为埋点把用户每次获取推荐列表的行为记录下来。好处是后续可以在管理端基于这些日志做简单的用户画像分析也可以作为毕设论文里“数据采集与用户建模”章节的素材。一个数据埋点的设计往往能让论文和答辩的深度提升一个档次。5. 部署上线流程与常见问题排查5.1 从模拟器到真机预览的关键步骤项目在开发者工具里跑通后不要急着提审先做真机预览。点击工具栏的“预览”按钮会生成一个二维码微信扫码后就可以在手机上体验。真机预览最常见的问题是“数据加载失败”。原因通常是模拟器里能正常访问云开发环境但真机上小程序的基础库版本和模拟器不一致或者云开发环境没有正确初始化。这里我给一个排查套路第一检查app.js里的env环境ID是否和云开发控制台一致。第二检查手机微信版本和基础库版本如果太久需要升级微信。第三在云开发控制台里看云函数调用日志确认是不是云函数本身的报错。另一个真机特有的问题是位置权限。模拟器里wx.getLocation会自动弹窗真机上则需要用户在小程序设置里手动开启位置权限。如果用户拒绝了授权小程序再次调用getLocation会直接失败。我的处理方式是先调用wx.getSetting检查权限状态如果已经被拒绝引导用户去设置页重新开启wx.getSetting({ success(res) { if (!res.authSetting[scope.userLocation]) { wx.showModal({ title: 需要位置权限, content: 请在设置中开启位置权限以便为你推荐附近的校园美食, success(modalRes) { if (modalRes.confirm) { wx.openSetting() } } }) } } })5.2 上传代码与提交审核真机体验没问题后点开发者工具右上角的“上传”按钮设置版本号和备注。上传完成后登录微信公众平台在“版本管理-开发版本”里找到你上传的版本点击提交审核。提交审核时有一个很容易被忽略的问题类目选择和隐私保护指引。小程序发布时要求选择类目校园美食推荐建议选“生活服务-餐饮”或“美食”类目。隐私保护指引里需要声明你收集了用户信息头像、昵称和位置信息如果不声明审核时会被打回而且还会导致部分接口无法调用。审核期间可以顺便把小程序的头像、名称、简介、服务范围这些基础信息完善一下。名称最好带上“校园”和“美食”关键词这样用户搜索时更容易找到。简介里写清楚这个小程序能做什么比如“校园食堂美食推荐、搜索、收藏与评价”。从提交审核到审核通过一般需要1-3个工作日。如果被打回最常见的理由是“类目选择不正确”或“页面功能与描述不符”。前者去调整类目后者检查一下页面里有没有未实现的功能入口有的话先隐藏等审核通过后再开放。5.3 高频报错与解决方案速查表我把做这个项目时遇到的高频问题整理成了一张速查表每个问题都附了排查思路和解决办法报错或现象原因解决方案云函数调用失败FunctionName not found云函数未部署或部署时选了“不上传配置”右键云函数目录选择“云端安装依赖并部署”数据库读取返回空数组集合权限设置为“仅创建者可读”在云开发控制台把“所有用户可读”权限开启或走云函数读取wx.getLocation 报错auth deny用户拒绝了位置授权检测授权状态并引导用户去设置页开启图片上传成功但页面显示不出来数据库中存的fileID没有转成临时链接组件里用cloud://开头的fileID或调用getTempFileURL转链接登录后获取用户信息失败wx.getUserProfile已被废弃改用头像昵称填写能力即open-typechooseAvatar和input typenickname真机预览白屏基础库版本过低或env配置错误更新微信版本检查app.js中wx.cloud.init的env参数提交审核被拒提示隐私接口未声明未填写隐私保护指引到小程序后台的“设置-服务内容声明-用户隐私保护指引”里补充推荐排序不合理没有位置信息或权重偏高检查是否传入了location参数调整权重系数下拉刷新数据不变化页面没有监听下拉刷新事件在页面的onPullDownRefresh里重新请求数据并调用wx.stopPullDownRefresh这张表里的问题我基本都实际遇到过。尤其想提一下图片链接的问题这是新手最容易懵的点。云存储里的文件默认是没有公网访问权限的你在云数据库里存的是文件的fileID类似cloud://env-id.xxx/xxx.jpg如果在image组件的src里直接填这条路有时候能显示有时候不能。稳妥的做法是上传图片后用wx.cloud.getTempFileURL换取一个临时HTTPS链接再存到数据库里临时链接有效期一般是一天。6. 项目复盘与一些个人经验整个项目做完我最大的感受是这种中小型校园类小程序最适合用“小而美”的方式来做。功能不在多而在于每条链路都能通。很多学生做毕设喜欢把功能列得特别满但最终能演示的也就首页和列表页。做美食推荐小程序你宁可只做首页展示、详情、搜索、收藏、评价这五个核心模块也要确保每一个都可以从首页一路点到底中间不报错、不白屏、数据是通的。这比堆二十个半成品功能要好得多。关于源码组织我建议从头到尾统一用云函数加前端分离的思路不要混用“前端直连数据库”和“云函数操作数据库”两种方式。混用的后果是权限规则非常难配而且答辩时讲到数据流会把自己绕晕。我自己的经验是读操作如果简单可以用前端直连数据库比如拉取美食列表但写操作一律走云函数这样安全、可控日志也好查。部署文档方面我给自己的项目整理了一份标准流程文档包括从注册小程序账号开始的所有步骤、云开发环境开通方式、数据库集合创建命令、云函数部署操作、真机调试注意事项、审核提交流程每一章节都配了截图。这个文档在毕设论文里可以直接作为“运行环境与部署说明”一章的素材同时也可以放进项目压缩包让老师按照文档步骤快速在本地把项目跑起来。最后再说一个很多人忽略的细节小程序项目的版本管理。我建议从第一天起就用Git做版本管理每次完成一个功能就提交一次写上清晰的commit信息比如“feat: 完成收藏功能”。这样做有两个好处一是如果改坏了某个功能可以随时回滚二是答辩前生成一份开发记录你可以在论文里把开发过程写得非常详实每一个功能模块是什么时候设计、什么时候实现、中间遇到什么问题、怎么解决的都有据可查。这比答辩现场被问到“你开发用了多久、每天都做了什么”时支支吾吾要强太多了。如果你真正动手做这个项目我建议每一步都亲手敲一遍不要直接复制别人的完整源码。云开发和微信小程序的知识密度不算高但细节特别多动手一次踩过坑比看十篇教程都管用。做完了之后把项目文档和代码整理好就是你简历上可以放心写的一笔。
网站建设高端定制企业官网