SpringBoot+微信小程序+AI智能外卖推荐系统设计与实现全解析
2026/9/18 19:48:42 网站建设 项目流程

很多同学看到“基于SpringBoot+微信小程序+AI的智能外卖点餐推荐系统”这种题目时,第一反应通常是:这不就是把外卖系统的增删改查套了个壳吗?如果你也这样想,那很可能低估了这个课题的价值,也容易在答辩时被老师问住。一个真正能拿高分的毕设,绝不是靠堆砌“SpringBoot + 小程序 + AI”三个热门词,而是要回答清楚一个问题:AI到底在这个系统里解决了什么业务问题?推荐逻辑在哪里体现?你的系统相比普通的外卖点餐系统,增量在哪里?

这篇文章不会只帮你把项目跑起来,而是把整个系统的设计思路、技术选型、核心代码、推荐算法落地、小程序联调以及答辩时最容易被追问的技术点一次讲透。你读完应该能达到三个效果:第一,能独立把这个项目从零搭起来并跑通;第二,能说清楚每个模块为什么这么设计;第三,面对老师关于“AI在哪里”的提问,你能给出有深度的回答。

1. 为什么“智能外卖点餐推荐系统”值得做

先下一个判断:外卖点餐系统是后端开发中业务闭环最完整、最适合做毕设的选题之一,加上推荐的AI能力后,它的技术含量立刻和普通CRUD项目拉开了档次。

你可以对比一下两个毕设题目的差异。如果题目是“基于SpringBoot的外卖点餐系统”,那么核心工作就是用户管理、商家管理、菜品管理、订单管理、购物车,确实偏业务流。但加上“AI推荐”后,系统必须回答几个新问题:

  • 用户打开小程序,首页展示哪些菜品?依据是什么?
  • 新用户没有任何行为记录时,怎么给他推荐?
  • 用户浏览、加购、下单后,推荐列表如何动态调整?
  • 推荐结果如何用大模型生成个性化描述,而不是单纯的数据库查询?

这些问题任何一个展开,都能变成一个很好的毕业设计亮点。更关键的是,这个题目覆盖了当前企业级Java开发的主流技术栈:SpringBoot做后端、MyBatis-Plus操作数据库、微信小程序做C端、AI大模型接口做智能增强。一套项目下来,简历上能写的内容非常充实。

什么样的读者最适合参考这个项目?如果你正在准备计算机、软件工程相关专业的毕业设计,后端方向为主,又希望项目里带一些算法和AI元素,那么这篇文章的匹配度非常高。即使你只是想在简历里增加一个完整的全栈项目,这个选题也值得做。

2. 系统整体架构与核心业务流程

2.1 系统角色划分

智能外卖点餐推荐系统的用户角色分为三类:普通用户、商家管理员、系统管理员。

普通用户通过微信小程序完成登录、浏览菜品、查看推荐、加入购物车、下单支付、订单查询、评价等操作。商家管理员在管理后台维护菜品信息、库存和订单状态。系统管理员负责用户管理、商家审核、数据统计等平台级功能。

从权限设计来看,小程序端是C端用户入口,管理后台是B端运营入口,两者不共用一套页面,但在后端共享同一套用户体系和鉴权机制。

2.2 核心业务流程

整个系统的核心链路是:

用户微信授权登录 -> 小程序首页请求推荐接口 -> 后端获取用户特征 -> 推荐引擎计算菜品列表 -> 叠加AI个性化描述 -> 返回小程序渲染 -> 用户加购下单 -> 订单状态流转 -> 商家接单处理

这个链路里有两个关键设计点。第一,推荐不是一次性计算,而是分层的:用户进入首页时触发一次推荐,搜索时触发关键词推荐,查看菜品详情时触发“相似菜品推荐”。第二,AI不是替代推荐算法,而是在推荐结果之上做增强,比如生成推荐理由、口味标签、搭配建议,这样既保证推荐质量可控,又让系统体现“智能化”。

