☰
SpringBoot+Vue3+MyBatis电影推荐系统实战:从数据库到协同过滤
2026/10/22 4:55:08 网站建设 项目流程

1. 项目拆解:这套技术栈为什么能撑起电影推荐

第一次看到“Java SpringBoot+Vue3+MyBatis 个性化电影推荐系统”这个标题的时候,我的第一反应是:这不就是现在市面上最典型的一套前后端分离毕设/练手项目组合嘛。但真正深挖下去,你会发现这个项目其实比普通的增删改查系统有意思得多。它不只是一个“电影管理后台”,核心亮点全在“个性化推荐”这四个字上——也就是说,它需要你在传统的 CRUD 之上,再实现一套能根据用户行为给不同人推荐不同电影的算法链路。

先给不熟悉这套组合的朋友讲清楚它是什么。SpringBoot 负责后端接口服务,MyBatis 负责数据库持久层操作,MySQL 存业务数据,Vue3 负责前端页面渲染和交互,前后端通过 HTTP 接口通信,互不干扰。这个架构在今天已经是 Java 后端开发的主流形态,放在一个电影推荐系统里,刚好能把“业务功能”和“推荐算法”两条线都走通。

适合谁来参考?如果你是一个正在做课程设计、毕业设计,或者想通过一个完整项目把前后端分离和推荐算法串起来的开发者,这个项目是非常合适的样本。它的难度曲线分布比较合理:普通模块走的是标准 CRUD,推荐模块又能触达协同过滤、相似度计算这些偏算法的内容,不会让人觉得整个项目只是“换个皮的管理系统”。

我当初自己做类似项目的时候,最深的感触是:很多人把眼光放在“推荐算法有多高级”上,结果忽略了工程侧的东西——比如用户行为数据从哪来、评分表怎么设计、推荐结果怎么在页面上呈现,这些才是一个推荐系统能不能跑起来的真正骨架。下面我按自己的实践顺序,把这个项目的完整拆解和落地过程讲清楚。

1.1 前后端分离到底分什么

前后端分离这个词被说了很多年,真正动手时很多新手还是会懵。在这个项目里,分离的核心有三层:代码工程分离、开发协作分离、部署运行分离。

