作为一名带过不少毕业设计、也帮人排查过无数Springboot+Vue项目的过来人,我第一眼看到“基于Springboot+Vue的智能推荐的卫生健康系统源码文档部署文档代码讲解等”这个标题,就知道这又是个典型的全栈“大综合”项目。这类项目在高校毕业设计、课程设计里出现频率极高,因为它几乎把后端开发、前端开发、数据库设计、算法应用、系统部署这条完整链路全串起来了。今天我就以这个项目为例,把从技术选型、系统设计、核心代码实现、部署上线到避坑排错的全过程,掰开揉碎讲清楚,给正在做类似系统或者准备开题的读者一个可以直接照抄的作业。
先说清楚这个系统是干什么的。它不是一个简单的“医院挂号平台”或“健康资讯展示站”,而是要在基础的卫生健康管理之上,加入“智能推荐”这个核心能力。通俗点说,系统不仅要管用户的健康档案、体检数据、饮食运动记录,还能根据这些数据为用户推荐合适的健康资讯、饮食方案、运动计划,甚至是附近的医疗机构或药品信息。这里的“智能”靠的是推荐算法,而“系统”靠的是Springboot和Vue这一对经典前后端组合。适合谁来参考?一个是正在准备毕业设计、需要完整项目支撑的本科生和研究生,另一个是想快速搭建一个带推荐功能的业务系统、但又不想从零造轮子的Java开发者和产品经理。无论你是哪种角色,这篇文章都会尽量避开虚的东西,直接讲能落地的方案。
1. 整体设计思路与核心功能模块拆解
1.1 前后端分离架构为什么是这类项目的首选
很多初学者会纠结一个问题:Springboot+Vue前后端分离,和我直接把页面写在Templates里、用Thymeleaf渲染,到底差在哪?我的答案是:如果你做的是类似这种需要反复迭代、前后端可能要并行开发甚至分开部署的智能推荐系统,那前后端分离几乎是唯一合理的选择。
前后端分离的核心逻辑是,前端只负责页面展示和用户交互,后端只负责提供接口和数据。两者通过JSON格式的数据进行通信。这样带来三个直接好处:第一,前端工程师和后端工程师可以各自独立开发,只要提前约定好接口文档,就不存在互相阻塞的情况;第二,后端接口可以被多个端复用,比如以后要做小程序端、移动App端,前端页面重写,后端接口完全不需改动;第三,部署时前端静态资源可以用Nginx托管,后端独立运行在Tomcat或内置服务器上,抗压能力和可维护性都更好。
用生活化的类比解释,前后端分离就像是餐厅的“厨房”和“前厅”。厨房(后端)负责按菜单(接口文档)做菜(处理数据),前厅(前端)负责把菜端给客人(用户)并收集反馈。厨房换大厨不影响前厅上菜,前厅重新装修也不影响厨房出餐,只要菜单不变,两边怎么改都行。
1.2 系统模块怎么划分才算合理
在动手写代码之前,模块划分是决定项目成败的第一步。基于“智能推荐的卫生健康系统”这个主题,合理的模块划分应该包含以下五个核心部分:
- 用户模块:注册、登录、个人信息维护、密码加密存储。这里的用户不只有普通用户,还应该有管理员角色,甚至可以考虑健康管理师角色,分权分责。
- 健康档案模块:体检指标录入(身高、体重、血压、血糖等)、既往病史、过敏史、家族病史。这是推荐系统的数据根基,数据越完整,推荐越准确。
- 内容管理模块:健康资讯、饮食食谱、运动课程、药品或服务信息的录入、编辑、上下架管理。这些是推荐系统要推的“物品”。
- 行为记录模块:用户的浏览记录、收藏、点赞、评分、搜索记录。这些行为数据是推荐算法计算相似度和偏好的重要输入。
- 推荐中心模块:根据用户画像和行为数据,生成个性化推荐列表,并通过接口返回给前端展示。
模块划分的原则是“高内聚、低耦合”。每个模块内部的业务逻辑尽量完整独立,模块之间通过明确的接口调用,避免互相掺和。举个例子,健康档案模块不需要知道推荐模块是怎么算出结果的,它只需要提供“根据用户ID查询最近一次体检数据”这个方法即可。
1.3 智能推荐在卫生健康场景下的定位与落地方式
说到“智能推荐”,很多人第一反应是上深度学习、做协同过滤、搞知识图谱。但在实际项目里,尤其是毕业设计或中小型商用系统,推荐系统要服务的目标不是“秀算法”,而是“让用户觉得有用”。卫生健康领域的推荐和电商推荐有个显著区别:电商推荐追求点击率和转化率,就算推错了最多不买;卫生健康推荐如果推错,比如给高血压用户推了高盐饮食方案,可能引发不良后果。所以推荐落地必须谨慎。
我的建议是,这类系统采用“混合推荐策略”,可以拆成三层:第一层是规则过滤,比如根据用户的疾病标签直接过滤掉禁忌内容,这是安全底线;第二层是基于内容的推荐,根据用户最近的浏览或收藏内容,找到相似标签的文章或食谱推荐给用户;第三层才是基于用户的协同过滤,找到行为相似的用户群体,把群体中其他人喜欢的内容推荐给当前用户。三层策略逐层递进,既能保证推荐效果,又不会因为算法过重导致开发困难。
2. 核心技术与数据库设计详解
2.1 Springboot后端在项目中扮演的角色与常用组件
Springboot在项目里的角色是“后端大脑”。它负责所有业务逻辑的处理、数据的读写、安全认证、以及对外提供RESTful API接口。之所以几乎所有的Java企业级项目都在用Springboot,是因为它能让你在几分钟内搭建起一个独立运行的应用,省去了Spring传统开发中大量的XML配置。
在这个卫生健康系统里,Springboot至少会用到以下几组组件:Spring Web(负责处理HTTP请求和响应)、Spring Data JPA或MyBatis(负责数据库操作)、Spring Security或Sa-Token(负责用户登录认证和权限控制)、以及一个用于参数校验的Validation组件。如果是做集群部署,以后还可以引入Redis做缓存,用Spring Cache注解来减少数据库压力。对于毕业设计级别,上面这些完全够用,不建议一开始就上微服务、消息队列那一套,那是过度设计。
2.2 Vue前端如何高效构建页面与交互
Vue在前端项目里负责所有用户界面的渲染和交互处理。用Vue做单页应用的好处是,页面切换不需要重新加载,用户体验非常流畅,而且组件化的开发方式让代码复用变得非常方便。比如你做了一个“健康资讯卡片”的组件,在首页推荐区、资讯列表页、我的收藏页都可以反复使用,改一处全盘生效。
在Vue生态里,有几个东西是这类项目躲不开的:Vue Router负责页面路由跳转;Pinia(或Vuex)负责全局状态管理,比如登录用户的token和个人信息就可以存在这里;Axios负责向后端发送HTTP请求,并且可以通过拦截器在请求头里自动带上token。界面UI方面,如果不想手写太多CSS,建议直接引入Element Plus组件库,表格、表单、弹窗、进度条这些常用组件开箱即用,开发效率直接翻倍。
2.3 数据库表设计是推荐系统的地基
说句实话,很多做这个项目的同学卡住的不是Springboot,也不是Vue,而是数据库表不知道该怎么设计。表设计不合理,后面写SQL和写算法特征的时候会痛苦到怀疑人生。这里给出一个推荐的“最小核心表集合”,你在这个基础上再根据自己的业务扩展就好:
- user表:id、username、password(密文)、nickname、age、gender、phone、role、create_time。
- health_profile表:id、user_id、height、weight、blood_pressure_high、blood_pressure_low、blood_sugar、heart_rate、allergy_history、family_history、update_time。
- article表:id、title、category(资讯/饮食/运动/药品)、content、tags(用逗号分隔)、status、publish_time。
- user_behavior表:id、user_id、item_id、item_type、behavior_type(view/like/favorite/search)、score、create_time。这张表是推荐系统的核心数据来源,每一条浏览、收藏、点赞都要记录。
- recommendation_log表:id、user_id、item_id、item_type、reason(规则/内容相似/协同过滤)、create_time。这张表用来记录推荐结果,方便后续做效果分析和算法调优。
如果你以后想扩展,可以再加一张“医生/机构表”用于医疗资源推荐,再加一张“预约记录表”做在线预约,表的结构设计思路是一样的。
2.4 用户画像构建与推荐特征的数据来源
推荐系统要“懂用户”,前提是系统有足够多的用户数据来构建“用户画像”。用户画像听起来玄乎,但说白了就是把用户的属性标签和行为偏好用数据的形式存起来。在这个项目里,用户画像的数据来源主要分为静态画像和动态画像两类。
静态画像来自注册信息和健康档案,比如年龄段、性别、身高体重、是否有高血压、是否对某种食物过敏,这些相对固定的属性。动态画像来自用户行为记录,比如反复浏览减脂餐文章、收藏了跑步课程、搜索过“感冒食疗”——这些实时变化的行为能反映用户近期的兴趣点。这两类画像分别对应了推荐策略中的“规则过滤”和“相似度计算”,在建表时就要考虑清楚哪些字段能为画像服务,不要等到写算法了发现数据不够用。
3. 推荐算法怎么在Springboot里落地实现
3.1 基于内容的推荐:最快见效的起步方案
基于内容的推荐是实操性最强、也最容易讲清楚的方案。它的核心逻辑可以用一句话概括:找到用户过去喜欢的内容,推荐与这些内容相似的其他内容。技术上要解决两个问题:第一,如何量化内容之间的相似度;第二,如何获取用户的偏好内容列表。
在这个项目中,内容就是文章或菜品或课程,每一条内容都有category和tags字段。计算内容相似度的最简做法是用标签集合的Jaccard相似度:两个内容的标签交集数量除以并集数量,结果越接近1,说明它们越相似。举个例子,文章A的标签是“减脂、鸡胸肉、健身餐”,文章B的标签是“健身餐、高蛋白、增肌”,交集是“健身餐”,并集是“减脂、鸡胸肉、健身餐、高蛋白、增肌”,所以相似度等于1/5,也就是0.2。把所有候选内容都与用户收藏列表中的内容计算一遍相似度,按分数排序,取TopN返回即可。
具体到Springboot实现,可以在定时任务或接口调用时,通过自定义工具类或者引入简单的计算库来完成这个过程。为了性能考虑,可以预先计算好内容之间的相似度矩阵并存到Redis缓存中,用户请求推荐时直接查缓存取TopN,而不是每次实时计算。
3.2 基于用户的协同过滤:从零实现与关键代码解析
协同过滤是推荐系统里另一块“固定节目”。基于用户的协同过滤核心思想是:找出与当前用户行为最相似的K个其他用户,把这K个用户喜欢而当前用户还没看过的内容推荐出来。它的核心是“人以群分”,比如用户A和你都收藏了差不多的减脂食谱,那用户A喜欢的其他食谱,你大概率也会喜欢。
实现这个算法,关键步骤有三个:第一步,构建“用户-物品”行为矩阵,行是用户ID,列是物品ID,值可以是行为得分(如浏览1分、收藏3分、点赞2分);第二步,用余弦相似度或皮尔逊相关系数计算用户之间的相似度,找出TopK相似用户;第三步,从相似用户的物品集合中,剔除当前用户已经产生过行为的物品,再按“相似度加权得分”排序取TopN。
这里给出一个简化版的核心代码逻辑,方便直接落到项目中使用:
// 计算两个用户之间的余弦相似度 public double cosineSimilarity(Map<Long, Double> user1Items, Map<Long, Double> user2Items) { Set<Long> commonItems = new HashSet<>(user1Items.keySet()); commonItems.retainAll(user2Items.keySet()); if (commonItems.isEmpty()) { return 0.0; } double dotProduct = 0.0; double norm1 = 0.0; double norm2 = 0.0; for (Long itemId : commonItems) { dotProduct += user1Items.get(itemId) * user2Items.get(itemId); } for (Double score : user1Items.values()) { norm1 += Math.pow(score, 2); } for (Double score : user2Items.values()) { norm2 += Math.pow(score, 2); } return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2) + 1e-9); }这个代码看着不长,但已经足以体现协同过滤的核心思想。实际项目中,处理用户-物品矩阵时尽量避免用嵌套循环遍历全部用户,因为复杂度可能是O(n平方)。更高效的做法是先用SQL查出与当前用户有过共同行为物品的其他用户,只对这些“候选用户”计算相似度,能省掉大量无效计算。
3.3 冷启动问题:新用户和新内容该怎么推
每个推荐系统都逃不过“冷启动”这道坎。新用户注册后没有任何行为数据,协同过滤和基于内容的方法全部失效;新发布的内容因为没有用户行为,也很难被推荐出去。冷启动处理不好,用户第一次打开推荐页是一片空白,体验极差。
目前项目中最实用的方案就是“规则兜底”。新用户没有行为数据时,直接根据其注册时填写的性别、年龄、健康档案中的疾病标签,推送对应类别的默认内容。比如用户标记了“高血压”,那系统就直接推送“高血压饮食注意事项”“适合高血压患者的运动方式”等内容,还能顺带过滤掉高盐食谱,这个逻辑还能体现“卫生健康场景的合规性”。对于新内容,则可以在一段时间内给予“新品加权”,比如在上架后48小时内,在热门榜或推荐列表里增加一个加权系数。我个人的习惯是,冷启动阶段推荐结果必须结合规则过滤一起使用,宁可推得没那么“精准”,也不能推得让人反感或产生风险。
3.4 推荐接口的性能优化:缓存与异步处理
推荐接口如果想在每次用户刷新页面时都实时算一遍全量数据,那数据库和CPU很快就会被拖垮。推荐结果的时效性要求并没有那么高,用户看推荐页和五分钟前看推荐页,结果不应该有太大变化。所以推荐结果可以做“短周期缓存”。
我常用的优化方案是:在Springboot里用一个定时任务,每隔30分钟对所有活跃用户跑一次推荐计算,把生成的结果列表(包含推荐内容和推荐原因)缓存到Redis里,key是userId,value是推荐结果的JSON串。用户请求推荐接口时,先用userId查Redis,命中就直接返回;没有命中(比如新用户)才走实时计算逻辑,并将结果写入缓存。这样既保证了推荐的实时提升效果,又大幅降低了系统的计算压力。对于毕设答辩来说,能把这个优化思路讲清楚,是非常加分的亮点。
4. 系统部署与运行环境准备
4.1 从零开始的环境搭建:JDK、Maven、Node.js与数据库
这套系统要跑起来,首先要把基础环境准备好。如果环境没弄对,后面每一步都在踩坑,这也是“部署文档”里最重要的第一部分。后端是Springboot项目,所以JDK版本建议选1.8或11,这里特别提醒一句,如果你的Springboot版本是2.7.0及以上,JDK 1.8依然兼容,但如果你直接上了Springboot 3.x,那就必须用JDK 17,这点在配置环境前一定要查清楚,不然项目根本起不来。构建工具Maven建议用3.6.3或以上版本,配置好阿里云镜像源,下载依赖的速度会快很多。
前端Vue项目建议使用Node.js 16.x LTS版本,安装完后自带npm包管理器,用来安装项目依赖。数据库方面,如果追求轻量方便,可以用MySQL 5.7或8.0,开发阶段直接用Navicat或DataGrip做可视化操作就行。所有软件安装完,记得在命令行里分别执行java -version、mvn -version、node -v、npm -v、mysql --version确认安装成功,再继续下一步。如果你需要 RabbitMQ,记得要先装 Erlang,版本对应关系也要提前查好。
4.2 项目初始化与配置文件的正确写法
环境准备好后,就可以开始初始化项目了。如果你是从零开始做,后端可以直接在IDEA里通过Spring Initializr创建Springboot项目,注意Group和Artifact的命名规范,选择Web、MyBatis(或JPA)、MySQL Driver、Validation这几个依赖。前端用Vue CLI创建项目,选择Vue 3版本,安装Vue Router、Pinia、Axios和Element Plus这些核心依赖。
配置文件的写法是这个阶段的重头戏。后端application.yml里,最核心的是配置数据源信息,包括数据库地址、用户名、密码,以及JPA或MyBatis的配置。如果你的项目连了Redis,还要配置Redis的连接信息。端口号建议统一用8080,如果被占用再换其他端口。数据库表结构和初始数据记得用SQL脚本一次性导出,这样在任何电脑上都能快速重建环境。前端项目的配置文件是vue.config.js,里面有一个关键配置devServer.proxy,它能把前端请求代理到后端地址,完美解决跨域问题。举个例子,前端在8081端口运行,后端在8080端口运行,前端请求/api/user/login时,proxy配置会把请求转发到http://localhost:8080/api/user/login,这样浏览器端就不会报跨域错误了。
4.3 本地联调与生产环境部署的完整流程
本地联调是整个开发过程中最频繁进行的环节,拿到这个项目后,建议先启动后端,确认没有报错日志并且数据库表自动创建成功,再启动前端,打开浏览器访问localhost页面。然后用一个最简单的用户注册接口,从前端页面发起请求,看能否成功写入数据库,顺利走通这一条链路,就说明系统基础是通的。
生产环境部署就要切换到另一套思路了。后端的打包命令是mvn clean package -DskipTests,在项目目录下执行,命令跑完后target目录下会生成一个jar包。把这个jar包上传到云服务器上,用nohup java -jar xxx.jar > app.log 2>&1 &命令实现后台运行。前端项目在本地执行npm run build,生成dist目录后,把dist下的静态文件上传到服务器的Nginx的html目录下,并配置Nginx将API请求反向代理到后端端口。最后用浏览器访问服务器IP,如果能正常看到页面并且接口都能通,就说明部署成功了。这一套流程执行下来,你会对整个系统的运行机制有非常深的理解。
5. 代码讲解与开发避坑指南
5.1 用户登录鉴权与健康数据安全保护
卫生健康类系统涉及用户的隐私数据,登录鉴权和数据安全是绝对绕不开的话题。项目中密码的存储坚决不能使用明文。推荐使用Spring Security的BCryptPasswordEncoder对密码进行加密,它每次加密的盐值都不同,即使两个用户密码相同,密文也不一样,能有效防止彩虹表攻击。
登录成功后的会话保持,最简单可靠的方案是使用JWT(JSON Web Token)。用户登录成功后,后端生成一个包含用户ID、用户名、过期时间的token字符串返回给前端。前端把token存在本地存储或Pinia状态管理里,之后每次请求都在HTTP请求头中带上Authorization: Bearer {token}。后端通过一个拦截器或Spring Security的过滤器解析token,解析失败就返回401错误,提示用户重新登录。这种方案是无状态的,服务器不需要保存会话信息,非常适合前后端分离架构。
健康档案数据在接口返回时也要注意脱敏,比如手机号只显示中间四位,父母病史这类敏感字段仅限本人和管理员查看。写接口文档时,可以先定义一个基础返回体类统一兜底异常,避免前端拿到一堆乱七八糟的报错格式。
5.2 Vue前端布局异常与打包后的白屏问题排查
在用Vue开发的过程中,有两个问题几乎每个人都会遇到。第一个是Vue打包后的布局异常,通常是因为项目部署在服务器的子路径下导致的。如果你把前端项目部署在http://ip地址/dist/下,而不是域名根路径下,那打包时就必须在vue.config.js里设置publicPath: './',否则打包后的JS和CSS路径会写死为根路径,导致资源加载404,页面自然就是白屏。改了publicPath之后,还要留意路由模式,如果用history模式,服务器还要额外配置try_files规则,否则直接访问某个子路由会报404,最简单的方案是直接用默认的hash模式。
第二个高频问题是本地开发时页面样式正常,一打包就乱。这个很大概率是CSS的全局样式和组件样式冲突了。Element Plus组件默认有一些基础样式,如果你自己写的全局样式文件放在了组件样式之后引入,或者没有给样式加scoped属性,就会互相覆盖。排查思路是先打开浏览器控制台看样式计算,找到被覆盖的属性和来源文件,再决定是调整引入顺序还是给组件加scoped。
5.3 代码讲解思路:怎么给别人讲清楚这个项目
如果你是用这个项目做毕业设计,那么“代码讲解”是答辩时必过的一关。很多同学代码跑通了但讲不出来,核心原因是只停留在“会用”的层面,没有理解设计的意图。我建议讲解时按照“一条主线、三个关键点”来组织。
一条主线,是“用户从登录到接收推荐结果”的完整数据流。从用户在前端输入用户名密码开始,讲述请求怎么通过Axios和Vue Router到达后端Controller,Controller怎么调用Service处理业务,Service怎么通过Mapper操作数据库,推荐算法怎么读取行为数据计算推荐结果,结果又以什么格式返回给前端渲染。任何代码讲解,能让听众跟随数据流走完一圈,就已经成功了。
三个关键点,是登录鉴权原理、推荐算法的实现逻辑、数据库表之间的关联关系。这三个点你刻意准备一下,每个点能用一句话点出设计思路,再用一个代码片段佐证,答辩基本稳了。切忌一上来就念代码,听者很快就会失去兴趣。
5.4 前端M3U8视频播放与进阶内容扩展的集成建议
在这个卫生健康系统里,如果你不太想局限于图文内容,还想接入视频课程,那就会遇到越来越多的项目在扩展时都会碰到的一个需求——M3U8视频流播放。M3U8是一种基于HTTP Live Streaming协议的视频切片格式,把完整视频切成一个个TS小文件,通过索引文件来按顺序播放。这样做的好处是支持边下边播、拖动进度条和自适应码率,非常适用于在线课程、健康讲座这类长视频场景。
Springboot后端在处理M3U8时,核心工作是提供视频文件存储和流媒体分发。最简单的方式,是不对视频做额外处理,直接把视频上传到服务器的静态资源目录,前端用支持HLS的播放器库hls.js来播放。在Vue组件里,你可以先判断当前浏览器的兼容性,在支持原生HLS的Safari浏览器上直接用video标签播放,在不支持的Chrome内核浏览器上加载hls.js。这个扩展做起来不算复杂,但对系统整体的专业感提升非常明显。
6. 常见问题排查与经验心得实录
6.1 环境与依赖层面的典型报错和处理
- Springboot版本太高导致无法启动:某些新版本要求JDK 17+,而你本地装的是JDK 1.8,启动时会报
UnsupportedClassVersionError。处理方案是,要么降低Springboot版本到2.x系列,要么升级JDK。我的建议是如果只是为了跑通项目,优先降Springboot版本,改动最小。 - Maven下载依赖失败或极慢:大概率是没有配置阿里云镜像源。打开Maven的settings.xml文件,在mirrors节点添加阿里云的
central仓库地址,然后重新执行mvn clean install。 - npm install失败或某个依赖版本不兼容:可以尝试删除项目的node_modules目录和package-lock.json,再执行
npm cache clean --force,最后重新npm install。如果是某个特定依赖报错,用npm install 包名@指定版本锁定版本安装。
6.2 前后端联调阶段的经典翻车现场
前后端联调时的报错大多数都集中在跨域、请求路径不对、参数格式不匹配这三类。跨域问题优先检查后端的CORS配置是否放开,以及前端的proxy是否配置成功。如果前端请求的URL是/api/user/login,而后端Controller的RequestMap是/user/login,那服务器就会直接返回404,这种问题可以通过看浏览器Network面板的请求地址快速定位。参数格式不匹配最常见的场景是日期类型,前端传的是String,后端用Date接收,不处理就报格式错误,解决方案是在DTO的日期字段上加上@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")注解,或者在全局配置里注册一个Jackson的日期反序列化器。
6.3 推荐结果的评价与系统扩展建议
推荐效果怎么评价,是很多人忽略的环节。最简单也最有效的指标是“点击率”和“收藏转化率”。可以后台上线一个统计接口,每天统计推荐位内容的点击次数和收藏次数,除以当天的推荐曝光量,就能看到算法效果的大致好坏。如果点击率偏低,优先检查推荐内容是否和用户真实需求错位,比如给减脂用户推了一堆增肌食谱,那大概率是标签体系没建好。
如果后续想把这个系统做得更专业,可以在架构不变的基础上做三件事:第一,引入Redis缓存用户特征和推荐列表,提升接口并发性能;第二,用Elasticsearch替换MySQL的模糊搜索,提升健康资讯的搜索体验;第三,接入一个简单的内容审核服务,保证健康类文章内容的合规性和安全性。这几步做完,系统从毕业设计水平直接向商用项目水平迈进。
6.4 几个让我印象深刻的排除故障记忆
我自己在部署这类项目时,遇到过一个非常隐蔽的问题:后端在本地运行一切正常,部署到服务器后,前端登录接口一直超时。排查了半天,最后发现是云服务器的安全组规则没有放行8080端口。这个不算技术问题,但特别容易忽略,遇到线上环境接口不通时,第一件事不是检查代码,而是先确认端口有没有对外开放。
还有一次是Vue项目打包后页面能打开,但一旦刷新某个子路由页面就404。这个就是前面提到的history路由模式部署时的老问题,Nginx配置里加上location / { try_files $uri $uri/ /index.html; },把所有请求都引导到入口文件即可。
做这种全栈项目,踩坑是常态,但只要记住一个核心排查原则——从外到内逐层处理浏览器开发者工具的Network面板、后端日志、最后才是代码调试,大部分问题都能在几分钟内定位。项目推进过程中,我发现一定不要等到所有代码写完了再部署,而是尽早把前后端一键启动脚本、数据库初始化脚本、部署说明文档准备好,这些“非功能性需求”往往能给你省下大量重复沟通的时间。最后再分享一个小技巧,开发前花两小时把Likert量表式的数据字典(比如所有行为类型、内容分类、推荐原因的枚举值)先定义好,后面的工作会顺畅到你不敢相信。希望这篇拆解能在你的开发路上帮上一点忙。