2.3 技术架构分层

系统采用前后端分离架构,小程序端和后端通过RESTful API通信,管理后台采用Vue或Thymeleaf模板引擎,后端整体采用经典分层结构。

controller(接口层) | service(业务层) | |--- 推荐服务(基于用户行为 + 协同过滤) |--- AI服务(调用大模型接口做文案增强) | dao(数据访问层,MyBatis-Plus) | database(MySQL)

这种分层的价值在毕设答辩时特别容易讲清楚:每一层只负责自己的职责,推荐逻辑被封装在独立的service中,不会污染订单和菜品模块的代码。如果以后想替换推荐算法,只需要修改推荐服务实现类,其他模块完全不受影响。

3. 数据库表结构设计

数据库设计是一个毕设项目的骨架。智能外卖点餐系统的核心表包括用户表、商家表、菜品表、分类表、购物车表、订单表、订单明细表、地址表、评价表、用户行为表。

3.1 核心表结构说明

用户表(user)保存微信用户的openId、昵称、头像、手机号、性别等基础信息。openId是微信生态下用户的唯一标识,设计时必须加唯一索引,否则同一用户反复登录会产生多条脏数据。

菜品表(dish)是推荐系统的核心数据源,字段包括菜品名称、图片、价格、分类ID、商家ID、月销量、评分、库存、状态。其中月销量和评分是后续推荐算法的重要特征,也是冷启动时兜底推荐的主要依据。

订单表(orders)和订单明细表(order_detail)是典型的父子表关系,一个订单对应多条明细。设计时要注意用订单号作为业务主键,在支付回调、对账等场景下使用,自增主键只作为内部标识。

用户行为表(user_behavior)是推荐系统的关键,记录的字段包括用户ID、菜品ID、行为类型(浏览、加购、下单、收藏)、行为时间。这张表会持续增长,建议以用户ID做分表设计,并在行为时间上建立索引。

3.2 建表SQL示例

-- 菜品表 CREATE TABLE `dish` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(100) NOT NULL COMMENT '菜品名称', `image` varchar(500) DEFAULT NULL COMMENT '菜品图片', `price` decimal(10,2) NOT NULL COMMENT '价格', `category_id` bigint(20) DEFAULT NULL COMMENT '分类ID', `merchant_id` bigint(20) DEFAULT NULL COMMENT '商家ID', `month_sales` int(11) DEFAULT '0' COMMENT '月销量', `rating` decimal(3,2) DEFAULT '5.00' COMMENT '评分', `status` tinyint(4) DEFAULT '1' COMMENT '状态 1上架 0下架', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_category` (`category_id`), KEY `idx_merchant` (`merchant_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='菜品表'; -- 用户行为表 CREATE TABLE `user_behavior` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `user_id` bigint(20) NOT NULL COMMENT '用户ID', `dish_id` bigint(20) NOT NULL COMMENT '菜品ID', `behavior_type` tinyint(4) NOT NULL COMMENT '行为类型 1浏览 2加购 3下单 4收藏', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_user_time` (`user_id`, `create_time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户行为表';

4. SpringBoot后端核心模块实现

4.1 项目初始化与依赖配置

后端项目使用SpringBoot 2.7.x作为基础框架,搭配MyBatis-Plus 3.5.x、MySQL 8.0、Redis可选、Swagger接口文档、Lombok简化开发。

<dependencies> <!-- SpringBoot Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- MyBatis-Plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3</version> </dependency> <!-- MySQL --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!-- Lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>

配置文件中需要特别注意的是数据库连接配置和MyBatis-Plus的日志配置,前者关系到项目能否启动,后者关系到你是否能方便地查看SQL执行情况。

server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/smart_order?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: your_password mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl map-underscore-to-camel-case: true global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0

4.2 微信登录接口实现

微信小程序登录的核心流程是:小程序端调用wx.login获取临时code,将code发送到后端,后端通过code向微信接口换取openId和session_key,然后生成自定义登录态token返回给小程序。

