毕业设计这东西每年选题都像在开盲盒。市面上那些库存管理系统、商城系统早就被做烂了你答辩时老师看一眼题目就知道你用了什么模板。相比之下“留守宠物喂养管理系统”是这几年我一直推荐给学生的选题需求真实存在、功能边界清晰、技术栈覆盖全面而且做出来之后是真的能拿去用的东西。先说一下这个系统到底解决了什么问题。养猫养狗的人出差、回老家、临时加班宠物没法带在身边放在宠物店寄养不仅贵还得担心宠物应激反应。所以一个能远程查看宠物状态、按计划定时喂食、记录进食情况的微信小程序就成了刚需。这个项目恰好卡在了一个非常合适的位置微信小程序做前端后端用Java或者Node.js都行数据用MySQL存再加上硬件侧的定时喂食器如果要做硬件联动的话整个链路做下来一个完整的毕设项目闭环就有了。我之前带过几个学生做这个方向今天就把整个项目的设计思路、关键代码、踩坑记录全部分享出来。1. 项目定位与整体设计思路1.1 为什么选微信小程序而不是App这可能是你要做的第一个决定。我的建议非常直接选微信小程序别犹豫。从用户角度看微信小程序的打开成本几乎为零。用户不会为了喂个猫专门去应用商店下载一个App但他们会为了等外卖顺手在微信里搜一下小程序。从开发角度看小程序前端上手门槛低WXML和WXSS的语法接近HTML和CSS只要是写过网页的人都能快速进入状态。再加上微信自带的登录体系和消息推送机制省掉了自己搭用户系统和短信服务的麻烦。从毕设评审的角度看微信小程序这个关键词本身就带着关注度。答辩老师看到你做的是小程序第一反应是“这学生跟得上技术趋势”而不是“又是传统Web那套”。1.2 功能模块拆解需求从哪来做毕设最容易犯的错就是一上来就写代码。正确做法是先画清楚功能边界。我当时给学生的建议是分四个核心模块宠物档案模块添加、编辑、删除宠物信息名字、品种、年龄、体重、饮食习惯备注喂食计划模块设定每日喂食时间、单次出粮量、喂食器状态反馈监控与记录模块查看宠物的进食记录、可选视频画面或摄像头抓拍个人中心模块用户登录、设备绑定、消息通知设置这四个模块覆盖了从“创建宠物信息”到“查看喂食结果”的完整闭环。每一块拿出来都能在文档里写出一章加起来内容量足够撑起一篇合格的毕业论文。1.3 技术选型的底层逻辑整个项目的主流技术栈是这个组合层级技术选型选择理由前端微信小程序原生或uni-app原生语法稳定、调试方便uni-app可兼顾多端后端Spring BootJava生态成熟毕业答辩被追问的概率低数据库MySQL关系型数据库的经典选择表结构设计好讲接口协议RESTful API JSON前后端分离的标准姿势硬件联动ESP8266/ESP32可选如果做硬件方向这是最便宜的方案后端我推荐Spring Boot是有私心的。不是因为Java性能多好而是因为答辩时老师大概率会问“为什么选这个框架”“Spring的IoC和AOP怎么体现的”你用Spring Boot可以很自然地引出依赖注入、自动配置这些知识点回答起来有东西可说。如果你更熟Node.js改成Express或Egg也没问题关键是自己弄得明白。2. 数据库设计与接口规范2.1 表结构怎么设计才合理这套系统的表结构比一般的商城系统要简单但有几张表的设计直接决定了后面功能好不好扩展。我建议核心表设计如下用户表useropenid是微信小程序的唯一身份标识必须加唯一索引。nickname、avatar_url用于展示个人资料绑定设备编号字段可空方便后面做设备解绑再绑定。宠物表petuser_id关联用户表pet_name、pet_type猫/狗、pet_weight、breed、birthday用于档案展示feeding_note是自由文本字段存“猫粮过敏”“每天加一次化毛膏”这类备注。喂食计划表feeding_plan计划创建时一次性生成未来N天的计划记录或者只在用户编辑时更新当天及之后的记录。每条记录包含计划时间、出粮克数、状态字段待执行、已执行、已跳过状态由后端定时任务更新。喂食记录表feeding_record设备上报喂食完成后写入一条记录包含实际喂食时间、出粮克数、剩余粮量、执行来源自动/手动。这张表的粒度决定了你之后能做多细的统计。设备表devicedevice_id作为物理设备的唯一标识status字段表示在线/离线last_online_time用于展示设备状态。如果你不做硬件这表可以简化成用户直接维护一个“喂食器状态”。2.2 接口怎么设计才清晰接口设计遵循一个原则让前端调用起来不用想太多。以下是核心接口清单POST /api/user/login小程序wx.login获取code后端用code换取openid首次登录自动注册GET /api/pet/list获取当前用户的宠物列表POST /api/pet/add新增宠物资料PUT /api/pet/update修改宠物资料DELETE /api/pet/delete删除宠物GET /api/plan/list?petIdxxxdatexxx按日期获取喂食计划POST /api/plan/save创建或修改喂食计划POST /api/plan/execute手动触发一次喂食GET /api/record/list?petIdxxxpageNum1pageSize10分页查询喂食记录GET /api/device/status获取绑定设备状态注意接口命名要语义化参数要校验响应格式保持统一。我习惯统一返回Result对象包含code200成功500失败、message和data三个字段。这样前端处理异常就只需要判断code省心很多。3. 微信小程序前端实现的核心细节3.1 登录流程别再用老一套了现在很多教程还在让你用wx.getUserInfo去拿用户头像昵称这已经行不通了。微信官方早就调整了规则 getUserInfo弹窗被砍掉现在是默认获取灰色头像和“微信用户”昵称。正确的做法是// app.js 中封装登录逻辑 const login () { wx.login({ success: (res) { if (res.code) { // 将code发送到后端后端通过code换openid wx.request({ url: http://localhost:8080/api/user/login, method: POST, data: { code: res.code }, success: (response) { const { token, userId } response.data.data wx.setStorageSync(token, token) wx.setStorageSync(userId, userId) } }) } } }) }用户头像和昵称要单独引导用户去完善点击头像时弹出wx.chooseMedia选择图片上传到自己的对象存储再把URL存到数据库。这也是一个可以写进文档的细节为什么不能用open-typegetUserInfo直接拿头像因为隐私协议收紧后很少会有用户愿意授权。3.2 定时任务的“坑”与解决方案这里说一个小程序端的经典坑。很多学生会想用小程序的定时器setInterval去定时触发喂食但这在微信小程序里根本不靠谱小程序在后台时定时器会被挂起。你的宠物喂食计划必须由后端执行。后端的定时任务方案也很简单在Spring Boot里用Scheduled注解Component public class FeedingTask { Autowired private FeedingPlanMapper planMapper; Autowired private FeedingRecordMapper recordMapper; // 每分钟执行一次检查是否有需要执行的喂食计划 Scheduled(cron 0 * * * * ?) public void checkPlans() { ListFeedingPlan plans planMapper.selectByStatusAndTime( WAITING, DateUtil.format(new Date(), yyyy-MM-dd HH:mm) ); for (FeedingPlan plan : plans) { // 发送HTTP请求到喂食器端 DeviceResponse resp deviceClient.executeFeed(plan.getDeviceId(), plan.getFeedAmount()); if (resp.isSuccess()) { plan.setStatus(EXECUTED); // 记录喂食信息 recordMapper.insert(...); } else { plan.setStatus(FAILED); // 发送告警通知给用户 wxMessageService.send(plan.getUserId(), 喂食失败请检查设备); } planMapper.updateById(plan); } } }这个定时任务的粒度设置为“每分钟检查一次”相比每秒轮询大大降低了对数据库的压力。计划表里的执行时间精确到分钟就足够了。3.3 前端页面开发顺序建议页面开发顺序直接决定了效率。我的建议按这个顺序来先做宠物列表页这是用户进入小程序后的首页需要显示宠物卡片头像、名字、品种、体重和“添加宠物”按钮。接着做宠物档案编辑页把表单组件调稳定了后面套用别的表单就顺畅了。然后做喂食计划页这是整个系统的核心功能页。这里有个设计要点喂食计划的展示建议按周视图排布周一到周日每天可以单独设置喂食时间。用表格布局做这个比时间轴更清晰。最后做动静分离的页面喂食记录列表用滚动列表每行显示时间和出粮克数我的页面用普通卡片布局放设置入口、设备绑定、关于页面。3.4 网络请求封装原生小程序请求有点繁琐建议封装一个request工具// utils/request.js const request (url, method, data) { return new Promise((resolve, reject) { wx.request({ url: https://your-api-server.com${url}, method, data, header: { Content-Type: application/json, Authorization: Bearer ${wx.getStorageSync(token)} }, success: (res) { if (res.data.code 200) { resolve(res.data.data) } else { wx.showToast({ title: res.data.message, icon: none }) reject(res.data) } }, fail: (err) { // 网络异常时的统一处理 wx.showToast({ title: 网络连接失败, icon: none }) reject(err) } }) }) }别小看这个封装它会让你的页面代码干净得多。每个页面里只需要写const list await request(/api/pet/list, GET) setData({ petList: list })而不是每次都去写一遍wx.request的回调、错误处理和loading状态。4. 后端关键逻辑与硬件联调可选方案4.1 用户认证的完整链路微信小程序后端的用户认证流程是固定套路前端调用wx.login拿到临时凭证code前端把code传给后端后端通过HTTPS请求微信接口https://api.weixin.qq.com/sns/jscode2session带上appid、secret和code微信返回openid和session_key后端查数据库有则更新登录信息无则注册新用户后端生成自定义token可以用jwt或session返回给前端这里要注意的坑是appid和secret绝对不能写到前端代码里否则任何人反编译小程序都能拿到你的secret理论上可以冒充你的小程序做坏事。正确做法是通过后端转发由后端来存secret。4.2 硬件联调的最后一步串口通信能不做就不做如果你选择做“硬件联动”最省心的方式是买一个带WiFi的智能喂食器市场价大约100到200元通过它的开放API接口对接你的后端而不是自己去写ESP8266的固件做串口通信。原因很现实纯软件方向的学生搞单片机要看很多焊接和电烙铁知识纯硬件方向的学生又会卡在后端接口上。用现成的智能喂食器把对接的重点放在“你的后端如何通过HTTP请求操作设备”一样可以讲清楚整个物联网闭环而且精力能集中在毕业设计真正考核的软件工程能力上。如果你一定要自己用ESP8266做硬件联调时的关键代码大致是这样的思路#include ESP8266WiFi.h #include HTTPClient.h void setup() { WiFi.begin(your-wifi-ssid, your-wifi-password); while (WiFi.status() ! WL_CONNECTED) { delay(500); } // 每10秒轮询一次后端查询是否有新的执行指令 } void loop() { if (WiFi.status() WL_CONNECTED) { HTTPClient http; http.begin(http://your-server.com/api/device/command); int httpCode http.GET(); if (httpCode 0) { String payload http.getString(); // 解析指令触发舵机转动出粮 } http.end(); } delay(10000); }这种轮询方案虽不优雅但胜在简单稳定。真正生产级的做法是让后端通过MQTT协议推送指令到设备这个对于毕设来说有点超纲能写进文档里提一下就行。4.3 消息通知怎么实现用户最关心的是“喂食是否成功”这个结果。微信小程序里推送订阅消息是合适的方案不过需要解决模板ID和用户授权的问题。// 小程序端请求订阅消息授权 wx.requestSubscribeMessage({ tmplIds: [模板ID], success: (res) { if (res[模板ID] accept) { // 用户同意授权可以发送订阅消息 request(/api/subscribe/register, POST) } } })服务端在计划执行完成或异常时调用微信的订阅消息接口curl -X POST https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_tokenACCESS_TOKEN \ -H Content-Type: application/json \ -d { touser: OPENID, template_id: 模板ID, page: pages/record/record, data: { thing1: { value: 小乖 }, time2: { value: 12:30 }, thing3: { value: 出粮15克剩余粮量充足 } } }有一个实际的限制需要提前知道微信订阅消息是一次性的。用户授权一次只能收到一条消息不能像公众号模板消息那样无限制推送。因此对于“喂食成功”这种高频场景不能每次都推送。实际设计中我建议只推送“异常告警”和“手动执行的结果”计划成功执行时不做推送而是在小程序首页展示让用户自行点开查看。5. 常见问题与排查技巧实录5.1 制作流程中会遇到的典型问题先盘点一下学生在做这个题目时最常见的问题问题场景现象排查思路与解决办法后端启动了但小程序请求失败提示“request:fail -2:net::ERR_FAILED”开发阶段后端地址要加 https但在本地调试必须勾选“不校验合法域名”小程序开发者工具右上角详情-本地设置里打开微信登录拿不到openid后端日志显示code无效检查appid和secret是否填写正确确认不是用的测试号来对接正式小程序后台计划保存了但到点不执行数据库状态没有更新检查Scheduled是否启用启动类要加EnableScheduling确认服务器时间与本地时间一致请求头跨域报错浏览器控制台CORS报错后端加CrossOrigin注解或在配置类中注册全局CORS配置数据库时间字段差8小时存储时间比实际时间晚8小时连接池URL里加serverTimezoneAsia/Shanghai同时检查服务器时区设置订阅消息发送时报43101用户拒绝了授权或已超过一次性限制引导用户重新在小程序内授权或换一个模板场景重新触发第一个问题概率最高。很多学生第一次用开发者工具不知道默认情况下小程序不能请求http接口。这里再次强调正式发布的小程序只能访问HTTPS接口且域名必须备案但开发和真机调试阶段可以在工具里勾选“开发环境不校验合法域名”。5.2 微信开发者工具的3个实用姿势这3个技巧是提升调试效率的关键常规教程很少提到利用“模拟操作”面板里的“编译模式”可以自定义启动页面的参数比如直接进入编辑宠物资料页而不用每次从首页点好几层才能到。非常适合调试某个深层次页面时使用。“真机调试”选择“USB调试”或“远程调试”当你发现模拟器上一切正常但真机上数据加载出来是空白时可以优先通过真机调试模式看Console面板的输出能直接看到具体报错是接口挂了还是渲染出问题。“缓存”面板可以一键清除全部缓存开发时经常遇到小程序代码更新了但运行结果还是旧数据多半是Storage缓存没清。通过“清缓存”一键完成省得反复手动删Storage。5.3 有没有必要做多端兼容uni-app版本这个问题的答案取决于你要不要参加比赛或后续继续维护。如果你做的是纯毕业设计这个不是刚需微信小程序原生自己做一遍就够了。但如果你要参加“互联网”之类的创新创业比赛多端发布微信小程序、支付宝小程序、H5、App会显著加分这时候考虑用uni-app重写前端是有价值的。用uni-app的代价是你可能会遇到一些编译层面的问题比如某些原生组件在uni-app里需要特殊适配以及很多教程都是针对原生写法的迁移过去需要一定的排查能力。建议是毕业设计就原生写省时省力参加比赛可以冲一下uni-app作为创新点写进文档。6. 毕业设计过程中自己踩过的坑6.1 需求膨胀是一个巨大的坑这个项目管理系统的方向很容易让人上头要不要加视频监控要不要加语音呼唤要不要加自动铲屎我的建议很明确除非你的毕设题目明确要求必须包含这些否则统一砍掉。你首先需要保证的是核心流程登录-建档-设置计划-执行记录-结果展示完整跑通。做减法是我带学生时反复强调的点。一个能稳定跑完核心流程的毕设拿到的评分一定高于一个做了5个功能但每一个都Bug连篇的毕设。核心流程做好了有余力再锦上添花。视频监控功能牵扯到视频流、对象存储、小程序live-player组件兼容性复杂度是以指数级增长的不是一星期能磨出来的。6.2 数据库的初始化脚本一定要留好很多学生喜欢直接在Navicat里面手动点着建表进程到了最后忘了留存SQL脚本换一台电脑就要重头建表。正确做法是写一个schema.sql存放在项目代码库里里面包含建库建表语句和基础测试数据。这样不管换开发机、部署服务器、还是最后交给导师演示都能一键初始化。核心SQL脚本示例-- 用户表 CREATE TABLE user ( id bigint(20) NOT NULL AUTO_INCREMENT, openid varchar(64) NOT NULL, nickname varchar(50) DEFAULT 微信用户, avatar_url varchar(255) DEFAULT NULL, device_id varchar(64) DEFAULT NULL, create_time datetime DEFAULT CURRENT_TIMESTAMP, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_openid (openid) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表; -- 喂食计划表 CREATE TABLE feeding_plan ( id bigint(20) NOT NULL AUTO_INCREMENT, user_id bigint(20) NOT NULL, pet_id bigint(20) NOT NULL, device_id varchar(64) NOT NULL, plan_time varchar(16) NOT NULL COMMENT 计划喂食时间 HH:mm, feed_amount int(11) NOT NULL COMMENT 出粮克数, status varchar(20) NOT NULL DEFAULT WAITING, create_time datetime DEFAULT CURRENT_TIMESTAMP, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT喂食计划表;多花这一点时间后期能省掉很多琐碎的麻烦。6.3 工作量展示上留意这几个细节最后说一个答辩和文档上的经验。截图配时序图论文里的功能展示不要只放小程序页面截图加上接口调用时序图比如用户发起喂食计划-后端保存-定时任务触发-设备执行-前端展示记录会显得你对系统整体运行逻辑有清晰的认知。过程文档按版本迭代命名答辩时老师在评审表上会看你的开发日志或技术报告。如果能把过程文档做成“V1.0-需求分析→V2.0-数据库设计→V3.0-前后端联调→V4.0-功能优化”这种版本线直观体现你的工作是在递进的。演示前一定要准备一台备用手机真机演示时最常见的翻车情况是小程序需要重新登录、扫码调试后网络断了、或手机电量不足。用备用机提前配置好测试账号避免现场手忙脚乱。这个选题最大的乐趣在于你做的东西是真的可以拿去喂家里那只猫的。我自己的那只橘猫就是被这套系统喂胖的。当你出差在外打开小程序看到猫主子在食盆前吃得正香的时候那种成就感不是一纸文凭能替代的。如果你也在做这个方向的毕设希望这篇文章能帮你少走一些弯路。