基于SpringBoot的旅游景点推荐系统:协同过滤算法与毕设实战全解析

发布时间:2026/10/1 18:33:17
基于SpringBoot的旅游景点推荐系统:协同过滤算法与毕设实战全解析 每年到了2月到5月这个时间段我后台私信就会被同一类问题塞满“博主毕设选题有没有推荐”“SpringBoot做什么题目好过”“有没有带推荐算法的项目可以抄”今年情况更夸张2026届的师弟师妹们好像提前半年就开始焦虑了。今天抽空把这段时间问得最多的一个题目拆开揉碎讲清楚——基于SpringBoot的旅游景点推荐系统。这个题目之所以每年都能杀进“最受欢迎毕设榜单”不是因为名字多fancy而是它完美踩中了毕设评审的几个关键得分点后端用的是一线互联网公司主流的SpringBoot技术栈、算法部分有可展示的“智能推荐”亮点、数据模型设计有足够的关联复杂度、前端交互有完整的用户场景。无论你是打算直接照着做一个、拿源码二次开发还是只参考它的设计思路套到自己题目里这篇内容都能帮你省下至少两周的摸索时间。先说清楚这个系统到底是干什么的。它不是一个简单的景点信息管理CRUD而是一个完整的C端产品游客进入系统后可以看到景点列表、搜索景点、查看详情和评论系统会根据用户的浏览行为、收藏记录和评分数据在“为你推荐”板块动态生成个性化的景点列表。管理员端则负责景点信息、用户管理、评论审核、推荐参数配置等后台操作。这套逻辑拆开看就是一个典型的SpringBoot 推荐算法 管理后台的全栈项目技术含量刚好够毕设评审的标准又不至于难到无法完成的地步。我实际看过这套编号14052的项目源码和配套文档整体做得比较完整下面我把它的核心设计、实现思路、代码细节和容易踩的坑全部梳理出来。1. 项目整体设计与思路拆解1.1 为什么毕设选题偏爱这个方向先聊一个比较实际的问题为什么旅游景点推荐系统能在一堆毕设题目里被反复选中而且通过率普遍不错我自己指导过多次毕业设计答辩也担任过企业导师参与过一些校企合作项目的结题评审从评审视角来看这个题目有几个天然的“保命优势”。第一业务背景不需要编造。旅游本身就是人人都能理解的生活场景评委不需要你费半天口舌解释“这个系统解决了什么痛点”。你只需要说“游客面对海量景点信息容易陷入选择困难系统通过协同过滤算法做个性化推荐”这句话放到哪个答辩现场都不会冷场而且评委一听就知道你做的是真实需求不是所谓的“课程设计管理系统”“图书馆管理系统”这种陈年烂梗。第二技术栈覆盖密度高。这个题目天然要求你把SpringBoot、MyBatis、Redis、Vue或Thymeleaf、推荐算法、拦截器登录鉴权、文件上传、异常处理、日志打印全部串起来。大部分毕设题目要么偏重前端展示、后端只是挂数据的桩子要么重后端业务、前端就是一个打死都不带响的管理界面。而这个题目两侧都有看头用户侧要体现推荐效果管理侧要体现数据维护能力。第三可扩展空间充足。系统内置了协同过滤但你完全可以把推荐模块替换成基于内容、基于标签权重、基于热门度的时间衰减推荐也可以叠加地理位置推荐。这种“可升级性”拿到答辩现场说就是加分项“我这套目前的推荐精度在离线数据集上达到XX%后续可以引入深度学习模型做实时序列推荐”——哪怕你只是聊聊思路评委也会觉得你有思考深度。第四数据治理价值容易被忽略但非常加分。旅游景点数据往往带有图片、坐标、费用区间、主题标签文化/自然/亲子/刺激、适合季节等多维属性。这意味着你的数据库字段形态丰富做查询时有复杂的过滤条件和多表关联场景实验过程中还可以引入真实公开旅游数据集例如各个城市景点的开放API数据来做填充演示。1.2 核心功能模块与系统角色拆解完整的旅游景点推荐系统一般拆成前台门户和后台管理两块用户角色分为普通用户、管理员有时还可以细分超级管理员和景点运营人员。每个角色的功能边界要划分清楚这直接决定后续数据库表结构和接口文档的写法。普通用户端核心功能注册与登录验证码校验、用户名唯一性校验、密码MD5加密游客浏览景点列表支持分页、按省份/城市筛选、按主题标签筛选、按价格区间筛选、按评分排序景点详情页轮播图展示、景点介绍、票务价格、开放时间、地图坐标、用户评价列表收藏功能与取消收藏对景点进行评分与评论评分范围通常1到5星推荐模块基于用户历史行为生成个性化推荐列表包括“猜你喜欢”“相似景点推荐”“热门推荐全局热度”个人中心查看新建收藏记录、历史评分、修改密码、维护个人信息管理员端核心功能登录鉴权与用户表分开独立管理员表景点信息管理增删改查、图片上传、上下架状态管理景点类别管理主题标签的增删改查用户管理查看用户列表、禁用/启用账号评论与评价管理查看、审核、删除敏感评论推荐参数配置设置推荐列表大小、协同过滤算法中的相似度TopN值、热门推荐按时间窗口计算天数等数据统计景点浏览排行、用户活跃度、评分分布通常会配几个图表页面从这里你可以看到这个系统的业务闭环非常清楚从用户产生行为数据到系统分析行为、产出推荐结果再回到用户端展示推荐列表。整个数据链条是流动的这一点在论文的“系统设计——核心业务流程图”里会非常好画。1.3 技术方案选型为什么偏偏是这套组合被问到最多的一个问题“学长为什么非要用SpringBoot我用SSHStruts2SpringHibernate行不行我JSP写得熟就不用前后端分离了行不行”技术选型直接影响毕设含金量和答辩评分。我直接说结论用SpringBoot别再用SSH了。SpringBoot在2026年已经是Java后端开发的绝对事实标准BAT一线互联网公司到中小型企业都在用。SSH那套XML配置堆成山的古董技术栈除非你学校的毕设要求里明确指定这种概率极低否则你把SSH写进论文遇到懂行的年轻评委第一印象分就下来了。SpringBoot的好处就是起步快、约定大于配置、生态无敌你用在毕设里是顺应技术趋势。持久层框架选MyBatis还是MyBatis-Plus我的结论是只要不是学校强制要求写原生XML映射首选MyBatis-Plus。它的BaseMapper帮你把单表CRUD全部内置了简单的接口操作不用写SQL项目开发周期直接压缩三分之一推荐模块中需要手写复杂SQL的地方再写XML也不迟。前端层面2026年做前后端分离几乎是大势所趋。前端用Vue 3 Element Plus已经是主流标配替代方案是Vue 2 Element UI老项目多或者后端模板引擎Thymeleaf想要省事的同学选这个也行。我见过大量用Thymeleaf做简单交互的毕设也拿了不错的中上评分关键是页面不要做得太丑、功能闭环要完整。数据库用MySQL 8.x这个没有争议。如果本地没装MySQL也可以用MySQL 5.7但建议直接上8.0窗口函数等特性在写统计类SQL时真的爽。Redis不是必选但强烈建议加。最直接的收益不光是性能而是答辩时你多了一条技术亮点比如“我把热门景点列表缓存到Redis并设置过期时间当景点浏览量发生变化时主动更新缓存降低MySQL压力”。哪怕是模拟数据量下看不出性能差异这个设计思想本身就是答辩加分点。如果不想在Redis上花费太多精力也完全可以把缓存模块做成可开关的配置项复杂度可控。权限认证用JWT还是Session毕设项目强烈推荐用JWT做无状态登录认证尤其在前后端分离架构下JWT跟随请求头带token避免跨域Session共享问题。这也是面试时SpringBoot相关岗位必问知识点你做了这个就有实战经验。不过要理解JWT的核心边界它适合做登录态保持不适合做服务端主动吊销所以管理员禁用一个用户时若用户已持有有效token可能仍需等token过期才失效这点在答辩中如果被问到要能自圆其说比如引入token黑名单机制。不推荐过度设计。微服务、Spring Cloud、消息队列、分布式事务这些词听着唬人但放在毕设就是给自己挖坑。一个单体SpringBoot应用模块划分清晰代码量控制在8000到12000行左右已经是中等偏上的量级。你的重点是“推荐算法能不能跑通”“核心业务有没有闭环”不是“系统拆了几个微服务”。这套技术方案选下来本质就是在“工作量适中”和“技术亮点充沛”之间找一个黄金分割点。2. 数据库设计与推荐算法落地思路2.1 核心数据表结构与关联关系数据库设计是整个项目的地基。很多同学上来就直接写代码写到第三天才发现表结构设计错了推荐算法没法写SQL又要推倒重来。我建议第一步就是老老实实把表结构设计完整。以这个项目为例核心表至少有这些表名主要字段说明userid, username, password, nickname, avatar, email, phone, status, create_time普通用户表密码存MD5或加盐哈希adminid, username, password, real_name, role, last_login_time管理员表与用户表分开scenic_areaid, name, cover_image, images, description, province, city, address, longitude, latitude, ticket_price, open_time, rating, theme, status, browse_count, create_time景点表核心信息表和推荐系统的主数据源scenic_themeid, name, description主题标签表如自然风光、人文历史、亲子游、极限运动等scenic_area_themescenic_id, theme_id景点和主题的多对多关联表user_favoriteid, user_id, scenic_id, create_time用户收藏表user_ratingid, user_id, scenic_id, rating, comment, create_time用户评分评论表browse_historyid, user_id, scenic_id, browse_time, duration用户浏览历史表推荐行为数据源之一recommendation_logid, user_id, scenic_ids, recommend_time, recommend_type推荐结果日志方便展示“推荐依据”noticeid, title, content, create_time系统公告表可选项表结构设计时有几个细节需要注意用户评分和用户评论建议放同一张表避免多张表导致数据一致性难维护。用户在详情页打分并提交评论一次事务同时写入评分字段和评论字段默认未评论时comment为空即可。如果你硬要把评分和评论拆成两张表联查和统计都会变得很繁琐。景点图片字段建议存JSON字符串或逗号分隔的URL列表不要为了一张图建一张景点图片表。毕设项目用JSON字段配合TypeHandler转换为List 写代码效率高存图片管理简单。浏览历史表建议加索引(user_id, scenic_id)因为最终要基于这个表算用户之间的相似度没索引跑全表扫描会拖到怀疑人生。经纬度字段类型用DECIMAL(10, 6)精确到6位小数大约能支持到米级精度将来你要做基于距离的推荐直接拿这个字段算Haversine距离不会丢精度。考虑数据保留完整性当你执行删除景点操作时收藏表、浏览记录表的外键级联策略要设计好。最简单稳妥的方案是“物理删除改逻辑删除”给景点表加一个status字段0下架/1上架删除本质是更新状态。这个设计非常加分因为真实生产系统都是这么做的。2.2 协同过滤推荐算法从原理到公式这应该是这个系统最受关注的“智能部分”我单独说一下。旅游景点推荐场景下最常用的是基于用户的协同过滤UserCF和基于物品的协同过滤ItemCF。不夸张地说80%的毕设推荐系统题你都绕不开这两种方案。基于用户的协同过滤核心逻辑找到和我兴趣相似的用户把他们喜欢的、我没去过/没看过的景点推荐给我。步骤拆开构建“用户—景点”评分矩阵行为数据可以是用户对景点的评分值也可以是浏览次数、收藏次数这些隐式反馈。计算用户之间的相似度最常用的是余弦相似度。对每个目标用户找出TopN最相似的邻居用户。根据邻居用户的行为数据预测目标用户未接触过的景点的偏好分数。取出偏置分数最高的K个景点作为推荐结果。基于物品的协同过滤核心逻辑先看你对哪些景点感兴趣然后找到和你感兴趣景点最相似的其他景点推荐给你。步骤拆开构建“景点—用户”反查表计算景点之间的相似度同时被大量用户收藏/评分过的两个景点相似度高。根据用户的历史正反馈物品列表找出相似的候选物品集合。加权求和过滤掉已交互物品生成TopK推荐。在人少地广的景点推荐场景我更推荐以ItemCF为主因为景点推荐的数据实体相对稳定物品之间的相似度可解释性强“你去过故宫所以推荐同样属于人文历史主题的天坛”而且实时计算压力小。UserCF更适合新闻、社区这类内容海量更新、用户兴趣漂移快的场景。你可以把两种算法都实现然后在代码里做一个推荐策略切换开关这个也是答辩亮点的常规打法。相似度计算的数学公式余弦相似度是必须掌握的sim(u1, u2) (u1向量 · u2向量) / (|u1向量| * |u2向量|)这里稍微展开说一个最常见的数据陷阱用户和景点的矩阵极其稀疏绝大多数用户在系统里只有一两次行为。如果两个用户之间共同评分的景点只有一个或两个算出来的相似度会虚高。所以实现协同过滤时一定要加一个过滤条件共同行为的景点数量至少大于等于N例如N2或3再参与相似度计算否则直接过滤掉视为无参考价值的弱相似关系。这个细节不写进论文里但答辩被问“如何处理数据稀疏问题”时有一个已经落地的过滤策略非常加分。另外预测评分的时候不要只用邻居的平均分直接推推荐采用加权平均公式pred(user, scenic) sum(sim(user, neighbor) * rating(neighbor, scenic)) / sum(sim(user, neighbor))中心思想是让相似度高的邻居说话权重大相似度低的邻居不拖后腿。这是你能在论文里写清楚、写好、大段展开的核心公式。2.3 冷启动问题的处理方案与代码实现冷启动问题是所有推荐系统新手绕不开的第一道坎。新用户进来没有任何行为数据算相似度时矩阵稀疏到极值UserCF直接输出空列表。如果不处理演示环节就会出现“收藏了五六个景点再刷新推荐页结果啥都没有”的尬演现场。标准的做法是用一个多策略推荐的兜底方案新用户或行为数据不足的用户走热门推荐。SQL直接按景点browse_count和评分加权排序取前10个展示。注意做时间衰减用一个简单的时间窗口比如30天内浏览量加权防止一个热门景点因为历史优势常年霸榜新景点永无出头之日。这也是一个能在论文中展开描述的优化点。注册时选兴趣标签然后基于内容推荐根据用户所选主题标签文化/自然/亲子等匹配景点。用户访问详情页时采用关联推荐“看过这个景点的用户还看了哪些景点”这个本质上就是一次ItemCF快速实时计算按同景点的其他用户行为日志聚合即可。写一个推荐策略的骨架伪代码你们感受一下public interface RecommendStrategy { ListScenicArea recommend(Long userId, int size); } // 策略一基于协同过滤 Component public class CollaborativeFilterStrategy implements RecommendStrategy { Override public ListScenicArea recommend(Long userId, int size) { // 判断行为数据丰富度不足直接返回空让路由层降级 return ...; } } // 策略二基于热门数据的冷启动兜底 Component public class HotRankStrategy implements RecommendStrategy { Override public ListScenicArea recommend(Long userId, int size) { // 简单实现按浏览数评分权重排名时间衰减加权 return ...; } } // 策略三基于用户画像标签的内容推荐 Component public class ContentBasedStrategy implements RecommendStrategy { Override public ListScenicArea recommend(Long userId, int size) { // 从用户表读取兴趣标签按标签匹配景点 return ...; } }然后在Service层写一个推荐分发器根据用户行为数据的条数自动选择策略public ListScenicArea getRecommendList(Long userId, int size) { int behaviorCount userBehaviorMapper.countBehaviorByUserId(userId); if (behaviorCount 5) { // 行为数据充足启用协同过滤 return collabStrategy.recommend(userId, size); } // 行为数据不足走热门/标签兜底 return hotRankStrategy.recommend(userId, size); }这套策略分层看起来简单但它把一个“算法模型”问题变成了“工程路由”问题推荐系统工程师在实际生产环境中也是类类似的架构思路。3. 后端接口实现与核心代码细节3.1 SpringBoot后端代码结构怎么组织项目代码结构直接反映编码习惯这是评委翻阅你源码时最先看的部分。毕设项目去一个小的商用工程推荐按“controller / service / mapper / entity / dto / vo / config / common”分层。一个清晰的目录结构大致长这样com.example.travelrecommend ├── common │ ├── result (ResultT通用返回体) │ ├── exception (业务异常与全局异常处理) │ └── constant ├── config │ ├── WebMvcConfig │ ├── CorsConfig │ ├── RedisConfig │ └── Knife4jConfig (接口文档配置) ├── controller │ ├── user (用户端接口) │ ├── admin (后台管理接口) │ └── recommend (推荐相关接口) ├── service │ ├── impl │ └── strategy (推荐策略模块) ├── mapper ├── entity ├── dto (接收前端参数) └── vo (返回前端视图对象)接口文档工具强烈建议集成Knife4j基于Swagger的重大增强。它自动生成接口文档你调试时直接在浏览器里点按钮就能调用接口测试省时省力。答辩的时候还可以演示“我是如何管理和测试接口的”这能让好几位懒得不写接口文档的同学当场破防。3.2 推荐算法核心代码实现我直接给出一段核心实现基于MyBatis-Plus和Java 8 Stream目标是只写23行代码完成基于用户的协同过滤中最核心的相似用户查找部分// 1. 查出目标用户的行为记录 ListUserBehavior behaviors userBehaviorMapper.selectByUserId(userId); // 2. 取出该用户交互过的景点ID列表 SetLong visitedScenicIds behaviors.stream() .map(UserBehavior::getScenicId) .collect(Collectors.toSet()); if (visitedScenicIds.size() 3) { return Collections.emptyList(); // 行为数据太少让上层走兜底 } // 3. 根据这些景点ID找出其他行为重合的用户 ListLong similarUserIds userBehaviorMapper.selectUserIdsByScenicIds(visitedScenicIds, userId); // 4. 已交互景点中显示出评过分的更高权重用户 ListSimilarUserVO similarUsers similarUserIds.stream().map(similarUserId - { // 计算两者共同交互景点数 long common userBehaviorMapper.countCommonScenicIds(userId, similarUserId); // 用Jaccard相似系数换算分数 double score (double) common / (visitedScenicIds.size() userBehaviorMapper.countScenicIdsByUserId(similarUserId) - common); return new SimilarUserVO(similarUserId, common, score); }).sorted(Comparator.comparingDouble(SimilarUserVO::getScore).reversed()) .limit(10) .collect(Collectors.toList()); // 5. 汇总邻居用户交互过但目标用户未交互过的景点作为候选集 ListLong candidateScenicIds userBehaviorMapper.selectScenicIdsByUserIds( similarUsers.stream().map(SimilarUserVO::getUserId).collect(Collectors.toList())); candidateScenicIds.removeAll(visitedScenicIds); // 6. 按候选景点在邻居群体中评分的加权聚合排序上面这是简化版本实际项目中还会考虑评分值、浏览时长权重等丰富维度。核心思路是不要一上来就上高大上的Embedding、Graph Neural Network先把基于行为的统计逻辑跑通让推荐结果可以解释再去谈优化元素。评审老师更看重你对基础算法的理解和实现能力而不是盲目背大模型概念。3.3 接口设计规范与统一返回体接口设计的好坏是背后代码优雅程度的直接映射。毕设项目最忌讳一个接口返回一个乱糟糟的Map前端拿数据全靠猜。我做这个项目时从第一个接口开始就强制使用统一返回体ResultTpublic class ResultT implements Serializable { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(success); result.setData(data); return result; } public static T ResultT error(String message) { ResultT result new Result(); result.setCode(500); result.setMessage(message); return result; } }一个标准推荐接口大概长这样GET /api/recommend/personal?size10 Headers: Authorization: Bearer eyJhbGciOiJIUzI1NiJ9... 响应体示例: { code: 200, message: success, data: [ { scenicId: 12, scenicName: 故宫博物院, coverImage: https://xxx.com/image/12.jpg, theme: 人文历史, rating: 4.8, reason: 因为你收藏了天坛公园所以向你推荐同为主题“人文历史”的景点 } ] }这个“reason”字段是很多同学忽略但实际非常关键的细节。系统可以在推荐结果里展示推荐解释让用户感觉推荐不是瞎推的。生产环境里推荐系统解释性一直是个重要话题你把字段加到推荐VO里无论演示还是答辩都会让人眼前一亮。4. 前端页面交互与项目演示要点4.1 前端选型与页面设计如果你选了前后端分离体系前端技术栈建议直接Vue 3 Vite Element Plus Axios Pinia。如果是为了应对毕业设计“时间紧任务重”的实际情况也可以直接下载一个现成的后台管理模板比如vue-element-admin的生态然后自己定制化页面。前台门户用户端重点页面有首页顶部Banner轮播图、搜索框、热门景点推荐瀑布流、个性化推荐区块景点列表页左侧筛选器省份、主题、价格区间、排序方式、右侧景点卡片列表景点详情页图片画廊、核心信息卡片、评分模块、评论列表个人中心页我的收藏、我的评分记录、我的浏览足迹登录/注册页组件后台管理页面相对模板化布局基本上就是左侧菜单、右侧表格再加上“新增/编辑弹窗表单”。真正花功夫的是交互细节收藏按钮点击后立即改变状态并弹出提示、评分用鼠标选择星级、头像上传实时预览、列表分页参数实时同步URL刷新地址栏。4.2 关键技术点Axios拦截器与路由守卫前端集成时有一个点需要额外说明就是Axios请求拦截器统一携带JWT token以及Vue Router的路由守卫做登录验证。很多毕设项目前后端因为协同不好经常出现用户明明没登录却能在页面看到个人信息接口返回数据的情况或者token过期后前端还继续发请求后端连环报500。这两个问题最佳实践如下// axios 请求拦截器 service.interceptors.request.use(config { const token localStorage.getItem(token); if (token) { config.headers[Authorization] Bearer token; } return config; }); // 路由前置守卫 router.beforeEach((to, from, next) { const token localStorage.getItem(token); if (to.meta.requiresAuth !token) { next({ path: /login, query: { redirect: to.fullPath } }); } else { next(); } });不夸张地说能不能把这两个机制写通直接决定了项目联调阶段你是在享受开发还是在给前端姐姐打工。5. 系统部署打包与验收演示准备5.1 从代码到可运行项目的完整流程写完代码只是完成了第一步毕设验收需要你把系统完整跑起来。这里包括本地MySQL数据库的初始化、Redis启动如果用了、SpringBoot项目的打包部署、前端项目的构建产物部署。推荐的做法是把项目和部署步骤都写进README方便换电脑演示时快速恢复环境。后端打包mvn clean package -DskipTests java -jar target/travel-recommend-0.0.1.jar --spring.profiles.activeprod前端构建npm run build # 构建产物在dist目录可以直接扔给nginx托管或者用python -m http.server临时托管做局域网演示说到部署之前有同学问过“SpringBoot jar能不能反编译成源码重新导入工程来修改”——实际上如果拿到的源码本身就是完整的不需要反编译。反编译一般是应急用的比如原始源码丢失我个人的经验是毕设源码尽量保留整套SQL初始化脚本、后端完整工程、前端完整工程、README部署文档这四样缺一不可。换电脑、换版本、换开发环境的时候能重建出来的项目才是真正属于你的作品。5.2 演示环境准备与数据填充技巧答辩演示最尴尬的瞬间不是系统报错而是界面空空如也——只有三个景点、五个用户的系统根本没法展示推荐算法的效果。我建议最少准备30到40个真实景点数据、20个模拟用户、几百条评分收藏记录。不要手动一条条录写一个数据初始化脚本用Java的CommandLineRunner或者SQL文件批量插入都可以统一生成模拟数据。推荐数据的生成上有一些思路可以参考设计五六个虚拟用户画像例如“喜欢文化和历史的用户A”“喜欢自然风光和徒步的用户B”“带娃亲子游的用户C”。按照画像给每个用户生成相应的评分行为偏好主题的景点给高分4到5分无关主题的给低分1到2分或不产生行为。保证用户之间有一定的偏好重合度否则协同过滤算不出任何相似用户推荐效果就会直接崩坏。答辩演示时按顺序展示新用户入口出现热门推荐冷启动兜底→ 登录一个行为丰富的用户去看他的收藏和过往记录 → 点开首页“为你推荐”对比推荐结果和用户画像标签是否吻合 → 给一个新景点打分刷新推荐列表观察推荐排序变化。这一套流程走完评委对系统的完整性和智能性就有了直观感受。6. 常见问题与排查技巧实录6.1 新手最容易踩的坑JWT过期时间问题JWT无状态特性导致服务端无法主动让token失效建议access token过期时间设短比如30分钟再配合前端逻辑后端返回401时Axios响应拦截器自动跳转登录页重新登录逻辑上是通顺的。跨域请求被拦截前后端分离开发时前端跑localhost:5173后端跑localhost:8080浏览器默认会拦截跨域请求。解决方案就是后端加一个CORS全局配置允许指定前端来源地址不要图省事直接用“*”否则携带着Authorization头一起飞的时候会出问题。要是用了Spring SecurityCORS还要和Security过滤链配合好。并发访问时浏览数不准确如果直接用update scenic_area set browse_count browse_count 1高并发下还是可能丢数据这就是为什么建议追加Redis缓存。最简方案用户访问详情页时先自增Redis计数数据定期从Redis刷新到MySQL。数据库连接超时如果项目跑了一段时间后报Communications link failure多半是MySQL的wait_timeout默认8小时空闲连接被切断而连接池没有回收旧连接。配置里max-lifetime调短一点就能解决。图片上传路径问题本地开发时经常会把图片存到工程目录下但打包成jar部署后写到临时目录或jar内部的行为是不可靠的——系统重启图片丢失。建议配置一个独立的upload文件夹并映射为静态资源路径或者干脆用云存储OSS最小成本方案也可以用MinIO搭在本地。选OSS或MinIO还可以在论文里普涨一句“使用开源的云存储中间件”性价比高。生产与开发环境配置分离一定养成application-dev.yml和application-prod.yml分离的习惯通过spring.profiles.active切换配置。哪怕是毕设也一样这习惯对于将来接手真实工程保护好自己的本地环境非常重要。6.2 答辩时容易被追问的“算法与工程交织”问题记录几个这一届我身边学生真实问过的问题你提前准备一下“推荐结果那么多个你是按什么指标评估好坏的”这个问题是经典中的经典。你可以答离线层面用数据集切分训练集和测试集算精确率PrecisionK和召回率RecallK在线层面观察推荐位有没有点击率、用户有没有继续评分。但要注意毕设如果只有“感觉推荐得挺准”这种回答非常苍白。提前用数据算一个精度指标放在论文里哪怕数值一般比如协同过滤P50.35如实写也比空手强得多。“如果用户的行为数据一直在增加系统如何保证实时性”如果用的是离线重算模式你可以说定时任务每隔6小时重算一次用户相似度矩阵如果想追求更好的实时性可以重点说用Redis缓存最近N次交互在线做增量更新。说出“离线计算 在线缓存”这组词语评委就会点头。“为什么选用协同过滤而不是深度学习”实话实说就是深度学习在数据量极小的前提下效果未必更好、可解释性更弱、部署成本更高。前面也提到过你再加一句本系统在数据规模扩大后可以平滑过渡到Embedding召回的双塔模型也是可选后续优化方向。“你能不能花两分钟讲一下你的推荐流程”这是一个开放题。提前把下面这个逻辑背熟用户产生行为 - 行为数据入库 - 触发推荐请求 - 过滤器判断行为数据量 - 选择推荐策略 - 离线特征/相似度结果预计算 - 在线召回 - 规则过滤去除已访问、下架景点- 排序 - 附带推荐理由返回前端。能讲清楚整个数据流就已经超过七成同学了。6.3 独家避坑技巧很多毕设源码项目不告诉你的事市面上大量所谓“XX套毕设源码分享”质量参差不齐我提几个辨别方法和使用技巧帮你少浪费时间。先看数据库初始化SQL文件。如果连sql目录都没有或者SQL文件里只有三四张表这种项目建议直接放弃很难剪枝或填充数据。先验证能不能本地跑起来再谈二次开发。源码拿到的第一步要做的不是打开编译器而是看README里的部署文档是否完整查JDK版本、MySQL版本、Redis版本、Maven版本都要匹配很多项目无法启动就是版本不匹配的问题。SpringBoot 2.x和3.x的差异很大关键依赖组名都变了javax.*改jakarta.*用错了全会翻车。拿到源码后要认真通读核心模块至少要让“自己能在答辩现场讲清每一行核心代码的作用”。有的学弟学妹拿qian买的源码连推荐算法在哪个类里都不知道答辩时一亮相就被识破了反而得不偿失。如果你想对项目做“防查重改造”我的建议是不要改表层代码真正有价值的改动是增加独立模块加一个“附近景点推荐”用Haversine公式做距离计算加一个“相似景点推荐”用ItemCF跑加一个“基于Redis缓存的热榜”。这些新增模块往项目里一放项目的独创性和个人特色就出来了也天然回避掉查重风险。我个人在实际操作中体会最深的一点是这个项目的上限完全取决于你对业务数据的理解程度而不是取决于你知道多少高深的算法名词。你越熟悉旅游场景越能设计出合理的数据结构越能构造出能让算法有效工作的行为数据最终展示效果也就越好。推荐系统本身是一个概率模型它永远不会给“正确答案”但你需要让评委看到你如何定义“更好的推荐结果”并用工程手段逼近它。如果你们学校对毕设要求不是变态级别的创新这套SpringBoot旅游景点推荐系统从实用性、展示效果、答辩安全性三个维度来看都非常能打。拿着这篇文章的思路去对照你手里的源码或文档重点把“推荐算法的策略分发”“数据初始化脚本”“推荐理由展示”这三块做好你就已经能拿出一份让多数评委满意的作品了。后面有时间我再单独写一篇关于如何用RuoYi框架二次改造推荐系统的实操记录有需要的朋友可以先关注上下篇。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询