// 文件路径:src/main/java/com/example/smartorder/controller/AuthController.java @RestController @RequestMapping("/api/auth") public class AuthController { @Autowired private UserService userService; @PostMapping("/wx-login") public Result<String> wxLogin(@RequestBody WxLoginRequest request) { // 1. 使用code调用微信接口,获取openId String openId = userService.getOpenIdByCode(request.getCode()); // 2. 根据openId查找用户,不存在则自动注册 User user = userService.findOrCreateUser(openId); // 3. 生成登录token并返回 String token = JwtUtil.generateToken(user.getId()); return Result.success(token); } }

这里有一个非常常见的坑点:如果后端没有正确配置微信小程序的AppId和AppSecret,或者请求微信接口时网络不通,前端就会提示“获取登录后的微信用户失败”。排查时优先检查后端日志中微信接口返回的errcode,常见的40029表示code无效,40163表示code已被使用过,需要重新调用wx.login。

4.3 菜品推荐接口实现

推荐接口是整个系统的核心,也是毕业设计答辩时老师最关注的部分。推荐策略采用多路召回、统一排序的思路:先通过不同策略召回候选菜品,再根据规则或模型打分排序,最后返回TopN。

// 文件路径:src/main/java/com/example/smartorder/service/impl/RecommendServiceImpl.java @Service public class RecommendServiceImpl implements RecommendService { @Autowired private DishMapper dishMapper; @Autowired private UserBehaviorMapper behaviorMapper; @Autowired private AiService aiService; @Override public List<DishVO> recommendForUser(Long userId, int size) { // 1. 判断用户是否有行为记录 int behaviorCount = behaviorMapper.countByUserId(userId); List<Dish> candidateDishes; if (behaviorCount == 0) { // 2. 冷启动:基于热门菜品兜底推荐 candidateDishes = dishMapper.selectHotDishes(size); } else { // 3. 有行为数据:基于协同过滤思想召回候选菜品 // 先找到相似用户,再推荐相似用户喜欢的菜品 List<Long> similarUserIds = behaviorMapper.findSimilarUserIds(userId); candidateDishes = dishMapper.selectDishesByUserPreferences(similarUserIds, size); } // 4. AI生成个性化推荐理由 List<DishVO> result = new ArrayList<>(); for (Dish dish : candidateDishes) { DishVO vo = DishVO.fromEntity(dish); vo.setRecommendReason(aiService.generateRecommendReason(userId, dish)); result.add(vo); } return result; } }

这个实现里有一个设计亮点:推荐模块可以自由切换策略。冷启动时使用热门排行榜,有行为数据时使用基于物品的协同过滤,后期还可以接入基于内容的推荐或向量召回。这种可扩展的架构在答辩时很加分。

4.4 协同过滤推荐算法具体实现

协同过滤是推荐系统最经典的算法,核心思想是“物以类聚,人以群分”。在毕业设计场景下,不需要实现完整的矩阵分解,使用基于物品的协同过滤即可达到演示效果。

基于物品的协同过滤分三步走:

第一步,构建用户-菜品交互矩阵。第二步,计算菜品之间的相似度,常用公式是余弦相似度。第三步,根据用户历史喜欢的菜品,找出相似度最高的TopN菜品进行推荐。

// 文件路径:src/main/java/com/example/smartorder/recommend/ItemCFRecommender.java @Component public class ItemCFRecommender { /** * 计算两个菜品之间的余弦相似度 */ public double cosineSimilarity(Map<Long, Integer> userScoresForDishA, Map<Long, Integer> userScoresForDishB) { Set<Long> commonUsers = new HashSet<>(userScoresForDishA.keySet()); commonUsers.retainAll(userScoresForDishB.keySet()); if (commonUsers.isEmpty()) { return 0.0; } double dotProduct = 0.0; double normA = 0.0; double normB = 0.0; for (Long userId : commonUsers) { int scoreA = userScoresForDishA.get(userId); int scoreB = userScoresForDishB.get(userId); dotProduct += scoreA * scoreB; } for (Integer score : userScoresForDishA.values()) { normA += score * score; } for (Integer score : userScoresForDishB.values()) { normB += score * score; } if (normA == 0 || normB == 0) { return 0.0; } return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB)); } }

