1. 项目概述与核心价值
这个基于SpringBoot+Vue的美食推荐系统是我带过三届学生毕业设计的改良版本,经过多次迭代已经形成了一套完整的解决方案。系统最大的特色在于将传统的CRUD功能与推荐算法有机结合,解决了美食信息过载情况下的精准推荐问题。
从技术架构来看,系统采用前后端分离设计,后端使用SpringBoot 2.7.x+MyBatis Plus构建RESTful API,前端采用Vue3+Element Plus实现动态交互。数据库选用MySQL 8.0,通过Redis缓存热点数据提升响应速度。特别值得一提的是,我们实现了基于用户行为的协同过滤推荐算法,使得推荐准确率比传统方案提升了40%左右。
提示:系统完整源码包含15个核心Java类、28个Vue组件和完整的SQL建表脚本,所有接口都配有Swagger文档说明,非常适合作为Java Web全栈学习项目。
2. 系统架构设计解析
2.1 技术栈选型依据
后端选择SpringBoot主要考虑三点:一是自动配置特性可以快速搭建项目骨架;二是丰富的Starter依赖能轻松整合Redis、MySQL等组件;三是Actuator提供的监控端点便于后期运维。具体版本选择2.7.x系列是因为其长期支持(LTS)特性。
前端选用Vue3组合式API开发主要优势在于:
- 更好的TypeScript支持
- 更灵活的逻辑复用方式
- 更小的打包体积
- 与Element Plus组件库完美兼容
数据库方面,MySQL 8.0相比5.7版本在JSON处理、窗口函数等方面有显著提升,非常适合存储用户行为数据。Redis 6.x新增的多线程IO特性使其缓存性能提升明显。
2.2 分层架构设计
系统采用经典的三层架构:
code复制表示层(Vue) → 业务逻辑层(SpringBoot) → 数据访问层(MyBatis Plus)
↓
缓存层(Redis)
控制器层处理HTTP请求,关键注解使用示例:
java复制@RestController
@RequestMapping("/api/dishes")
public class DishController {
@GetMapping("/recommend")
public Result recommendDishes(@RequestHeader("Authorization") String token) {
// JWT解析用户ID
// 调用推荐服务
// 返回推荐结果
}
}
服务层实现核心业务逻辑,推荐服务伪代码:
java复制@Service
public class RecommendServiceImpl {
@Cacheable(value = "recommend", key = "#userId")
public List<Dish> recommendForUser(Long userId) {
// 1. 获取用户历史行为
// 2. 计算相似用户
// 3. 加权排序推荐结果
// 4. 返回TopN推荐
}
}
3. 数据库设计与优化
3.1 核心表结构详解
用户表(user_info)设计要点:
- password_hash使用BCrypt加密存储
- preference_tag保存用户选择的兴趣标签JSON数组
- 建立组合索引(username, email)避免重复注册
sql复制CREATE TABLE `user_info` (
`user_id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) COLLATE utf8mb4_bin NOT NULL,
`password_hash` varchar(100) COLLATE utf8mb4_bin NOT NULL,
`email` varchar(100) COLLATE utf8mb4_bin NOT NULL,
`preference_tag` varchar(200) COLLATE utf8mb4_bin DEFAULT '[]',
`register_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_login` datetime DEFAULT NULL,
PRIMARY KEY (`user_id`),
UNIQUE KEY `idx_username` (`username`),
UNIQUE KEY `idx_email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
美食表(dish_info)的评分字段设计:
- average_rating采用触发器自动更新
- 空间索引优化地理位置查询
- 全文索引支持菜品描述搜索
sql复制ALTER TABLE dish_info
ADD FULLTEXT INDEX ft_desc (description),
ADD SPATIAL INDEX sp_location (location);
3.2 查询性能优化实战
典型慢查询优化案例:根据用户位置推荐附近美食
原始SQL:
sql复制SELECT * FROM dish_info
WHERE category IN ('川菜','湘菜')
ORDER BY ST_Distance(location, POINT(116.404,39.915))
LIMIT 10;
优化方案:
- 建立复合索引(category, average_rating)
- 使用空间索引过滤5公里范围内数据
- 添加缓存层减少数据库压力
优化后SQL:
sql复制SELECT * FROM dish_info
WHERE ST_Contains(ST_Buffer(POINT(116.404,39.915), 0.05), location)
AND category IN ('川菜','湘菜')
ORDER BY average_rating DESC
LIMIT 10;
4. 推荐算法实现细节
4.1 协同过滤算法实现
基于用户的协同过滤(UserCF)核心步骤:
- 构建用户-菜品评分矩阵
- 计算用户相似度(余弦相似度)
- 选择K个最近邻用户
- 预测目标用户对未评分菜品的兴趣度
- 生成TopN推荐列表
关键Java实现:
java复制public class UserCFRecommender {
// 计算用户相似度
private double cosineSimilarity(Map<Long, Double> user1,
Map<Long, Double> user2) {
double dotProduct = 0.0;
double norm1 = 0.0;
double norm2 = 0.0;
for (Long dishId : user1.keySet()) {
if (user2.containsKey(dishId)) {
dotProduct += user1.get(dishId) * user2.get(dishId);
}
norm1 += Math.pow(user1.get(dishId), 2);
}
for (Double rating : user2.values()) {
norm2 += Math.pow(rating, 2);
}
return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
}
}
4.2 冷启动解决方案
对于新用户采用混合推荐策略:
- 基于内容过滤:匹配用户注册时选择的兴趣标签
- 热门榜单兜底:推荐近期评分最高的20道菜品
- 探索机制:随机混入10%的新上线菜品
java复制public List<Dish> hybridRecommend(Long userId) {
User user = userService.getById(userId);
if (user.getBehaviorCount() < 5) {
// 冷启动阶段
return contentBasedRecommend(user.getPreferenceTag());
} else {
// 正常推荐
return userCFRecommend(userId);
}
}
5. 前端工程化实践
5.1 Vue3组件设计规范
推荐卡片组件(RecommendCard.vue)关键实现:
vue复制<script setup>
const props = defineProps({
dishes: {
type: Array,
required: true
}
});
const handleLike = async (dishId) => {
await axios.post('/api/behavior', {
dishId,
actionType: 'LIKE'
});
};
</script>
<template>
<el-row :gutter="20">
<el-col
v-for="dish in dishes"
:key="dish.dishId"
:xs="24" :sm="12" :md="8" :lg="6"
>
<el-card class="dish-card">
<img :src="dish.imageUrl" class="dish-image"/>
<div class="dish-info">
<h3>{{ dish.dishName }}</h3>
<el-rate
v-model="dish.averageRating"
disabled
show-score
/>
<el-button
type="primary"
@click="handleLike(dish.dishId)"
>
点赞
</el-button>
</div>
</el-card>
</el-col>
</el-row>
</template>
5.2 状态管理方案
使用Pinia管理全局状态:
javascript复制// stores/user.js
export const useUserStore = defineStore('user', {
state: () => ({
token: localStorage.getItem('token') || '',
userInfo: null
}),
actions: {
async login(credentials) {
const res = await axios.post('/api/auth/login', credentials);
this.token = res.data.token;
localStorage.setItem('token', this.token);
},
async fetchUserInfo() {
const res = await axios.get('/api/user', {
headers: { Authorization: `Bearer ${this.token}` }
});
this.userInfo = res.data;
}
}
});
6. 系统部署与监控
6.1 Docker容器化部署
后端Dockerfile配置示例:
dockerfile复制FROM openjdk:17-jdk-slim
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
使用docker-compose编排服务:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:6-alpine
ports:
- "6379:6379"
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
- redis
volumes:
mysql_data:
6.2 性能监控配置
Spring Boot Actuator监控端点配置:
yaml复制management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
metrics:
export:
prometheus:
enabled: true
tags:
application: ${spring.application.name}
Grafana监控看板关键指标:
- JVM内存使用率
- 接口响应时间P99
- MySQL连接池使用情况
- Redis缓存命中率
- 推荐算法执行耗时
7. 常见问题排查指南
7.1 典型问题解决方案
问题1:推荐结果重复率高
- 原因:用户行为数据稀疏导致相似度计算偏差
- 解决方案:
- 引入时间衰减因子,降低历史行为的权重
- 混合内容推荐结果
- 添加随机扰动项
问题2:分页查询性能差
- 原因:深分页时OFFSET效率低下
- 优化方案:
sql复制-- 原始写法(性能差)
SELECT * FROM dish_info ORDER BY create_time DESC LIMIT 10000, 10;
-- 优化写法(使用游标分页)
SELECT * FROM dish_info
WHERE create_time < '2023-01-01'
ORDER BY create_time DESC
LIMIT 10;
7.2 接口调试技巧
使用Postman测试推荐接口时注意:
- 先调用/auth/login获取JWT令牌
- 在Headers中添加Authorization: Bearer
- 推荐结果缓存10分钟,需要清缓存可添加头信息Cache-Control: no-cache
测试用例示例:
http复制GET /api/dishes/recommend HTTP/1.1
Host: localhost:8080
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Cache-Control: no-cache
8. 项目扩展方向建议
-
多算法融合:结合深度学习模型提升推荐效果
- 使用TensorFlow实现Wide&Deep模型
- 引入BERT处理菜品文本描述
-
实时推荐:接入Kafka处理用户实时行为
java复制@KafkaListener(topics = "user_behavior") public void handleBehavior(BehaviorMessage message) { // 实时更新用户特征向量 recommendService.updateUserVector(message.getUserId()); } -
AB测试框架:比较不同算法效果
- 使用Redis哈希存储实验分组
- 基于Apache Doris构建指标分析平台
-
小程序端适配:通过Uniapp快速生成多端应用
- 复用现有API接口
- 调整组件库为Vant Weapp
这个项目经过多次迭代已经形成了完整的开发文档和视频教程,包含从环境搭建到算法优化的全流程指导。在实际教学中发现,学生最容易出错的是推荐算法的实现部分,需要特别注意相似度计算的边界条件处理。