简介:这是一套面向计算机专业本科生的毕业设计级微信小程序开发实战资源,聚焦家庭餐饮服务场景,为Java后端与小程序前端全栈开发提供完整参考方案。资源包含基于SSM框架的后台管理系统、MySQL数据库脚本、微信小程序源码及配套开题报告、论文、PPT和使用说明,覆盖从需求分析、系统设计到部署上线的全流程。压缩包共1251个文件,涵盖127个Java后端逻辑文件、137个Vue组件、178个JS交互脚本、90个WXSS样式文件、88个WXML模板及231个PNG界面素材,结构清晰、模块解耦明确,便于学习分层架构与前后端联调。资源包大小17.31MB,轻量易解压,已吸引98人下载学习。读者可直接运行管理后台与小程序双端,掌握用户/店铺双角色登录、菜品分类管理、订单全流程处理等核心业务实现,并复用数据库设计、权限控制逻辑与响应式UI组件。
1. 家庭大厨微信小程序:为什么一个“家常菜场景”能撑起完整毕业设计闭环?
你有没有遇到过这样的毕业设计卡点:选题太泛——“基于Web的餐饮系统”查重率98%;技术太虚——“融合AI推荐算法”结果连数据集都凑不齐;交付太散——代码、数据库、文档各在三个压缩包里,答辩前一晚还在改PPT字体?而“家庭大厨微信小程序”这个标题,表面看是做个菜谱App,实则是一条被反复验证过的高完成度、低翻车率、全链路可展示的毕业设计路径。它天然绑定微信生态(免部署、真机可测)、聚焦真实高频场景(家人查菜谱、记备忘、传小贴士),且Java后端+MySQL+小程序前端的技术栈,既避开Spring Cloud等复杂架构,又保留足够工程量体现能力。更重要的是,它把“开题报告怎么写需求分析”“论文里如何画ER图和时序图”“PPT第3页放什么截图最显真机效果”这些隐性门槛,全部折叠进一个可运行的菜谱收藏、食材管理、烹饪步骤分步查看的闭环里。这不是玩具项目,而是某高校连续三年推荐给Java方向本科生的“保底型实战载体”。
2. 从零搭起后端骨架:用Spring Boot 2.7 + MyBatis-Plus 快速生成用户与菜谱模块
2.1 为什么选 Spring Boot 2.7 而非 3.x?兼容性才是毕业设计的生命线
毕业设计不是技术发布会,稳定压倒一切。Spring Boot 3.x 强制要求 JDK 17+,但学校机房、导师电脑、答辩演示机大概率还跑着 JDK 8 或 11。一旦本地能跑、答辩机报错Unsupported class file major version 61,就是当场掉血。Spring Boot 2.7.18(当前2.7系列最新维护版)完美兼容 JDK 8~17,且 MyBatis-Plus 3.5.3.1 对它的适配已打磨多年。我们用spring-boot-starter-web+mybatis-plus-boot-starter+mysql-connector-java三件套起步,不引入 Redis、RabbitMQ 等加分项——它们会吃掉你调试连接池超时的3天时间。
<!-- pom.xml 关键依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.7.18</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> <version>8.0.33</version> </dependency>提示:
mysql-connector-java8.0.33 是 MySQL 5.7/8.0 双兼容的“黄金版本”,避免Public Key Retrieval is not allowed这类玄学报错。
2.2 用 MyBatis-Plus 代码生成器,10分钟产出 User 和 Recipe 的全套CRUD
别手写Mapper XML!MyBatis-Plus 的AutoGenerator能根据数据库表结构,自动生成 Entity、Mapper、Service、Controller 全家桶。先建库建表:
-- 创建数据库 CREATE DATABASE IF NOT EXISTS family_chef DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 用户表(简化版,毕业设计够用) CREATE TABLE `user` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', `wx_openid` varchar(64) NOT NULL COMMENT '微信openid,唯一标识用户', `nickname` varchar(32) DEFAULT NULL COMMENT '微信昵称', `avatar_url` varchar(255) DEFAULT NULL COMMENT '头像URL', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_openid` (`wx_openid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; -- 菜谱表 CREATE TABLE `recipe` ( `id` bigint NOT NULL AUTO_INCREMENT, `title` varchar(100) NOT NULL COMMENT '菜名', `ingredients` text COMMENT '食材列表,JSON格式存储["鸡蛋","葱花"]', `steps` text COMMENT '步骤,JSON格式[{"step":1,"desc":"打蛋"},{"step":2,"desc":"热锅凉油"}]', `cover_img` varchar(255) DEFAULT NULL COMMENT '封面图URL', `author_id` bigint NOT NULL COMMENT '作者user.id', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_author` (`author_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='菜谱表';然后运行代码生成器(放在src/test/java下):
// CodeGenerator.java public class CodeGenerator { public static void main(String[] args) { // 1. 全局配置 GlobalConfig gc = new GlobalConfig(); gc.setOutputDir("src/main/java"); // 输出目录 gc.setAuthor("student"); // 作者名,答辩PPT里可写“本系统由XXX同学独立开发” gc.setOpen(false); // 不打开输出目录 gc.setSwagger2(true); // 生成Swagger注解,方便接口测试 // 2. 数据源配置 DataSourceConfig dsc = new DataSourceConfig(); dsc.setUrl("jdbc:mysql://localhost:3306/family_chef?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true"); dsc.setDriverName("com.mysql.cj.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("123456"); // 3. 包配置 PackageConfig pc = new PackageConfig(); pc.setModuleName("recipe"); // 模块名,生成的包为 com.example.familychef.recipe pc.setParent("com.example.familychef"); // 4. 策略配置 StrategyConfig strategy = new StrategyConfig(); strategy.setNaming(NamingStrategy.underline_to_camel); // 数据库下划线转驼峰 strategy.setColumnNaming(NamingStrategy.underline_to_camel); strategy.setEntityLombokModel(true); // 自动添加Lombok注解 strategy.setInclude("user", "recipe"); // 只生成这两张表 // 5. 执行 new AutoGenerator() .setGlobalConfig(gc) .setDataSource(dsc) .setPackageInfo(pc) .setStrategy(strategy) .execute(); } }执行后,你会得到User.java(带@Data@TableName("user"))、UserMapper.java(空接口,继承BaseMapper<User>)、UserService.java(带@Service)、UserController.java(带@RestController和/user/list接口)。这省下的不是代码行数,是答辩前夜调试SQL拼接错误的崩溃感。
2.3 微信登录对接:用 wx.login 临时凭证换用户信息,不碰敏感权限
小程序端调wx.login()获取code,后端用该code向微信服务器换取openid,这是唯一必须走通的鉴权链路。关键点在于:绝不请求scope.userInfo!因为微信2023年起强制要求用户主动触发button open-type="getUserInfo"才能获取昵称头像,而毕业设计演示时用户根本不会点。正确做法是:后端只换openid,前端用wx.getUserProfile()(需用户确认)获取昵称头像,再通过POST /api/user/bind接口补全用户信息。
// UserController.java @PostMapping("/login") public Result<Map<String, Object>> login(@RequestBody Map<String, String> params) { String code = params.get("code"); if (StringUtils.isBlank(code)) { return Result.fail("code不能为空"); } // 1. 调用微信接口换取 openid String url = "https://api.weixin.qq.com/sns/jscode2session?" + "appid=" + WX_APPID + "&secret=" + WX_SECRET + "&js_code=" + code + "&grant_type=authorization_code"; String response = HttpUtil.get(url); // 使用Hutool工具类,比原生HttpURLConnection稳 JSONObject json = JSON.parseObject(response); String openid = json.getString("openid"); if (StringUtils.isBlank(openid)) { log.error("微信登录失败,响应: {}", response); return Result.fail("登录失败:" + json.getString("errmsg")); } // 2. 查询或创建用户 User user = userService.getByOpenid(openid); if (user == null) { user = new User(); user.setWxOpenid(openid); user.setCreateTime(new Date()); userService.save(user); } // 3. 生成自定义登录态 token(用JWT简单实现,不用Redis存session) String token = JWT.create() .withClaim("userId", user.getId()) .withExpiresAt(new Date(System.currentTimeMillis() + 7 * 24 * 3600 * 1000L)) // 7天过期 .sign(Algorithm.HMAC256("family_chef_secret_key")); // 密钥写死,毕业设计够用 Map<String, Object> data = new HashMap<>(); data.put("token", token); data.put("userId", user.getId()); data.put("openid", openid); return Result.success(data); }参数说明:
WX_APPID和WX_SECRET需在微信公众平台注册小程序后获取,填入application.yml。JWT.create()依赖com.auth0:java-jwt库,轻量无依赖。token 存 localStorage 即可,小程序端每次请求带Authorization: Bearer xxx,后端用@RequestHeader("Authorization")解析,比 session 更适合演示。
3. 小程序前端:用原生框架+云开发能力快速呈现核心功能
3.1 页面结构设计:首页轮播+分类导航+菜谱瀑布流,3个页面搞定
毕业设计不追求复杂交互,而要一眼看清功能边界。我们只做3个核心页面:
index/index:顶部轮播图(宣传“家常菜大全”)、中部“按场景分类”(早餐/快手菜/宝宝辅食)、底部“热门菜谱”瀑布流;recipe/detail:单个菜谱详情页,含封面图、标题、食材清单(横向滚动)、步骤图文(纵向列表);mine/mine:我的页面,显示用户头像昵称、我的收藏、上传菜谱入口(仅开发时用,答辩演示可隐藏)。
所有页面用微信原生 WXML + WXSS 开发,不引入 Taro/uni-app 等跨端框架——它们会增加npm run dev失败的排查成本。WXML 结构遵循“语义化+最小DOM”原则:
<!-- index.wxml --> <view class="container"> <!-- 轮播图 --> <swiper class="banner" indicator-dots autoplay interval="3000"> <swiper-item><image src="/images/banner1.jpg" mode="aspectFill"/></swiper-item> <swiper-item><image src="/images/banner2.jpg" mode="aspectFill"/></swiper-item> </swiper> <!-- 分类导航 --> <view class="category-list"> <navigator url="/pages/category/category?type=breakfast" class="category-item"> <image src="/icons/breakfast.png"/><text>早餐</text> </navigator> <navigator url="/pages/category/category?type=quick" class="category-item"> <image src="/icons/quick.png"/><text>快手菜</text> </navigator> </view> <!-- 热门菜谱 --> <view class="hot-recipes"> <text class="section-title">热门菜谱</text> <scroll-view class="recipe-scroll" scroll-x> <navigator wx:for="{{hotRecipes}}" wx:key="id" url="/pages/recipe/detail?id={{item.id}}"> <view class="recipe-card"> <image src="{{item.cover_img}}" mode="aspectFill"/> <text class="recipe-title">{{item.title}}</text> </view> </navigator> </scroll-view> </view> </view>注意:
scroll-view的scroll-x属性实现横向滚动,比swiper更轻量;navigator组件自带跳转能力,无需wx.navigateTo手动写JS,降低出错概率。
3.2 菜谱详情页:用rich-text渲染步骤描述,规避富文本编辑器坑
菜谱步骤常含图片+文字混排(如“步骤1:[图片] 热锅凉油”),若用textarea或editor组件,会陷入“图片上传到哪?”“怎么存HTML?”“小程序渲染HTML安全吗?”三连问。毕业设计最优解:步骤字段存JSON数组,前端用rich-text直接渲染。后端返回数据结构:
{ "steps": [ {"type": "text", "content": "1. 鸡蛋打入碗中,加少许盐,搅匀"}, {"type": "image", "content": "https://xxx/step1.jpg"}, {"type": "text", "content": "2. 锅烧热,倒入适量油,油温六成热时倒入蛋液"} ] }小程序端用rich-text解析:
<!-- recipe/detail.wxml --> <view class="steps-container"> <rich-text nodes="{{stepsNodes}}"/> </view>// recipe/detail.js Page({ data: { stepsNodes: [] }, onLoad(options) { const id = options.id; wx.request({ url: 'https://your-server/api/recipe/detail?id=' + id, success: (res) => { const steps = res.data.data.steps || []; // 将后端JSON转为rich-text所需nodes格式 const nodes = steps.map(step => { if (step.type === 'image') { return { name: 'img', attrs: { src: step.content, style: 'width:100%;height:auto;display:block;margin:10rpx 0;' } }; } else { return { name: 'p', children: [{ type: 'text', text: step.content }] }; } }); this.setData({ stepsNodes: nodes }); } }); } });血泪经验:
rich-text的nodes数组必须严格符合文档格式,name字段不能写错(如写成img而非image),attrs里的style建议写内联样式,避免WXSS全局污染。这招让“图文混排”从3天攻坚变成1小时配置,且渲染性能远超web-view。
3.3 云开发能力复用:用云存储存封面图,绕过自建文件服务
毕业设计最怕“图片上传功能”。自己搭 Nginx + FastDFS?答辩时网络一抖就挂。微信云开发提供免费额度(每月1G云存储、5万次调用),且 SDK 一行代码上传:
// 上传封面图(在 recipe/add 页面) wx.cloud.uploadFile({ cloudPath: 'recipe/cover/' + Date.now() + '.jpg', // 云存储路径 filePath: tempFilePath, // 本地临时路径 success: res => { console.log('上传成功', res.fileID); // res.fileID 即云存储URL,存入数据库 that.setData({ coverUrl: res.fileID }); } });后端 Java 代码只需接收并保存这个fileID(形如cloud://xxx.jpg),前端<image>标签直接src="{{recipe.cover_img}}"即可显示。云存储URL本质是CDN链接,加载快、不占服务器带宽,且完全规避了“跨域问题”“MIME类型错误”等新手高频雷区。
4. 数据库设计与避坑:从 ER 图到索引优化的毕业设计级实践
4.1 核心 ER 图:3张表讲清家庭场景关系
毕业设计数据库不必追求范式完美,但 ER 图必须逻辑自洽、答辩能讲清。我们围绕“人-菜-互动”构建三张表:
| 表名 | 主键 | 关键外键 | 业务含义 |
|---|---|---|---|
user | id | — | 小程序用户,由微信 openid 唯一标识 |
recipe | id | author_id → user.id | 菜谱,作者是某个用户 |
collect | id | user_id → user.id,recipe_id → recipe.id | 收藏关系,多对多中间表 |
注意:
collect表不叫user_recipe,因为毕业设计命名要体现业务语义;author_id不叫user_id,避免和collect.user_id混淆。答辩时指着ER图说:“用户发布菜谱形成一对多,用户收藏菜谱形成多对多,所以需要中间表”——这句话就能拿满设计分。
4.2 索引优化:3个必加索引让查询不卡顿
没有索引的数据库,在1000条数据时就可能拖慢演示。针对高频查询场景加索引:
- 用户登录查询:
SELECT * FROM user WHERE wx_openid = ?→ 在wx_openid加唯一索引(建表时已加UNIQUE KEY uk_openid); - 菜谱列表分页:
SELECT * FROM recipe ORDER BY create_time DESC LIMIT 0,10→ 在create_time加普通索引; - 收藏状态判断:
SELECT COUNT(*) FROM collect WHERE user_id = ? AND recipe_id = ?→ 在(user_id, recipe_id)加联合索引,覆盖查询。
-- 执行建索引SQL ALTER TABLE `recipe` ADD INDEX `idx_create_time` (`create_time`); ALTER TABLE `collect` ADD UNIQUE INDEX `uk_user_recipe` (`user_id`, `recipe_id`);提示:
EXPLAIN SELECT ...是你的朋友。在 MySQL Workbench 里执行EXPLAIN SELECT * FROM recipe ORDER BY create_time DESC LIMIT 10,如果type显示index或range,说明索引生效;若为ALL,说明全表扫描,赶紧加索引。
4.3 避坑:毕业设计数据库的5个血泪教训
现象1:插入中文乱码,数据库里显示“???”
原因:建库时未指定字符集,或 JDBC URL 缺少characterEncoding=utf8mb4。
解决:建库语句必须带DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;JDBC URL 加?useUnicode=true&characterEncoding=utf8mb4。
现象2:datetime字段存入数据库后秒数丢失(如2023-01-01 12:30:45.123变成2023-01-01 12:30:45)
原因:MySQL 5.6 默认datetime精度为0,MyBatis-Plus 的@TableField(fill = FieldFill.INSERT)自动填充时截断。
解决:将字段类型改为datetime(3)(支持毫秒),并在实体类Date字段上加@TableField(fill = FieldFill.INSERT)注解,同时确保application.yml中spring.jackson.date-format=yyyy-MM-dd HH:mm:ss.SSS。
现象3:MyBatis-Plus 分页插件PageHelper不生效,select count(*)返回0
原因:Spring Boot 2.7+ 默认禁用PageHelper的自动配置,或@Select注解方法未加@SelectProvider。
解决:在pom.xml中排除pagehelper-spring-boot-starter,改用 MyBatis-Plus 内置分页:IPage<Recipe> page = new Page<>(current, size); recipeService.page(page, wrapper);。
现象4:collect表插入重复收藏,违反唯一索引但没报错
原因:代码里用collectService.save(collect),未捕获DuplicateKeyException。
解决:用collectService.saveOrUpdate(collect, new QueryWrapper<Collect>().eq("user_id", userId).eq("recipe_id", recipeId)),或手动 try-catch 并提示“已收藏”。
现象5:导出 SQL 文件后,在另一台电脑导入失败,报错Unknown collation: 'utf8mb4_0900_ai_ci'
原因:MySQL 8.0 默认校对规则,老版本不识别。
解决:导出时用mysqldump --default-character-set=utf8mb4 -r family_chef.sql family_chef,或用 Navicat 导出选择“兼容 MySQL 5.7”。
5. 论文与PPT:把技术细节转化为答辩得分点的实操技巧
5.1 论文写作:用“问题驱动”结构替代教科书式章节
别写“第一章 绪论:介绍微信小程序发展现状…”——这会让导师觉得你在复制百度百科。毕业论文要体现你遇到了什么问题、怎么解决的、为什么这么选。例如:
- 需求分析章节:不罗列“用户需要查菜谱”,而是写:“经问卷调研(附问卷截图),72%的家庭主妇反馈‘孩子挑食’是做饭最大痛点,因此系统增加‘宝宝辅食’分类,并在菜谱详情页强化‘营养成分’字段(见图3-2)”;
- 系统设计章节:不画一堆UML图,而是聚焦“为什么用 MyBatis-Plus 而非 JPA”:“JPA 的
@OneToMany在小程序高并发查询场景下易产生 N+1 查询,而 MyBatis-Plus 的QueryWrapper可精准控制 SQL,实测首页加载速度提升40%(见表4-1 响应时间对比)”; - 测试章节:不写“使用Postman测试接口”,而是记录真实数据:“模拟100用户并发收藏同一菜谱,
collect表uk_user_recipe索引使冲突检测耗时稳定在15ms内,无脏数据(见图5-3 JMeter结果截图)”。
技巧:所有图表编号用“图X-Y”“表X-Y”(X为章号,Y为顺序号),Word里用“引用→插入题注”自动生成,避免答辩时被问“图3-2在哪?”手忙脚乱。
5.2 PPT制作:3页讲清技术亮点,拒绝代码堆砌
答辩PPT不是代码展览馆。我一般只放3页技术页,每页一个核心点:
| 页码 | 标题 | 内容要点 | 视觉建议 |
|---|---|---|---|
| 第4页 | 微信登录态设计:轻量JWT方案 | 左侧流程图:小程序code → 后端换openid → 生成JWT → 前端存localStorage;右侧对比表格:JWT vs Session(优势:无服务端存储、跨域友好、7天过期可控) | 用 draw.io 画简洁流程图,对比表格用绿色✔标JWT优势 |
| 第5页 | 菜谱图文混排:rich-text 实现方案 | 左侧JSON示例({"type":"image","content":"url"});右侧小程序截图(步骤区域清晰显示图片+文字);底部小字:“规避editor组件图片上传复杂度,渲染性能提升60%” | 截图用 iPhone X 模拟器,加红色箭头指向步骤区域 |
| 第6页 | 数据库索引优化:从卡顿到流畅 | 左侧EXPLAIN执行结果对比图(优化前type=ALL,优化后type=range);右侧折线图:首页加载时间从2.1s→0.8s | 用 Excel 生成折线图,标注“优化后达标(<1s)” |
注意:所有截图必须是真机或模拟器实际运行画面,不要用PS合成。答辩时导师会问“这个按钮点一下发生了什么?”,你得能立刻说出对应接口和数据库操作。
5.3 开题报告与使用说明:把“怎么做”写成“谁都能照着做”
开题报告不是计划书,而是可行性承诺书。在“技术路线”部分,明确写出:
- “后端采用 Spring Boot 2.7.18 + MyBatis-Plus 3.5.3.1,JDK 版本要求:8~17(兼容学校机房环境)”;
- “前端使用微信原生框架,不依赖第三方UI库,确保在基础库2.20.0+版本正常运行”;
- “数据库使用 MySQL 5.7/8.0,SQL文件位于
/docs/database/family_chef_init.sql,执行即可初始化”。
使用说明文档(README.md)更要傻瓜化:
## 快速启动 1. 导入SQL:执行 `docs/database/family_chef_init.sql` 到 MySQL 2. 配置后端:修改 `application.yml` 中 `wx.appid` 和 `wx.secret` 3. 启动后端:`mvn spring-boot:run` 4. 启动小程序:微信开发者工具打开 `/miniprogram` 目录,点击“编译” 5. 登录:手机微信扫码预览,点击“授权登录”(仅首次)最后一句我永远加:“如遇问题,请检查
application.yml中数据库密码是否为123456(默认值)”。因为90%的“启动失败”都是密码没改对——这句能帮你省下3次答疑电话。
希望帮到你。
本文还有配套的精品资源,点击获取