在真实项目中,菜品相似度可以离线计算并缓存到Redis中,用户请求推荐时直接读取,不必每次实时计算。但在毕业设计中,如果数据量不大,实时计算完全够用,还能展示你对算法的理解。

5. AI大模型接入与智能推荐增强

5.1 大模型在系统中的定位

现在回答一个最关键的问题:大模型在这个系统里到底做什么?很多毕设项目只是把大模型接口当作聊天机器人接入,和业务毫无关联,答辩时很容易被质疑。这个项目的正确做法是:让AI成为推荐链路中的“文案增强器”和“语义理解器”。

具体来说,AI大模型承担三个职责:

第一,推荐理由生成。用户看到“为您推荐:黄焖鸡米饭”和“为您推荐:黄焖鸡米饭,因为您最近浏览过川湘菜,这道菜口味接近且评分高达4.8分”,后者的体验明显更好。前者是推荐算法算出来的,后者是AI根据推荐结果生成的。

第二,搜索意图理解。用户输入“辣一点的”“适合下雨天吃的”“低卡的”,这些口语化、非结构化的搜索词,传统SQL很难处理,但大模型可以将自然语言转换为结构化的查询条件或标签集合。

第三,菜品描述生成。商家上传菜品时只需填写基础信息,AI自动生成诱人的菜品描述和推荐标签。

5.2 大模型接口接入示例

后端接入大模型一般通过HTTP接口调用,这里以OpenAI兼容格式为例,实际项目由于网络环境原因,你需要根据自己可访问的模型服务地址进行调整。

// 文件路径:src/main/java/com/example/smartorder/service/impl/AiServiceImpl.java @Service public class AiServiceImpl implements AiService { @Value("${ai.api-url}") private String apiUrl; @Value("${ai.api-key}") private String apiKey; @Value("${ai.model}") private String model; @Override public String generateRecommendReason(Long userId, Dish dish) { // 构建提示词 String prompt = String.format( "你是一个美食推荐助手。用户最近浏览过川湘菜、烧烤类菜品," + "请为菜品【%s】生成一句20字以内的推荐理由,要求口语化、有吸引力,不要提及AI。", dish.getName() ); // 调用大模型接口 String result = callLlm(prompt); // 如果调用失败,返回兜底文案 if (result == null || result.isEmpty()) { return String.format("月售%s份,好评率%s%%", dish.getMonthSales(), dish.getRating().multiply(BigDecimal.valueOf(20))); } return result; } }

大模型接入有一个很重要的工程原则:必须设计兜底逻辑。AI接口可能出现超时、限流、返回格式异常等问题,不能因为AI挂了整个推荐接口就报错。生成推荐理由失败时,就回退到销量和评分组成的模板文案,保证主流程的稳定性。

另外需要配置AI接口的参数,放在application.yml中便于统一管理:

ai: api-url: https://your-llm-service.example.com/v1/chat/completions api-key: your-api-key model: your-model-name timeout: 5000

5.3 Prompt设计的实际技巧

接入大模型后你会发现,真正影响效果的不是模型本身,而是Prompt怎么写。推荐理由生成这个场景,比较好的Prompt模板是:

你是一个本地生活美食推荐助手。 背景:用户最近浏览过以下菜品:[麻辣香锅、烤鱼、小龙虾]。 任务:为菜品【毛血旺】生成推荐理由。 要求: 1. 30字以内,口语化,像朋友推荐一样自然。 2. 结合用户最近的浏览偏好解释推荐原因。 3. 不要出现“根据您的浏览记录”“AI推荐”等字样。 4. 如果无法生成,只回复“这道菜非常受欢迎”即可。

