毕业设计实战:基于SpringBoot+Vue的旅游推荐系统,从需求到实现全流程拆解,附避坑指南!
谁懂啊!当初做旅游推荐系统毕设时,光"协同过滤推荐算法"和"景点关联"就卡了我半个月——一开始算法没调好,结果推荐的景点全是冷门地,导师直接让我"重新设计推荐逻辑"😫 今天把从需求分析到功能实现的全流程经验分享出来,跟着做就能轻松搞定毕设!
一、先搞懂"旅游推荐系统要做什么"!需求分析是关键
刚开始我跳过需求分析就写代码,花三周做了个"深度学习推荐模型",结果导师一句"核心是景点管理、路线规划、用户互动,不是复杂算法"直接打回重改!
1. 核心用户&功能拆解(实战总结版)
旅游推荐系统有三类核心用户:管理员、普通用户,功能要区分清楚:
-
管理员端(系统管理):
- 景点管理:审核景点信息(名称、类型、门票、图片)、设置景点推荐等级
- 路线管理:设计旅游路线(景点组合、预算估算、最佳时间)、管理路线分类
- 用户管理:管理用户账号、查看用户收藏记录、分析用户偏好
- 内容管理:发布公告、审核论坛帖子、回复用户留言
- 数据统计:景点热度分析、用户活跃度统计、推荐效果评估
-
普通用户端(核心功能):
- 景点浏览:查看景点列表(按类型/热度/评分筛选)、查看景点详情(图片、门票、评价)
- 路线推荐:获取个性化旅游路线推荐、查看路线详情(景点列表、预算、时间安排)
- 互动功能:收藏景点/路线、发布景点留言/路线留言、参与论坛讨论
- 个性化推荐:基于用户浏览历史和收藏记录推荐相关景点和路线
- 个人中心:管理收藏记录、查看浏览历史、修改个人信息
2. 需求分析避坑指南(血泪教训!)
- 别闭门造车!找喜欢旅游的同学测试提意见:有同学说"想看到路线的时间安排",我才加了"路线行程表"功能
- 一定要画用例图!用DrawIO画"用户-收藏景点""系统-个性化推荐"等核心用例
- 写需求规格文档!约束条件要写清楚:"景点图片必须上传""路线预算要合理""推荐算法要可解释"
3. 可行性分析要专业
导师最爱问"可行吗",从3个角度回答:
- 技术可行:SpringBoot+Vue+MySQL+推荐算法,技术栈成熟
- 经济可行:开发工具全免费,地图API可用免费额度
- 操作可行:界面参考马蜂窝/携程,用户上手快
二、技术选型别追新!实用最重要
刚开始我用Spark+机器学习库,结果部署复杂,本地都跑不起来😫 后来换成SpringBoot+Vue2+MySQL+简单推荐算法,真香!
1. 技术栈对比(附避坑提醒)
| 技术工具 | 为什么选它 | 避坑提醒! |
|---|---|---|
| SpringBoot 2.7 | 快速开发,集成方便 | 别用3.0!生态还不完善 |
| Vue 2 | 生态成熟,Element UI好用 | 别用Vue 3组合式API!增加复杂度 |
| Element UI | 旅游类组件丰富(卡片、轮播图) | 按需引入,控制包大小 |
| MySQL 8.0 | 关系型数据存储稳定 | 一定要设计好表关联 |
| 推荐算法 | 协同过滤(简单实现) | 别用太复杂的算法,毕设够用就行 |
| ECharts | 数据可视化展示 | 用于展示旅游数据统计 |
2. 开发环境搭建
# 后端
spring init --dependencies=web,mybatis,mysql,lombok travel-recommend
# 前端
vue create travel-frontend
cd travel-frontend
vue add element
npm install axios vue-router vuex echarts
3. 架构图要画!答辩加分
用DrawIO画前后端分离+推荐引擎架构:
- 前端:Vue + Element UI + ECharts
- 后端:SpringBoot + MyBatis
- 推荐模块:基于内容的推荐 + 协同过滤
- 数据层:MySQL + Redis(缓存用户行为)
三、数据库设计:推荐算法的基础
这部分是推荐系统的核心,我当初用户行为表设计不合理,推荐效果很差。
1. 核心实体&ER图
核心表设计:
- 用户表(user):id、用户名、头像、联系方式、旅游偏好标签
- 景点表(attraction):id、名称、类型、图片、门票、地址、评分、描述
- 旅游路线表(route):id、名称、类型、预算、适合季节、行程天数、包含景点
- 收藏表(collection):id、用户ID、收藏对象ID、收藏类型(景点/路线)、收藏时间
- 浏览记录表(browse_history):id、用户ID、浏览对象ID、浏览类型、浏览时长、浏览时间
- 留言表(comment):id、用户ID、对象ID、留言类型、内容、评分、时间
- 用户偏好表(user_preference):id、用户ID、偏好标签(如:自然风光、历史遗迹、美食)、权重
2. 建表SQL示例(关键表)
-- 景点表(核心表)
CREATE TABLE `attraction` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '景点名称',
`type` int NOT NULL COMMENT '景点类型(1-自然风光,2-历史遗迹,3-城市地标,4-主题公园)',
`image` varchar(500) DEFAULT NULL COMMENT '景点图片(JSON数组)',
`ticket_price` decimal(10,2) DEFAULT NULL COMMENT '门票价格',
`address` varchar(200) DEFAULT NULL COMMENT '地址',
`province` varchar(50) DEFAULT NULL COMMENT '省份',
`city` varchar(50) DEFAULT NULL COMMENT '城市',
`latitude` decimal(10,6) DEFAULT NULL COMMENT '纬度',
`longitude` decimal(10,6) DEFAULT NULL COMMENT '经度',
`description` text COMMENT '景点描述',
`open_time` varchar(100) DEFAULT NULL COMMENT '开放时间',
`best_season` varchar(50) DEFAULT NULL COMMENT '最佳季节',
`visit_duration` int DEFAULT NULL COMMENT '建议游览时长(小时)',
`popularity` int DEFAULT 0 COMMENT '热度(基于浏览、收藏计算)',
`average_score` decimal(3,2) DEFAULT 0.00 COMMENT '平均评分',
`status` int 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_type` (`type`),
KEY `idx_city` (`city`),
KEY `idx_popularity` (`popularity`),
KEY `idx_score` (`average_score`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 旅游路线表(推荐核心)
CREATE TABLE `travel_route` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '路线名称',
`type` int NOT NULL COMMENT '路线类型(1-经典线路,2-深度游,3-亲子游,4-背包客)',
`budget` decimal(10,2) NOT NULL COMMENT '预算估算',
`days` int NOT NULL COMMENT '行程天数',
`suitable_season` varchar(100) DEFAULT NULL COMMENT '适合季节',
`cover_image` varchar(200) DEFAULT NULL COMMENT '封面图',
`description` text COMMENT '路线描述',
`attraction_ids` varchar(500) NOT NULL COMMENT '包含景点ID(JSON数组)',
`attraction_names` varchar(1000) DEFAULT NULL COMMENT '包含景点名称(用于展示)',
`day_plan` text COMMENT '每日行程安排(JSON)',
`view_count` int DEFAULT 0 COMMENT '浏览次数',
`collect_count` int DEFAULT 0 COMMENT '收藏次数',
`average_score` decimal(3,2) DEFAULT 0.00 COMMENT '平均评分',
`status` int DEFAULT 1 COMMENT '状态(1-正常,0-下架)',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_type` (`type`),
KEY `idx_days` (`days`),
KEY `idx_budget` (`budget`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 用户行为表(推荐算法基础)
CREATE TABLE `user_behavior` (
`id` int NOT NULL AUTO_INCREMENT,
`user_id` int NOT NULL COMMENT '用户ID',
`item_id` int NOT NULL COMMENT '项目ID(景点或路线)',
`item_type` int NOT NULL COMMENT '项目类型(1-景点,2-路线)',
`behavior_type` int NOT NULL COMMENT '行为类型(1-浏览,2-收藏,3-评论,4-评分)',
`behavior_value` decimal(3,2) DEFAULT NULL COMMENT '行为值(如评分)',
`duration` int DEFAULT NULL COMMENT '停留时长(秒)',
`behavior_time` datetime NOT NULL COMMENT '行为时间',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_user_item` (`user_id`,`item_id`,`item_type`),
KEY `idx_user_behavior` (`user_id`,`behavior_type`),
KEY `idx_item_behavior` (`item_id`,`item_type`,`behavior_type`),
KEY `idx_time` (`behavior_time`),
CONSTRAINT `fk_behavior_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 收藏表(用户偏好分析)
CREATE TABLE `collection` (
`id` int NOT NULL AUTO_INCREMENT,
`user_id` int NOT NULL COMMENT '用户ID',
`item_id` int NOT NULL COMMENT '收藏项目ID',
`item_type` int NOT NULL COMMENT '收藏类型(1-景点,2-路线)',
`collection_time` datetime NOT NULL COMMENT '收藏时间',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_user_item` (`user_id`,`item_id`,`item_type`),
KEY `idx_user` (`user_id`),
KEY `idx_item` (`item_id`,`item_type`),
CONSTRAINT `fk_collection_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3. 推荐算法设计(毕设够用版)
方案一(简单版):基于热度的推荐
-- 热门景点推荐(按收藏数+评分)
SELECT a.*,
(a.popularity * 0.6 + a.average_score * 100 * 0.4) as recommend_score
FROM attraction a
WHERE a.status = 1
ORDER BY recommend_score DESC
LIMIT 10;
方案二(进阶版):基于内容的推荐
// 根据用户收藏的景点类型推荐相似景点
public List contentBasedRecommend(Integer userId) {
// 1. 获取用户收藏的景点
List collectedAttractionIds = collectionMapper.selectCollectedAttractions(userId);
// 2. 分析用户偏好类型
Map typePreferences = new HashMap<>();
for (Integer attractionId : collectedAttractionIds) {
Attraction attraction = attractionMapper.selectById(attractionId);
typePreferences.merge(attraction.getType(), 1, Integer::sum);
}
// 3. 按偏好类型推荐(排除已收藏的)
List preferredTypes = typePreferences.entrySet().stream()
.sorted(Map.Entry.comparingByValue().reversed())
.map(Map.Entry::getKey)
.collect(Collectors.toList());
return attractionMapper.selectRecommendByTypes(
preferredTypes,
collectedAttractionIds,
10
);
}
方案三(高级版):协同过滤推荐
// 基于用户的协同过滤(简化版)
public List collaborativeFilteringRecommend(Integer userId) {
// 1. 找到相似用户(收藏了相同景点)
List similarUserIds = collectionMapper.findSimilarUsers(userId, 5);
// 2. 获取相似用户收藏但当前用户未收藏的景点
List collectedAttractionIds = collectionMapper.selectCollectedAttractions(userId);
// 3. 计算推荐分数(基于相似用户的收藏数)
Map attractionScores = new HashMap<>();
for (Integer similarUserId : similarUserIds) {
List similarUserCollections = collectionMapper.selectCollectedAttractions(similarUserId);
for (Integer attractionId : similarUserCollections) {
if (!collectedAttractionIds.contains(attractionId)) {
attractionScores.merge(attractionId, 1, Integer::sum);
}
}
}
// 4. 按分数排序返回
return attractionScores.entrySet().stream()
.sorted(Map.Entry.comparingByValue().reversed())
.limit(10)
.map(entry -> attractionMapper.selectById(entry.getKey()))
.collect(Collectors.toList());
}
四、功能实现:核心模块详解
1. 个性化推荐模块(必做!亮点)
推荐策略组合:
- 新用户:热门推荐 + 地域推荐
- 老用户:协同过滤 + 基于内容推荐
- 实时推荐:基于当前浏览记录
实现代码示例:
@Service
public class RecommendationService {
@Autowired
private AttractionMapper attractionMapper;
@Autowired
private CollectionMapper collectionMapper;
@Autowired
private UserBehaviorMapper userBehaviorMapper;
// 综合推荐入口
public List getRecommendations(Integer userId, String city) {
List recommendations = new ArrayList<>();
// 检查用户是否有行为记录
boolean hasBehavior = userBehaviorMapper.hasUserBehavior(userId);
if (!hasBehavior) {
// 新用户推荐:热门 + 同城
recommendations.addAll(getPopularRecommendations(city, 5));
recommendations.addAll(getLocalRecommendations(city, 5));
} else {
// 老用户推荐:协同过滤 + 基于内容
recommendations.addAll(getCollaborativeFilteringRecommendations(userId, 6));
recommendations.addAll(getContentBasedRecommendations(userId, 4));
}
// 去重并返回
return recommendations.stream()
.distinct()
.limit(10)
.collect(Collectors.toList());
}
// 热门推荐
private List getPopularRecommendations(String city, int limit) {
return attractionMapper.selectPopularByCity(city, limit);
}
// 同城推荐
private List getLocalRecommendations(String city, int limit) {
return attractionMapper.selectByCity(city, limit);
}
// 更多推荐方法...
}
2. 旅游路线规划模块(核心功能)
路线生成逻辑:
- 用户选择兴趣点(自然风光、美食、购物等)
- 系统推荐匹配的景点
- 根据地理位置和开放时间智能排序
- 生成合理的行程安排和预算估算
路线详情数据结构:
{
"id": 1,
"name": "北京经典三日游",
"days": 3,
"budget": 1500.00,
"dayPlan": [
{
"day": 1,
"title": "皇家园林之旅",
"attractions": [
{"id": 1, "name": "故宫", "duration": 4, "time": "09:00-13:00"},
{"id": 2, "name": "景山公园", "duration": 2, "time": "14:00-16:00"}
],
"transport": "地铁1号线",
"tips": "故宫需提前预约"
}
]
}
3. 景点详情展示模块
功能要点:
- 图片轮播展示
- 基本信息(门票、开放时间、地址)
- 地图位置展示(集成百度/高德地图)
- 用户评价和评分
- 相关推荐(相似景点、组合路线)
前端实现:
<div class="attraction-detail">
<img src="img" class="carousel-image"/>
<div class="basic-info">
<h1>{{ attraction.name }}</h1>
<div class="tags">
{{ attraction.typeName }}
门票¥{{ attraction.ticketPrice }}
免费
</div>
{{ isCollected ? '已收藏' : '收藏' }}
</div>
<div class="map-section">
<h3>位置信息</h3>
<div id="map-container"></div>
</div>
<div class="recommendations">
<h3>猜你喜欢</h3>
</div>
</div>
4. 用户行为分析模块
行为收集:
// 用户行为埋点
@PostMapping("/trackBehavior")
public Result trackBehavior(@RequestBody UserBehaviorDTO dto) {
UserBehavior behavior = new UserBehavior();
behavior.setUserId(dto.getUserId());
behavior.setItemId(dto.getItemId());
behavior.setItemType(dto.getItemType());
behavior.setBehaviorType(dto.getBehaviorType());
behavior.setBehaviorValue(dto.getValue());
behavior.setDuration(dto.getDuration());
behavior.setBehaviorTime(new Date());
userBehaviorMapper.insert(behavior);
// 实时更新景点热度
if (dto.getItemType() == 1) { // 景点
attractionMapper.incrementPopularity(dto.getItemId());
}
return Result.success("行为记录成功");
}
五、前端页面设计要点
1. 首页设计
- 搜索框:支持景点/路线搜索,支持城市筛选
- 轮播图:推荐热门景点和路线
- 推荐区域:个性化推荐卡片展示
- 分类导航:按景点类型快速筛选
2. 景点列表页
- 筛选器:按类型、门票价格、评分、距离筛选
- 排序:默认按热度,支持按评分、价格排序
- 展示模式:列表模式/网格模式切换
- 分页加载:滚动加载更多
3. 路线推荐页
- 路线筛选:按天数、预算、适合人群筛选
- 行程预览:展示路线概览(景点数量、总预算)
- 一键收藏:收藏感兴趣的路线
- 行程详情:点击查看详细行程安排
4. 个人中心页
- 我的收藏:景点收藏、路线收藏分开展示
- 浏览历史:最近浏览记录,可清除
- 推荐偏好:展示系统分析的用户偏好标签
- 个人信息:头像、昵称、旅游偏好设置
六、测试:这些场景必须测!
1. 功能测试用例
表1:推荐功能测试
| 测试场景 | 操作步骤 | 预期结果 |
|---|---|---|
| 新用户访问 | 新注册用户访问首页 | 看到热门景点和本地推荐 |
| 收藏后推荐 | 用户收藏几个自然景点 | 推荐更多自然类景点 |
| 浏览行为影响 | 用户浏览多个历史遗迹 | 推荐相关历史景点 |
表2:路线规划测试
| 测试场景 | 操作步骤 | 预期结果 |
|---|---|---|
| 生成路线 | 选择兴趣点生成路线 | 路线包含相关景点,时间安排合理 |
| 路线收藏 | 收藏一条路线 | 在个人中心能看到收藏 |
| 路线分享 | 点击分享按钮 | 生成分享链接或二维码 |
2. 性能测试
- 推荐响应时间:推荐算法应在500ms内返回结果
- 并发访问:模拟100个用户同时访问景点详情页
- 大数据量:测试10000个景点数据时的查询性能
3. 推荐效果评估(加分项)
- 准确率:推荐内容与用户实际兴趣的匹配度
- 覆盖率:推荐系统能覆盖多少景点/路线
- 新颖性:推荐的景点/路线是否多样
七、部署与答辩准备
1. 项目打包部署
# 后端打包
mvn clean package -DskipTests
# 前端打包
npm run build
# 部署
# 1. 上传jar包和dist文件夹
# 2. 导入SQL脚本(含测试数据)
# 3. 启动后端服务
# 4. 配置Nginx反向代理
2. 答辩准备(3个加分技巧)
-
演示流程要生动:
- 用户注册→设置偏好→查看个性化推荐
- 浏览景点→收藏→查看推荐变化
- 规划路线→查看行程安排
-
重点讲技术亮点:
- 推荐算法的设计与实现(展示算法逻辑图)
- 用户行为数据的收集与分析
- 路线规划的智能算法
-
准备常见问题:
- Q:推荐算法怎么实现的? A:采用混合推荐策略,新用户用热门推荐,老用户用协同过滤+基于内容推荐
- Q:如何保证推荐准确性? A:①收集用户行为数据 ②定期评估推荐效果 ③支持用户反馈
- Q:系统如何扩展? A:①推荐算法可替换 ②支持插件化推荐策略 ③数据存储可分库分表
八、毕设文档结构
旅游推荐系统/
├── 毕业论文.docx # 完整论文(含算法章节)
├── 开题报告.docx # 研究背景、创新点
├── 中期检查表.docx # 进度汇报
├── 源码/
│ ├── backend/ # SpringBoot后端
│ ├── frontend/ # Vue前端
│ ├── algorithm/ # 推荐算法实现
│ └── database/ # 数据库脚本
├── 演示视频.mp4 # 10分钟功能演示(重点展示推荐)
├── 答辩PPT.pptx # 15分钟答辩展示
└── 算法说明文档.md # 推荐算法详细说明
最后:真心话时间
旅游推荐系统是技术含量较高的毕设选题,能很好展示你的算法能力和工程能力。关键是推荐算法要设计合理,用户交互要友好,数据可视化要做好。
需要完整源码(含推荐算法实现)、数据库脚本(含旅游测试数据)、答辩PPT模板的同学,评论区扣"旅游推荐",我发你。遇到具体技术问题(比如推荐算法、地图集成),也可以留言讨论!
这篇干货整理了我所有经验教训,点赞收藏,毕设路上不迷路!祝大家顺利毕业!🏞️✨