代码工程上,后端是一个 Maven 工程,前端是一个 Vite 工程,两者目录完全独立。后端只管提供/api/**这类接口,前端只管调用接口,不直接碰数据库。开发协作上,前端同学(或者你自己做全栈时切换角色)只需要看后端给的接口文档,后端只需要保证接口返回的数据结构正确,两边可以并行推进。部署运行时,前端打包后是一堆静态文件,可以由 Nginx 托管,后端打包成 Jar 包独立运行,两者通过域名或端口区分。

在这套架构里,一个非常容易被忽略的细节是数据交互格式。我习惯全项目统一使用 JSON,后端返回结构固定为:

{ "code": 200, "message": "操作成功", "data": {} }

这样做的最大好处是前端能写统一的请求拦截器和响应拦截器,不用在每个页面里重复处理错误状态。我自己在写 Vue3 项目时,会在axios的响应拦截器里统一判断code,不是 200 就直接抛出全局错误提示,页面代码干净很多。

1.2 为什么是 SpringBoot+Vue3+MyBatis,而不是其他组合

这套组合能流行起来,不是因为什么技术信仰,而是因为它恰好卡在了“学习成本”和“就业市场需求”的交汇点上。

先说后端。SpringBoot 简化了 Spring 的配置,内嵌 Tomcat,一个 Jar 包就能启动,这对中小型项目来说太友好了。MyBatis 比 JPA 更贴近 SQL,推荐系统里经常要写复杂的多表查询和动态条件拼接,比如“查询用户没看过的电影且评分大于某个阈值”,这种 SQL 用 MyBatis 的<where>和<if>标签写起来特别直观。相比之下,JPA 的派生查询在这种动态场景下反而绕。

再说前端。Vue3 相比 Vue2 最核心的变化是 Composition API,也就是setup语法糖。在这个项目里,推荐模块的前端逻辑其实有点复杂——要同时展示“为你推荐”“相似电影”“热门排行”等多个数据源,用 Composition API 可以把这些逻辑按业务拆成多个组合式函数(比如useRecommend.js、useMovieDetail.js),而不是像 Options API 那样全部挤在methods里。我实际写过之后,再也不想回到 Vue2 那种按选项组织的写法了。

MySQL 就不多说了,这个体量的数据量用它完全够,而且你可以在本地轻松部署调试。真正决定一个项目写起来舒不舒服的,是上面这些技术能不能形成闭环:Vue3 的响应式数据通过 axios 传给 SpringBoot,SpringBoot 通过 MyBatis 操作 MySQL,查完的数据再以 JSON 返回给前端渲染——链条短,问题好定位,特别适合一个人独立开发。

2. 核心业务模块与推荐链路

很多第一次接触这种项目的朋友会问:电影推荐系统到底有哪些功能?是不是比普通管理系统多一堆复杂的算法?其实不是。它的业务模块可以分为用户侧和管理侧两条线,推荐算法是嵌在用户侧里的一条独立链路。理解这个结构,比急着去看代码更重要。

2.1 用户侧功能:从注册到看推荐

用户侧是这个系统的门面,功能都是围绕“一个普通用户进来之后会做什么”来设计的。

注册与登录是最基础的模块。在这个项目里,我会推荐使用 JWT 来做登录态管理,而不是传统的 Session。原因是前后端分离之后,后端接口是无状态的,Session 跨域处理起来很麻烦,而 JWT 把用户身份信息加密后放在请求头里,后端只需校验签名即可识别用户,天然适合这种架构。JWT 还有一个额外的好处:推荐系统需要记录“当前是谁在操作”,有了 JWT 解析出的 userId,后续的评分、收藏、推荐请求都能直接关联到用户。

电影浏览模块是内容展示的核心。为了让页面不那么像“表格系统”,一般会使用卡片式布局展示电影封面、标题、评分和简介,支持按类型、地区、年份筛选,还支持模糊搜索。这个模块看起来简单,但其实是推荐系统最重要的数据入口——用户在这里产生的浏览行为、点击行为,都是后续推荐的素材。

评分与收藏模块是用户表达偏好的主要途径。用户可以对看过的电影打 1-5 星评分,也可以收藏想看的电影。这两个操作会分别写入评分表和收藏表,而这两张表就是协同过滤算法的主要输入。我见过一些项目把评分和收藏混在一起,只做一个“喜欢”按钮,这样不是不行,但数据维度少了,推荐效果会很单薄。

最后才是“为我推荐”这个重头戏模块。用户进入首页或推荐页,会看到一个根据他历史行为生成的电影列表。这里有两种策略,冷启动阶段给热门榜,积累了评分和收藏数据后给个性化推荐。这是整个系统里最能体现“个性化”的地方,也是后面我要重点讲的算法部分。

2.2 管理侧功能:不只是后台上架电影

管理侧给管理员使用,使用独立后台,功能按角色区分权限拦截。电影管理负责电影信息的增删改查,包括封面图上传、类型标签设置、上映时间维护。用户管理可以查看用户列表、禁用异常账号。评分管理用于查看和干预某些异常评分数据。

这里我必须多说一句:管理侧的设计会直接影响推荐系统的数据质量。比如,电影表里如果没有“类型”字段,那基于内容的推荐(你看了科幻片,我给你推更多科幻片)就完全没法做。如果电影信息里没有封面图和简介,前端卡片页就会非常难看。所以,管理侧不只是一个内部工具,它是整个推荐系统内容底座的来源。

我在管理端还建议加一个“用户行为统计”页面,展示注册用户总数、评分总数、收藏总数、每日活跃用户等指标。这看起来像个仪表盘,但不只是为了好看——它帮助你判断系统有没有被真实使用,如果注册了 100 个用户但评分表只有 20 条,那你的推荐算法再厉害也巧妇难为无米之炊,这就是冷启动问题。

2.3 推荐链路怎么串起来

推荐模块不是单独一个“推荐表”存结果,而是一条实时计算的链路。这条链路一般是这样走的:

用户在系统里产生行为(注册、浏览、评分、收藏)后,这些行为会写入 MySQL 的业务表。当用户访问推荐接口时,后端会读取该用户的评分和收藏记录。如果行为数据足够,就调用协同过滤算法算出一批候选电影;如果行为数据不足,就走热门榜兜底。最后将推荐结果按预测评分降序返回给前端渲染。

推荐算法这一步不能在每次请求时都全量跑一遍 O(n²) 的相似度计算,不然数据库和 CPU 都受不了。实际工程中会有两种思路:如果数据量小,直接在内存里算;如果数据量大,就提前离线算好相似度矩阵,把结果存下来,在线请求时只做查表和排序。我们这个项目属于前者,但我在后面写实现时会顺带提一下怎么为扩展做预留。

这个链路在代码层面涉及的不只是推荐模块本身,还包括用户模块、评分模块、收藏模块的联动。也就是说,写推荐功能的前置条件,是把前面那些基础模块的数据流打通。我见过不少人一上来就直奔推荐算法,结果发现没有评分数据入口,算法写完了没数据可算,只好手动往数据库里塞假数据。记住:推荐系统是业务的延伸,不是空中楼阁。

3. 数据库设计与推荐算法落地

到了这一节,就进入这个项目最有技术含量的部分了。推荐系统做得好不好,一半看数据结构设计得合不合理,另一半看算法落地方案选得对不对。

3.1 MySQL 表结构怎么设计才算够用

我先说结论:核心表至少要有 6 张,分别是用户表、电影表、电影类型表(或者类型字段)、评分表、收藏表、管理员表。如果要做基于内容的推荐,电影表里的类型字段是最低要求;如果还想做得更细,可以再拆一张电影类型关联表,实现多对多关系。

用户表的核心字段可以这样设计:

字段名类型说明
idbigint自增主键
usernamevarchar(50)登录名
passwordvarchar(100)BCrypt 加密后的密码
nicknamevarchar(50)昵称
avatarvarchar(255)头像 URL
created_atdatetime注册时间

密码字段我这里特意强调一下,千万别明文存储。Spring Security 或者 SpringBoot 里集成一个BCryptPasswordEncoder就能解决,要用随机盐,同一个密码每次加密结果都不同,安全性不是一个量级的。

电影表的核心字段:

字段名类型说明
idbigint自增主键
titlevarchar(100)电影名
covervarchar(255)封面图 URL
directorvarchar(50)导演
actorsvarchar(255)主演,逗号分隔存储
typevarchar(50)类型,如“科幻,动作”
regionvarchar(50)地区
yearint上映年份
ratingdecimal(2,1)电影平均分
descriptiontext简介

评分表是推荐系统最关键的输入:

字段名类型说明
idbigint自增主键
user_idbigint用户 ID
movie_idbigint电影 ID
scoretinyint1-5 分
created_atdatetime评分时间
updated_atdatetime最后修改时间

这里要加一个数据库层面的唯一约束,比如unique(user_id, movie_id),防止同一用户同一部电影出现多条评分。这个约束帮你省掉很多后端的重复校验逻辑,实测特别好用。

收藏表比评分表更简单,核心就是user_id+movie_id+ 收藏时间,同样加唯一约束。管理员表结构就不细说了,和用户表类似,只是角色标记不同。

数据库设计的一个隐藏要点是索引。推荐系统要按用户查评分,所以评分表上要建idx_user_id索引;电影列表要支持按类型筛选,电影表建一个idx_type索引。数据量超过几十万之后再回头看,你会发现有没有索引的性能差距是几百毫秒和秒级之间的差别。

3.2 基于用户的协同过滤怎么写

这个项目里我用的是基于用户的协同过滤,简称 UserCF,是最经典、也最好被讲清楚的推荐算法之一。它的核心思想用一句话概括就是:跟你口味相似的人喜欢的电影,你也大概率喜欢。

完整流程分四步。第一步,构建用户-电影评分矩阵。第二步,计算用户之间的相似度,比如就用余弦相似度。第三步,找出当前用户的 K 个最近邻。第四步,把近邻们评分高且当前用户没看过的电影汇总,按加权预测评分排序,取 TopN。

余弦相似度的公式长这样:

sim(u, v) = Σ(rui * rvi) / ( sqrt(Σ rui²) * sqrt(Σ rvi²) )

其中rui表示用户 u 对电影 i 的评分,rvi表示用户 v 对电影 i 的评分,只乘双方都评过分的那部分电影。说白了就是判断两个人的打分方向是否一致,一致度高就是相似用户。每个用户打分习惯不同,有的人喜欢给高分,有的人手紧,所以更稳的变体是 “减去用户平均分” 的调整后余弦相似度,能剔除打分尺度差异的影响。

用 Java 实现时,先查询当前用户所有评分记录,再查询其他用户所有评分记录,构建一个Map<Long, Double>的映射。两两比对共同评分项,套公式计算。这个阶段一定要关注复杂度问题:如果有 1000 个用户,两两计算就要跑 50 万次,虽然还能接受,但如果变成 1 万个用户,就必须改成预计算相似度矩阵,或者用更高效的算法。

算出相似用户后,候选电影集合来自这些相似用户评分过的、但当前用户没评分的电影。预测当前用户对候选电影 i 的评分公式是:

pred(u, i) = avg(u) + Σ( sim(u, v) * (rvi - avg(v)) ) / Σ |sim(u, v)|

avg(u)是当前用户历史评分的平均值,这个基准值很重要。然后按预测分从高到低排,取前 20 条左右输出。

3.3 基于内容的推荐作为补充

只有基于用户的协同过滤有一个天生缺陷:冷启动。新用户没有评分行为,没有任何用户和他相似,算法直接失效。这个项目里我采用了双路兜底策略。

第一路是热门榜兜底。新用户进入推荐页时,直接返回全站评分最高、评分人数最多的热门电影。这个逻辑非常简单,一条 SQL 就能搞定:

SELECT * FROM movie ORDER BY rating DESC, rating_count DESC LIMIT 20

第二路是基于内容的推荐。对已经有一定行为的用户,可以根据他最近评过高分的电影类型,找出同类型的其他高分电影。比如用户给《星际穿越》打了 5 分,那系统就该去电影表里找类型包含“科幻”的其他高分片。

这两路策略叠加,保证任何状态下用户都能看到推荐结果。我在实践中的经验是:推荐系统最重要的不是算法多高级,而是“永远有结果”。哪怕结果暂时不那么精准,也比白屏和提示“暂无推荐”要好得多。精准度可以随着用户行为积累逐步提升,但第一印象一旦坏了,用户再也不来了。

4. 前后端关键实现细节

这一节我挑几个最容易出问题、也最能体现技术水平的关键点来拆解。这些都是我在实际开发和调试中反复踩坑后沉淀下来的经验。

4.1 SpringBoot 后端接口要这样组织

推荐用 Controller、Service、Mapper 三层结构。Controller 只负责接收参数、调用 Service、返回统一结构;Service 写业务逻辑和算法;Mapper 只写数据库操作。以推荐模块为例,Controller 里大概是这样的:

@RestController @RequestMapping("/api/recommend") public class RecommendController { @Resource private RecommendService recommendService; @GetMapping("/movies") public Result getRecommendMovies(@RequestParam Long userId) { List<MovieVO> movies = recommendService.recommendForUser(userId); return Result.success(movies); } }

Service 接口里定义推荐链路的主逻辑。我会在 Service 实现类里写出电视节目里看不到的真实处理流程:先根据 userId 查询评分记录数量,小于阈值走热门榜,大于等于阈值走协同过滤,协同过滤结果不足时再用基于内容的推荐补位,最终返回合并后的列表。这个“降级链路”在代码里非常好用,但很多初版项目都没有。

这里有一个所有用 MyBatis 的同学都该注意的坑:多表关联查询的时候,如果返回的 VO 里有数据库表里不存在的字段,不要试图用 Map 接收,而是定义一个 VO 类。比如MovieVO里除了电影基本信息,可能还要临时装一个score(当前用户对它的评分)、reason(推荐理由),这种字段在 SQL 里查出来后再装配进 VO,代码的可读性和可维护性比 Map 好太多。

还要注意一个细节是分页。电影列表和搜索功能必须做分页查询,我用的是 PageHelper 插件,配合 MyBatis 只需要先设置页码和每页条数,后面的 SQL 不用手动加LIMIT。但不推荐在推荐模块里分页——推荐结果是一次性计算出来的,排序已经决定了用户最可能喜欢哪些,再分页就有点反直觉了。我通常是一次性查出 20 条直接返回。

4.2 Vue3 前端工程必须掌握的套路

Vue3 项目我是用 Vite 搭建的,比 Webpack 的速度快得不是一点半点,尤其在冷启动开发服务器的时候。搭配 Element Plus 做 UI 组件库,页面写起来很省事。状态管理用 Pinia,它比 Vuex 更轻量,TypeScript 支持也更好。路由用 Vue Router 4,这个版本原生支持 Vue3。

推荐页的展示建议做一个“推荐理由”的文案,这对用户体验的提升非常明显。同样是推荐一部电影,只显示“推荐给你”和显示“因为你看过《星际穿越》并且喜欢科幻类型,所以推荐这部《盗梦空间》”,后者给用户的信任感完全不同。这个理由在算法侧生成,后端在返回推荐列表时附带一个 reason 字段,前端直接渲染。

前端请求后端的地址要统一封装。我习惯在src/utils/request.js里创建一个 axios 实例,设置基础路径为/api,请求头里自动带上 token,响应拦截器统一处理后端返回的code,非 200 时弹出错误提示并跳转登录页。如果不做这个封装,每个页面自己处理错误逻辑,几十个页面会让你写到崩溃。

关于跨域问题,开发环境我用 Vite 的 proxy 转发,配置在vite.config.js:

server: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } }

这里重点解释一下为什么这个配置能解决跨域。浏览器的同源策略限制的是“不同端口”的请求,前端跑在 5173,后端跑在 8080,直接请求就是跨域。但配置了 proxy 之后,前端请求发给了 Vite 开发服务器,Vite 服务器在服务端把这个请求转发给 8080,服务器之间的通信不受同源策略限制,所以就不会报跨域错误了。部署上线后,用 Nginx 配置一个反向代理完成同样的事。

4.3 登录权限校验与联调

登录模块不可回避的问题就是 JWT 的校验位置。很多新手把所有接口都放在拦截器外面,觉得后端加上校验麻烦,结果一个项目中端接口裸奔。正确的做法是:定义一个拦截器,拦截所有/api/**请求,用白名单排除掉登录、注册、获取电影列表等必要接口。每次请求过来时从请求头里拿 token,解析失败就返回 401。

我在 Vue3 端的响应拦截器里也做了联动处理:检测到后端返回 401 时,直接清除本地 token、跳转到登录页。这样用户登录过期后会被自动引导回登录页,不需要手动清数据。

前后端联调时最影响效率的坑是字段名不一致。比如后端 Java 里驼峰命名movieId,前端 JS 里也写了一样的名字,本来没问题,但如果后端 JSON 配置了spring.jackson.property-naming-strategy改成下划线,前端一下就全懵了。我的建议是保持默认,全项目统一驼峰命名。这种问题排查起来非常耗时间,而且代码越写越多,重构成本越来越高,所以一开始就约定好,比事后加班找 bug 划算得多。

还有一个联调问题很多人会忽略:时间格式。Java 默认序列化 LocalDateTime 出来是一串数组格式,前端拿到根本没法直接用。你需要在配置里加一行:

spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8

这样前端拿到的就是正常人能看懂的时间字符串了。

5. 实操记录:从零跑通整个项目

我在自己的机器上跑这个项目跑过很多次,记录一下完整的操作流。这套流程哪怕第一次接触的人,按顺序走也能把项目跑起来。

5.1 环境准备清单

后端需要 JDK 17 以上版本、Maven 3.8 左右、MySQL 8.0。前端需要 Node.js 16 以上版本,我建议用 18 的 LTS 版本。IDE 方面后端用 IntelliJ IDEA,前端用 VS Code,也可以都用 IDEA,一个人开发时切换起来更顺手。

先创建数据库执行初始化 SQL:

CREATE DATABASE movie_recommend CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

建库时字符集选 utf8mb4,不是为了别的什么,就是防止电影简介里有 emoji 或者其他特殊字符时插入报错。我在早期用 utf8 建表就遇到过插入带特殊符号的简介直接报错的情况,后来直接统一改用 utf8mb4 就没再出现过了。

导入表结构和初始数据后,修改后端的application.yml:

spring: datasource: url: jdbc:mysql://localhost:3306/movie_recommend?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true username: root password: 你自己的密码 driver-class-name: com.mysql.cj.jdbc.Driver

特别注意一下allowPublicKeyRetrieval=true这个参数。MySQL 8.0 默认的认证插件是 caching_sha2_password,很多客户端连接时如果不加这个参数会报 Public Key Retrieval is not allowed 的错误,加了才能正常连接。

5.2 后端启动与自测

后端工程导入 IDEA 后,等待 Maven 下载依赖。第一次启动的时候最耗耐心的就是这一步,依赖多、网络不好的时候等十几分钟很正常。启动成功后,在浏览器访问 Swagger 或者直接访问一个已知接口测试。

我习惯先测登录接口。用初始化的管理员账号登录,拿到 token 带上请求头访问用户列表接口。如果一切正常,后端基本就站住了。后端自测这一步千万不能跳,因为前端联调时你很难分辨问题是出在前端代码还是后端接口。

5.3 前端启动与联调验证

前端工程打开终端执行npm install安装依赖,执行npm run dev启动开发服务器。启动后访问前端地址,正常情况下会跳转到登录页。

你先注册一个新用户,登录进去后第一件事不是去看推荐页,而是去评分模块给三五部电影打上分。这个操作很关键,因为推荐算法的数据来源就是这些评分记录。然后回到推荐页刷新,你会看到推荐列表从“热门电影”变成了带推荐理由的个性化列表。

如果这一步没有生效,按我惯用的排查路径走一遍:打开浏览器开发者工具,看网络请求里推荐接口返回了什么数据。如果返回的是热门榜,说明用户行为数据还没打到阈值;如果返回的是空数组,说明算法执行报错了,去看后端控制台日志,重点关注协同过滤计算那块。按照这个思路排查,90% 的问题都能在十分钟内定位。

6. 常见问题与排查技巧实录

最后分享一些我在实际开发和帮别人调试这个项目时遇到的问题汇总。这些问题都是真实出现过的,不是网上复制的经验。

6.1 跨域问题到底怎么排查

前端报错CORS,后端接口用 Postman 测是通的,这种情况先确认下你的请求方式。Vite 的 proxy 配置只对开发服务器生效,如果你直接在前端代码里把 axios 的 baseURL 指向了http://localhost:8080,那 proxy 就完全不会起作用。我见过不少人在这个坑里绕半天,本质是 axios 发起请求时根本没经过 Vite 服务器。

另外,如果你一定要用后端开启跨域的方式,需要在后端加一个配置类,并指定允许的来源、方法、请求头。但我还是更推荐 Nginx 反代或者 Vite proxy 的方案,因为这样前后端甚至可以用同一个域名访问,省掉一堆跨域相关的麻烦事。

6.2 登录后请求接口返回 401

如果登录成功了,但后续请求一直 401,优先怀疑前端没把 token 带上。axios 请求头里 token 的字段名前后端必须一致,比如前端传的是Authorization,后端拦截器读取的是token,那就对不上。这种问题看浏览器开发者工具里的请求头一目了然,token 存在就别急着查后端代码。

还有一种情况是 token 有效期设得太短,比如只设了 30 分钟,调试时一转头就过期了。开发环境建议把有效期设成 7 天,省得反复登录打断思路。

6.3 推荐结果一直停留在热门榜

这不是 bug,很可能是算法判断用户行为数据不足。协同过滤要有足够多的评分数据才能算出相似用户,如果整个系统只有几个注册用户,评分数据太少,就算算法实现正确,结果也是乱的。我建议初始化数据时至少造 10 个虚拟用户,每个用户给 10 到 20 部电影打分,这样调试协同过滤时才有数据基础。

如果确认数据充足但算法没生效,那就看日志。在 Service 里加一个日志输出,打印当前用户 ID、评分数、计算的相似用户列表、候选电影数,人肉追踪一遍数据流,问题马上现形。

6.4 MySQL 8.0 连接报错

最常见的两个错误:一个是Public Key Retrieval is not allowed,这个在连接串上加allowPublicKeyRetrieval=true就能解决。另一个是Unknown database,这个就是初始化 SQL 没执行成功,或者连接的库名写错了。我特别建议在数据库连接串上加上serverTimezone=Asia/Shanghai,不然时间字段可能出现 8 小时的时差偏移,排查的时候非常难受。

还有个很隐蔽的问题:MySQL 服务没有启动,后端启动时一直报连接失败。我见过不止一个新手下意识认为是密码错了,反复修改配置文件,结果是根本没打开 MySQL 服务。Windows 上可以在服务里看 MySQL 的状态,Mac 上可以用命令行确认。

6.5 前端启动报错端口被占用

Vite 默认端口是 5173,如果被占用会自动尝试下一个端口。但如果你指定了固定端口,那就需要手动换一个。还有一种情况是 Node 版本太低导致 Vite 直接启动失败,报错信息里一般会提示不支持某个语法。升级到 Node 18 或 20 基本都能解决。

前端依赖安装慢的问题,国内环境建议配置 npm 淘宝镜像源,安装速度会有质的提升。这也是很多新手卡在npm install半天没动静时的常见解法。

7. 之后还能怎么扩展

这个项目如果完成了基础版,后续扩展的方向非常多。我个人觉得比较有价值的是把协同过滤的离线化做一下,用定时任务在深夜统一计算用户相似度矩阵并存库,白天请求时直接查结果,这样系统能支撑更大的数据量。其次可以做电影详情页的“看了还看”(基于物品的协同过滤),逻辑和基于用户的推荐对称,实现成本不高但用户感知很强。如果你还想加一点工程亮点,可以在前端引入虚拟滚动处理超长电影列表的渲染性能问题。

我做的过程中特别有体会的是,这个项目的价值不在于“算法有多难写”,而在于把推荐这个偏理论的东西落到了完整可运行的前后端系统中。每一步都是工程问题,从数据采集、到算法落地、再到前端呈现,哪一环断了整个推荐链路都不成立。这也是我最推荐这类项目的原因——它能逼着你去完整地思考一个真实业务系统,而不是在虚拟机里跑一段孤立的算法脚本。

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

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

立即咨询