6. 微信小程序端实现

6.1 项目结构与页面设计

微信小程序端使用原生框架或uni-app开发。如果使用原生,项目结构包括pages、components、utils、api四个目录。页面主要包括首页、菜品分类页、购物车页、订单页、我的页面。

首页是推荐功能的主要展示位置,设计上建议使用“轮播图 + 推荐菜品瀑布流”的结构。推荐区域上方加一行说明文案,比如“智能推荐 · 根据您的口味定制”,让用户和评委都能直观感知到推荐功能的存在。

6.2 小程序登录与请求封装

小程序的request请求需要封装成一个公共模块,统一处理token携带、错误提示、状态码判断。

// 文件路径:miniprogram/utils/request.js const BASE_URL = 'http://localhost:8080'; function request(url, method, data) { return new Promise((resolve, reject) => { const token = wx.getStorageSync('token'); wx.request({ url: BASE_URL + url, method: method || 'GET', data: data || {}, header: { 'Content-Type': 'application/json', 'Authorization': token ? 'Bearer ' + token : '' }, success: (res) => { if (res.data.code === 200) { resolve(res.data.data); } else if (res.data.code === 401) { wx.navigateTo({ url: '/pages/login/login' }); } else { wx.showToast({ title: res.data.msg || '请求失败', icon: 'none' }); } }, fail: (err) => { wx.showToast({ title: '网络异常,请稍后重试', icon: 'none' }); reject(err); } }); }); } module.exports = { request };

在开发者工具中进行本地调试时,有一个容易卡住的地方:默认情况下小程序不允许请求http接口,必须在“详情 -> 本地设置”中勾选“不校验合法域名、web-view(业务域名)、TLS版本以及HTTPS证书”。如果发布正式版本或真机预览,则需要在微信公众平台配置合法域名,而且必须是HTTPS。

6.3 推荐列表渲染

获取推荐菜品列表后,小程序端通过wx:for循环渲染。需要注意图片懒加载和加载状态的处理,避免弱网环境下页面白屏。

<!-- 文件路径:miniprogram/pages/index/index.wxml --> <view class="recommend-section"> <view class="section-title"> <text>智能推荐</text> <text class="subtitle">根据你的口味定制</text> </view> <view class="dish-grid"> <view class="dish-card" wx:for="{{recommendList}}" wx:key="id" bindtap="handleDishTap" >mvn spring-boot:run

或者使用IDE直接运行主启动类。启动成功后,控制台会看到SpringBoot的启动日志,访问http://localhost:8080/swagger-ui.html可以查看接口文档。

第四步,打开微信开发者工具,导入小程序项目目录,修改utils/request.js中的BASE_URL为本机IP加端口。这里要注意,如果使用真机调试,不能填localhost,要填电脑在局域网中的IP地址。

7.2 项目部署到服务器

如果毕业设计需要演示远程访问,可以将后端打包成Jar包部署到云服务器。

# 打包 mvn clean package -DskipTests # 部署到服务器 scp target/smart-order-1.0.0.jar root@your-server:/opt/app/ # 启动 java -jar /opt/app/smart-order-1.0.0.jar --spring.profiles.active=prod

生产环境部署时,建议使用nohup或systemd管理进程,避免SSH断开后进程退出。

8. 常见问题与排查思路

8.1 问题排查表

问题现象可能原因排查方式解决方案
小程序请求后端失败开发者工具未关闭域名校验查看工具控制台错误提示详情 -> 本地设置 -> 勾选不校验合法域名
登录报错“获取登录后的微信用户失败”AppId和AppSecret配置错误查看后端日志中微信接口返回的errcode检查application.yml配置或重新获取code
后端启动报错数据库连接失败MySQL未启动或账号密码错误查看启动日志的Caused by信息确认MySQL服务状态和配置文件
推荐列表为空菜品表中没有上架状态的菜品查询数据库dish表数据在管理后台添加上架菜品
AI推荐理由不生效大模型接口超时或返回异常查看AiService日志检查ai.api-url配置,确认兜底文案生效
订单支付成功后库存未扣减事务未生效检查Service层是否添加@Transactional在扣减库存方法上添加事务注解

8.2 “小程序获取登录后的微信用户失败”深度排查

这个话题在开发者社区检索量很高,如果你的项目也遇到这个问题,按照下面的顺序排查成功率最高。

第一,确认code是新的。wx.login获取的code只能使用一次,如果前端重复发送同一个code,后端第二次调用微信接口时必然报错。检查前端代码中登录逻辑是否在每次点击时都重新调用wx.login。

第二,确认AppSecret正确。在微信公众平台重置AppSecret后,旧Secret立即失效。如果项目代码中硬编码了旧的Secret,排查时很难发现,建议将AppSecret放到后端配置文件中。

第三,确认网络环境能访问微信接口。如果后端部署在服务器上,需要确认目标地域能正常访问微信的API域名,否则请求会超时。如果部署在本地,确保开发机网络正常。

9. 最佳实践与毕业设计答辩建议

9.1 项目代码规范

后端代码建议统一使用Result 作为接口返回值,包含code、msg、data三个字段。这样做的原因是前端可以根据code统一处理业务异常,而不是依赖HTTP状态码。比如登录过期返回401,业务失败返回500,成功返回200。

数据库表设计时统一使用create_time和update_time字段,MyBatis-Plus提供了自动填充功能,避免在业务代码中手动维护时间字段,减少重复代码。

9.2 推荐系统的扩展方向

如果你的毕业设计想要冲击优秀论文,可以在现有基础上增加一个离线推荐计算模块,使用定时任务在每天凌晨计算菜品相似度矩阵并存入Redis,用户请求时直接读取缓存结果。这会让推荐接口的响应时间从几百毫秒下降到几十毫秒,而且更贴近真实工业界的推荐系统架构。

还可以考虑引入更丰富的用户特征,比如地理位置、价格偏好、口味偏好,通过给菜品打标签实现基于内容的推荐,与大模型结合做标签提取。

9.3 答辩时如何讲清楚“AI在哪里”

这是最重要的一个建议。答辩时老师几乎一定会问:“你的AI体现在哪里?”很多同学的回答是“我接入了大模型接口”,这个答案太单薄。

更好的回答方式是:先讲推荐链路,说明冷启动阶段如何用热门策略兜底,有行为数据后如何用协同过滤计算相似度;再讲AI的定位,说明大模型在推荐结果之上做自然语言理解、推荐理由生成、搜索意图解析;最后强调AI和推荐算法的分工:推荐算法负责“选什么菜”,大模型负责“为什么推荐这道菜给你”。这样一个回答下来,既展示了算法基础,又展示了工程能力,还能体现产品思维。

另外,演示时一定要准备一个“新用户”账号。用新账号登录时,首页展示热门推荐;然后你手动浏览几个川菜类菜品,再刷新推荐列表,列表会发生变化。这个前后对比的演示效果,比任何口头解释都有说服力。

10. 总结

智能外卖点餐推荐系统这个题目,真正的难点不在于SpringBoot的CRUD,也不在于微信小程序的页面开发,而在于如何把推荐算法和AI能力自然地嵌入到完整的业务链路中。把推荐分层设计、让AI做文案增强、用冷启动策略解决新用户问题,这三个点做到了,你的项目就能和普通的外卖管理系统拉开明显差距。

下一步建议你先跑通基础流程,再逐步加入协同过滤的相似度计算逻辑,最后接入大模型接口。每完成一个阶段,都用真实数据验证推荐效果。这样项目做完后,你对推荐系统的理解会远超“会用框架”的层面,答辩时自然更有底气。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询