
1. 项目从0到1的整体思路与破局点1.1 毕设题目拆解导师到底想让你做什么先把这个题目挖透。对于springboot个性化新闻推荐系统的设计与实现这个毕设命题很多同学第一反应是我要写一个新闻网站然后就一头扎进增删改查里最后做出来一个带登录注册的CMS系统——这在答辩现场几乎就是自杀式操作。导师想看到的不是一个新闻内容的展示平台而是推荐链路你有多少路召回、怎么融合排序、如何做用户画像、怎样在无历史行为时完成冷启动。题眼在个性化三个字上不在新闻上。所以正确的开局方式是把系统拆成三层底层是新闻内容管理和用户行为采集这部分就是常规CRUD用来打底中间层是用户画像和新闻特征建模这是推荐算法的数据地基顶层是召回-过滤-排序的推荐引擎这是系统的核心亮点。三层都做扎实了这个项目在毕设里就是妥妥的A档水平。1.2 技术选型为什么是Spring Boot而不是别的技术选型这块直接说结论Spring Boot 2.7.x MyBatis-Plus Redis MySQL 8.0推荐算法用基于内容和协同过滤的混合策略前端用Thymeleaf Bootstrap不要上Vue前后端分离不要上微服务不要搞Elasticsearch。为什么这么选Spring Boot的自动配置和起步依赖能让你把所有精力集中在业务和推荐链路上而不是浪费在配置XML和jar包冲突上。选MyBatis-Plus是因为分页插件和条件构造器写起来太顺手了做后台管理系统能省三分之一的时间。Redis在这里承担两个角色一个是缓存热点新闻列表另一个是存储用户的实时行为特征后面讲推荐链路的时候你会看到它的价值。这里要踩过坑才有发言权不要为了显得高大上引入你驾驭不了的技术栈。我用Elasticsearch做过一版结果数据同步、分词器配置、查询DSL折腾了两个星期推荐效果并没有本质提升。毕设的核心是把你用到的每个技术讲清楚为什么需要它而不是堆砌名词。1.3 项目日程规划7天环境 20天核心 7天收尾这套系统从零到完整可演示我建议的节奏是35天左右每天投入3到4个小时完全来得及。前7天把基础设施全部搞定MySQL建库建表、Spring Boot工程初始化、MyBatis-Plus接入、Redis装上、前端页面骨架搭出来确保一个最简单的查询新闻列表接口能跑通全链路。中间20天攻坚核心功能新闻管理模块、用户注册登录、行为埋点、推荐引擎三路召回和融合排序这是系统的主体。最后7天做两件事一是查漏补缺把流程走顺确保演示的时候不出意外二是把README和系统架构图写好这些是答辩PPT的素材。这个安排里最容易翻车的是第一周。很多人花了两周还在纠结JWT还是Session、前端模板用哪个其实这些决策在毕设尺度上怎么选都能用。先跑通再优化这是过来人的忠告。2. 系统设计与数据库建模的核心细节2.1 功能模块划分六个模块怎么各司其职整个系统我从功能上切成了六个模块每个模块的边界必须清晰否则后期维护会非常痛苦。第一个是新闻管理模块负责新闻的发布、编辑、上下架和分类管理。这个模块可以在后台直接录入新闻也可以做一个爬虫脚本定时抓取新闻数据到数据库爬虫脚本我建议单独放一个子项目里不跟主系统耦合。第二个是用户模块注册、登录、个人偏好设置。用户注册时勾选感兴趣的新闻分类这个信息是冷启动阶段的重要信号。第三个是行为采集模块用户对新闻的浏览、点赞、收藏、评论这些动作都要记录下来。这是整个系统最容易做砸的地方——很多人把行为数据直接写进MySQL结果数据一多查询就慢。我的做法是行为日志先写到Redis的List里再由定时任务批量刷入MySQL既能扛住并发又不会丢数据。第四个是用户画像模块基于用户历史行为计算用户的分类偏好向量、标签向量和活跃度指标。第五个是推荐引擎模块把召回、过滤、排序、缓存这一整套链路封装成服务。最后一个就是系统管理后台做新闻审核、用户管理、数据统计看板。2.2 数据库表结构设计七张核心表的字段与关联数据库设计直接决定了推荐算法的实现复杂度我把核心表结构列出来讲清楚每个字段存在的意义。用户表tb_userid、username、passwordBCrypt加密存储、preferred_categories用JSON数组存储注册时勾选的分类ID、interest_tags系统根据行为自动更新的标签集合、status、create_time。这个表的关键在设计preferred_categories和interest_tags这两个字段前者是冷启动的种子数据后者是画像更新的结果。新闻表tb_newsid、title、summary、content、category_id、tagsJSON数组人工打标或自动关键词提取、source、publish_time、view_count、like_count。view_count和like_count是冗余计数字段用于热度排序避免每次推荐都现算聚合。行为表tb_behaviorid、user_id、news_id、behavior_type1浏览、2点赞、3收藏、4评论、score行为权重分、create_time。这个表是推荐算法的核心数据源每一行都代表用户的一次真实反馈。用户画像表tb_user_profileid、user_id、category_prefJSON对象格式为{分类ID: 权重分}、tag_prefJSON对象标签权重、last_update_time。注意这个表是不存实时数据的它会由一个定时任务每隔15分钟从行为表聚合生成。分布式定时任务可以考虑用xxl-job后期会写具体方案。新闻标签表tb_news_tagid、news_id、tag、weight。新闻的标签从标题和摘要里用HanLP的依存句法分析提取TF-IDF关键词得出这个表给基于内容的召回用。相似新闻表tb_news_similarid、news_id、similar_news_id、similarity。这是离线任务预计算好的相似新闻集合推荐时直接查询不能在线实时计算否则接口会卡死。行为事件表tb_event_log记录用户每一次操作的日志明细包含event_id、user_id、news_id、event_type、event_data、create_time。这七张表之间的关联逻辑用户行为表是流水的账单画像表是账单汇总出来的报表新闻表是商品目录相似表和标签表是商品的特征描述。记住一个原则能离线预计算的不要在线算能在内存里算的不要查数据库。这个原则贯穿整个推荐系统设计。2.3 行为权重设计浏览、点赞、收藏、评论怎么打分行为数据是推荐算法的燃料但不同类型的用户行为代表不同的兴趣强度不能简单一刀切。我的权重方案是浏览记1分点赞记5分收藏记8分评论记10分。为什么这样分浏览可能是误点权重最低。点赞说明用户觉得不错中等权重。收藏的行为意图更明确——用户想以后再看代表较强的兴趣。评论付出的成本最高权重自然最高。这个方案不是拍脑袋定的爽快的话可以参考电商推荐里常用的行为价值金字塔。权重方案需要在系统里做成可配置项不要写死在代码里。你可以在系统配置表sys_config里加一行key是behavior_weightvalue是JSON格式的权重配置。答辩时这句话很加分权重参数通过配置中心动态调整不需要重启服务。有了行为权重后用户对分类的偏好计算就简单了用户在某分类下的得分 用户在该分类下所有行为的权重分之和最后做归一化处理把得分映射到0到1之间。同理用户对标签的偏好也是这样算。这个计算过程用一条SQL加一段Java代码就能搞定后面会给出具体实现。3. 推荐链路核心实现从召回、过滤到排序3.1 三路召回策略时间衰减、内容相似、协同过滤推荐系统的第一个核心环节是召回就是从海量新闻里快速筛出几百条候选集。只用一路召回结果太单一我的方案是三路并行召回最后做融合。第一路是热度召回考虑到新闻的时效性热度分 基础热度分 * 时间衰减因子。基础热度分用新闻的浏览量、点赞数、评论数加权求和时间衰减用牛顿冷却公式模拟。这个机制的通俗理解就是一条新闻越老权重越低像热点事件一样三天前的消息在推荐列表里要让位给最新内容。公式是score_now score_initial * exp(-decay_rate * age_hours)decay_rate建议设0.02左右也就是一条新闻大概两天热度降到初始值的一半。这条路保证推荐列表里有最新的内容解决新闻领域的时效性问题。第二路是基于内容的召回核心逻辑是找出与用户历史行为里高评分新闻相似的新闻。用户点赞了一篇关于人工智能的新闻系统就找到其他打了人工智能标签或者跟它相似度高的新闻推荐出来。实现上先去用户行为表里取出用户最近点赞、收藏的新闻ID列表再查相似新闻表拿到候选集最后过滤掉用户已经看过的。这条路用不到复杂的词向量直接基于标签重合度就能做。第三路是基于用户的协同过滤召回就是找到和当前用户兴趣最相似的邻居用户看看他们在看什么。计算用户相似度用余弦相似度或者皮尔逊相关系数这套逻辑对毕设来说足够了。协同过滤的好处是能发现用户自己都没意识到的兴趣点而基于内容的推荐容易让用户陷入信息茧房。两路互补这是混合推荐的核心理由。3.2 过滤与去重三个必须处理的脏数据场景召回回来的候选集通常有两三百条其中混着大量用户已经看过的、重复主题的、时效过期的新闻直接排序推荐体验会非常差。过滤环节我做了三层第一层是行为过滤查Redis里的用户已读新闻ID集合批量排除用户已经看过的新闻。已读集合用Set结构存储key是read:news:{userId}每次用户浏览新闻时往集合里加新闻ID。这里要注意集合不能无限增长可以只保留最近30天的记录用定时任务定期清理。第二层是时效过滤发布超过72小时的新闻退居二级候选这个时间窗口可以配置新闻领域的消费周期就是72小时左右太久的内容没有推荐价值。第三层是质量过滤标题空、内容过短少于100字、无标签的新闻直接拿掉宁缺毋滥。3.3 融合排序策略为什么我放弃了纯公式加权三路召回会产生多个候选集合怎么融合成一个最终列表是个关键问题。最简单的方案是加权求和final_score 0.4 * content_score 0.3 * collaborative_score 0.3 * hot_score。我一开始就是这么做的但很快发现问题当用户的历史行为很少时content_score和collaborative_score都算不准排序结果基本被热度和随机性主导个性化不足。后面我调整了策略改成分层透传优先级最高的是用户近期偏好标签直接匹配的新闻这个列表认为质量最高固定排在前面其次是协同过滤召回的高邻居分新闻最后才是热度补位。每层内部再用公式加权排序。这种策略的效果比纯公式加权稳定很多而且有一个额外的好处——答辩时讲起来逻辑特别清晰每一步都有明确的业务含义。最终分排序公式可以写成rank_score 0.45 * 用户匹配度 0.35 * 时效性得分 0.20 * 行为反馈热度其中用户匹配度是指用户画像中分类权重与新闻分类的匹配值。这个公式的权重同样做进配置中心方便调整。3.4 Redis在推荐链路里的三个使用位置Redis在这个系统里不是可有可无的装饰品三个位置缺了它整个链路跑不动。第一个位置是热度榜缓存用ZSet存储热门新闻ID和热度分key是hot:newsmember是新闻IDscore是热度分。定时任务每5分钟更新一次同时淘汰掉过期新闻。推荐接口读排序列表时直接读这个ZSet不要查数据库排序。第二个位置是用户行为实时流用户浏览、点赞等行为发生时先写入Redis的List结构key是behavior:queue:{userId}然后由后台线程批量落库。这样既不影响前端的响应速度又能在用户画像实时计算时快速拿到最新行为。第三个位置是已读新闻集合前面说过用Set结构存储。推荐前先从Redis批量检查哪些新闻用户看过了直接过滤掉避免让用户反复看到同一条新闻。这三个位置的代码实现后面统一给出。4. 用户画像构建与新闻特征提取的工程实践4.1 基于行为日志的用户画像聚合算法用户画像本质上是一个加权词袋模型。我采用的维度有分类偏好、标签偏好、活跃时段、阅读深度四个维度。前两个维度是推荐算法的主力后两个维度用来辅助排序和优化推荐时机。分类偏好的计算逻辑遍历用户最近30天的行为数据按分类ID分组每组累加行为权重分最后除以所有分类的总分做归一化得到用户对每个新闻分类的偏好概率。算法只在每天的凌晨跑一次全量白天每15分钟跑一次增量增量更新只需要把新增行为加权合并到已有的画像向量里即可。标签偏好的计算逻辑类似但有一个细节要注意标签的粒度比分类细得多噪声也大。有些标签用户只碰过一次比如特朗普弹劾案不代表他真喜欢这个领域。所以我在聚合时只保留出现次数不低于3次的标签且行为权重分累计值不低于10。宁缺毋滥标签太碎会让推荐结果显得莫名其妙。4.2 新闻内容特征的自动提取方案给新闻打标签是这个项目的一大工程量。手动打标是不可能完成的必须自动化。我的方案分两步第一步是关键词提取。把新闻标题和摘要拼接后用HanLP的TF-IDF算法提取Top 10关键词作为候选标签。HanLP的依赖很干净直接引入maven坐标就能用分词和关键词提取的效果对比jieba更适合做这个场景。第二步是实体识别。用HanLP的命名实体识别功能把新闻中的人名、地名、机构名识别出来作为实体标签。这两种标签存储时加一个type字段区分后续计算相似度时关键词权重给0.7实体权重给0.3。提取好的标签存进tb_news_tag表作为内容相似度和用户标签匹配的依据。这部分工作的耗时主要不在写代码而在调参数关键词提取器的Top N设多少合适TF-IDF的平滑系数选什么值都需要拿一批真实新闻测试效果。4.3 冷启动问题的三层解决策略任何推荐系统都逃不过冷启动问题新用户和新新闻都会导致推荐算法没有数据可用。我的三层策略是这样的第一层是新用户冷启动注册时让用户勾选感兴趣的新闻分类。这一条信息虽然粗糙但比没有强太多。推荐引擎在用户没有行为数据时直接用注册分类匹配对应分类下的热度榜新闻加上随机偏移量打散排序避免推荐列表全是同一家的内容。第二层是新新闻冷启动新闻发布时间在2小时内的推荐引擎会给它一个新品加权。具体做法是在排序公式里给时效性因子加一个boost值让新新闻有更多曝光机会用曝光量换反馈数据。第三层是行为稀疏用户冷启动有些用户注册后从来不勾选偏好也几乎没有行为。对这类用户系统直接退化为热门推荐推送全站热度最高的新闻。等用户产生行为后再逐步加大个性化权重。这条策略在答辩时一定要讲冷启动是推荐系统的经典话题导师一听就知道你做过功课。5. 系统实现的重难点从Spring Boot配置到答辩加分项5.1 环境准备与工程结构开发环境建议JDK 1.8、Maven 3.6、MySQL 8.0、Redis 6.x、IDEA。Spring Boot的版本选了2.7.18这是2.x系列最后的一个版本稳定且不会因为3.x的包名变化带来额外麻烦。工程模块结构上用Maven多模块还是一单个Spring Boot工程对于毕设级别的系统单工程就行但包结构要清晰。我推荐的包划分是controller接口层、service业务层、mapper数据访问层、model实体类、recommend推荐引擎、config配置类、util工具类、task定时任务。把recommend单独拆一个包出来而不是混在service里是为了代码审查时有清晰的推荐链路入口。在pom.xml里核心依赖是spring-boot-starter-web、mybatis-plus-boot-starter、spring-boot-starter-data-redis、hanlp、fastjson2。MyBatis-Plus的分页插件需要在配置类里注册这个容易忘配好之后写分页查询会非常爽。application.yml里三个关键配置数据源、Redis连接、MyBatis-Plus日志。数据源建议用Druid因为它的监控页面在本地调试时能直观看到SQL执行情况。Redis的配置里要设置连接池参数默认的lettuce连接池在并发一高就会报连接不够。5.2 推荐引擎核心代码实现召回、排序与Controller示例下面给出推荐引擎的骨架代码这是整个系统的核心部分。先写一个推荐服务接口public interface RecommendService { // 获取用户的个性化推荐列表 ListNewsVO recommendForUser(Long userId, Integer size); }然后是召回和排序的核心实现类。这个类的逻辑不要写在Controller里也不要写在Service里单独放命名一个RecommendEngine职责边界清晰Service public class RecommendEngineImpl implements RecommendService { Resource private NewsMapper newsMapper; Resource private UserProfileMapper userProfileMapper; Resource private BehaviorMapper behaviorMapper; Resource private RedisTemplateString, Object redisTemplate; Override public ListNewsVO recommendForUser(Long userId, Integer size) { // 1. 三路召回返回候选集合和对应得分 ListRecCandidate contentCandidates contentRecall(userId); ListRecCandidate cfCandidates cfRecall(userId); ListRecCandidate hotCandidates hotRecall(); // 2. 过滤已读 ListLong readIds getReadNewsIds(userId); filterRead(contentCandidates, readIds); filterRead(cfCandidates, readIds); filterRead(hotCandidates, readIds); // 3. 融合排序 ListRecCandidate merged mergeAndRank( contentCandidates, cfCandidates, hotCandidates, userId); // 4. 截断返回 return merged.stream().limit(size).map(this::toVO).collect(toList()); } }这个类的核心思想是召回只是粗筛真正决定推荐结果的是融合排序这里的逻辑。contentRecall方法基于用户画像中的高权重标签去匹配新闻表的tags字段cfRecall方法先查用户相似度表找到Top 10邻居再取邻居点赞过的新闻hotRecall直接读Redis的ZSet排行榜。三个方法的实现细节都比较常规。排序合并之后给每个候选新闻计算最终分按分数降序截断前面N条返回。这里建议在返回前做一次日志记录把每个新闻的召回来源和各项分数都打出来调试时看日志就能知道为什么某条新闻排在前面这是排查推荐效果不好的第一手段。最后是Controller层的代码注意接口要返回统一结构体。统一返回结构体类我用的是最基础的Result包含code、message、data三个字段。推荐接口的URL路径建议是/api/recommend/news请求参数只有userId和size。前端页面拿到这个接口的数据渲染推荐列表。5.3 关键词提取与相似度计算的落地代码关于新闻标签的关键词提取使用HanLP来完成TF-IDF关键词提取。简单说明用法import com.hankcs.hanlp.HanLP; import com.hankcs.hanlp.seg.common.Term; import java.util.List; import java.util.stream.Collectors; // 提取摘要 ListString keywordList HanLP.extractKeyword(content, 10);代码极简单但要注意两个坑第一HanLP默认的词性标注库和模型在首次加载时需要联网下载联不上网会报错解决办法是提前手动下载数据包放到指定目录第二对很短的内容做关键词提取效果很差所以新闻的摘要不能太短最好在200字以上。新闻相似度的计算采用Jaccard相似度public double jaccardSimilarity(SetString tagsA, SetString tagsB) { if (tagsA.isEmpty() || tagsB.isEmpty()) return 0.0; SetString union new HashSet(tagsA); union.addAll(tagsB); SetString inter new HashSet(tagsA); inter.retainAll(tagsB); return (double) inter.size() / union.size(); }这个算法在标签数量少时效率很高比漫无目的地用词向量去算文本相似度更快更容易解释。相似度计算的结果写入tb_news_similar表作为离线预计算任务每天跑一次推荐引擎运行时直接查表。此外还可以研究一下如何给新闻增加时效分。可以使用差值衰减或者指数衰减模型我的做法是指数衰减因为指数衰减对新闻这种强时效性的内容更友好。5.4 答辩演示效果升级系统界面与数据可视化辛辛苦苦做出来的系统答辩演示时一定要有一个一眼惊艳的效果这部分投入时间很值。第一个加分项是推荐效果对比页面。做一个单独的调试页面输入用户ID就能看到该用户从头到尾的推荐列表同时标注每条新闻的推荐理由标签比如因为你关注了人工智能因为相似用户也看过。把三个不同画像的用户推荐列表放在同一个页面左右对比视觉冲击力远大于单纯展示新闻列表。第二个加分项是用户画像雷达图用ECharts做了一个可视化的分类偏好展示。用户在系统里点击我的兴趣分析就能看到自己的分类偏好雷达图选中的分类实时高亮。这个功能实现成本很低但答辩时导师一定会感兴趣。第三个加分项是Druid监控页面。开启Druid的StatViewServlet在本地环境可以看到SQL执行频率、慢查询统计、并发情况。演示时切到这个页面再对比一下不使用缓存和走Redis缓存时的响应时间差异数据比任何假设都有说服力。第四个加分项是Redis可视化工具比如使用RDMRedis Desktop Manager演示时展示Redis里实时变化的用户画像、已读集合和热度榜证明系统的缓存和实时计算是真的在运行的。5.5 数据处理与内容治理版权合规的新闻数据获取新闻数据从哪来这是一个避不开的问题。第一网上随便爬取别人的新闻内容用于毕设在版权和合规角度是不严谨的这类做法要坚决避免。第二我推荐的做法是面向教学和毕业设计场景自建一个可控的数据集。具体操作方式用网上公开的新闻标题和摘要做种子集但只保留元数据不复制正文。新闻正文可以自己编写通用占位内容或使用公开的文本语料库生成摘要。给新闻打标签的逻辑不变推荐链路照常走既不影响系统功能演示也规避了版权风险。在论文和答辩PPT中要说明项目数据来自自建教学数据集用于算法验证和功能演示这句话虽然朴素但能体现你在数据治理上的意识这反而是一个加分项。实际上这里还有一条更稳妥的路直接用Java写一个随机的新闻模拟器随机生成新闻标题、摘要、分类和标签数据量能生成10万条级别的模拟数据足以让推荐算法跑出效果。日志数据也可以自己循环造出来写法非常简单就是随机数加时间戳。值得一提的是这个模拟造数工具本身也是工作量的一部分可在论文里写系统内置数据增强工具用于推荐算法效果验证。6. 本地运行与测试Bug排查和效果验证实录6.1 Spring Boot启动过程中的常见连环坑本地启动这个项目环境问题比代码问题更容易卡住。按下面的顺序排查至少节省三天时间。第一个大坑是MyBatis-Plus和Spring Boot版本不兼容。如果你用的MP版本是3.4.x以下配合Spring Boot 2.7使用会报Invalid bound statement错误。解决办法是确保mybatis-plus-boot-starter版本不低于3.4.2同时在启动类上加上MapperScan注解。这个注解漏写的话所有Mapper都会报找不到Bean非常隐蔽。第二个大坑是Redis连接失败。Spring Boot 2.x默认的lettuce连接池在Redis密码为空、本地环境时也会暴露问题。解决办法是在application.yml里把lettuce的shutdown-timeout调大并且确保Redis服务端没有绑定保护模式。如果本机没装Redis用Docker跑一个是最省事的docker run --name redis -p 6379:6379 -d redis:6。第三个大坑是Druid连接池的wall过滤器误杀SQL。Druid默认开启了防火墙MyBatis-Plus的分页插件生成的SQL偶尔会被拦截报出sql injection violation。解决办法是在Druid配置里关闭wall过滤器本地开发环境不需要这层防护。第四个大坑是主键类型用错导致新增数据失败。MyBatis-Plus的雪花算法主键是Long类型如果你数据库表的id字段定义成了int插入超过一定行数就会溢出报错。建表时id字段直接定义成bigint避免返工。6.2 推荐效果不理想先看数据再调算法推荐系统的调试和普通Bug调试完全不同不能靠IDE断点去跟。我的调试方法是先看推荐日志里每条新闻的召回来源和各项得分确认数据本身有没有问题再判断是算法的问题还是数据的问题。数据层面的常见问题行为表里数据量太少总共不到100条怎么调算法都没有意义。解决办法是先运行模拟造数脚本给若干个虚拟用户生成足够多的行为数据把数据量撑到几千条量级。另外用户画像的定时任务是否真的在跑——很多人写完定时任务就直接忘了画像表里根本没有数据推荐引擎拿到空画像自然只能全部走热度兜底。算法层面的常见问题相似新闻表的相似度普遍偏低因为标签提取的质量太差或者新闻内容太短导致关键词重复度低。这个时候不用急着改算法先把标签提取的关键词打印出来看看分词不合理就调停用词表标签太碎就适当增加TF-IDF的Top N值。调试推荐系统一定要有耐心它的反馈周期比普通功能长得多。你改完算法需要等用户行为写入画像下次推荐时才能看到效果变化。在这个等待期间可以把日志加上、把监控面板打开观察数据变化而不是干等着刷新页面。6.3 推荐Controller接口的单元测试与性能压测毕设里如果能有一段像样的测试代码会显得项目完整性很高。我在系统里写了两个测试类一个是推荐服务的单元测试另一个是本地方便对接的接口联调测试。推荐服务的单元测试核心逻辑是构造一个已知画像的用户调用recommendForUser方法断言返回列表不为空、新闻数据合法、没有重复新闻。对于推荐的个性化效果更简单有效的验证方法是创建两个画像完全不同的账号比如一个偏好科技、一个偏好体育在日常使用中积累行为数据然后比对两个账号在同一个推荐接口返回的内容差异。如果两边的推荐列表有明显差异说明个性化在起作用如果两边结果几乎一样说明推荐链路哪里断了。压测就简单多了用Postman或者JMeter模拟并发请求观察推荐接口在100并发下的响应时间。如果响应时间飙升到几秒优先检查数据库连接池是否太少、Redis是否没生效、SQL是否走了全表扫描。这里有一个很实用的优化手段给行为表和新闻表的常用查询字段加上联合索引查询性能能提升一个数量级。7. 系统优化和扩展从毕设跑通到优秀答辩7.1 流程引擎Flowable做内容审核流程Spring Boot相关的热词里经常出现flowable毕设里如果能把这个工作流引擎嵌入进来确实会提高项目的完整度。但我的建议是项目主体功能全部跑通后如果有富余时间再引入Flowable做新闻审核流程不要把流程引擎放在第一阶段做它是个时间黑洞。如果决定要引入具体方案是新闻发布后进入流程引擎创建审核任务审核人通过Flowable的TaskService完成任务新闻状态从待审核变为已发布。这个流程简单但展示了工作流引擎的用法答辩时可以讲清楚流程变量、任务节点、网关三个概念已经足够证明你用过Flowable了。需要提一句的是Flowable的数据表有几十张不要重复初始化数据库避免跟业务数据表混在一起。7.2 推荐效果评估除了讲准确率还能讲什么毕设答辩时导师一定会问效果怎么评估。只有演示截图是不够的建议在论文里和答辩PPT里放上离线评估数据。最简单的评估方式是在本地模拟一批用户行为数据把行为数据按时间切分为训练集和测试集前80%时间做训练后20%做评估。用训练集生成用户画像然后对测试集里的用户行为进行预测——判断系统是否推荐了用户实际点击的新闻。统计出覆盖率、命中率以及推荐列表里新闻的多样性指标。对于毕设级别来说命中率做到20%以上覆盖率推荐过的新闻数占新闻总数的比例尽量高于60%就已经是一个不错的效果了。加分项是在论文里画出两个曲线召回率和精确率的权衡曲线、不同Top N推荐数量下的效果对比表。多花一点时间做这些答辩时的底气是不一样的。7.3 论文和答辩PPT的黄金结构最后说说论文和答辩怎么包装直接决定你的工作量能不能被看见。论文结构建议按这个顺序写第一章绪论背景、意义、现状第二章关键技术Spring Boot、推荐算法、Redis第三章需求分析功能需求、数据需求、非功能需求第四章系统设计架构、数据库、接口第五章系统实现核心代码、页面截图第六章系统测试测试用例、效果评估。答辩时PPT控制在15页以内核心讲三件事系统能做什么——展示演示视频或现场操作系统怎么做的——架构图加核心链路图效果怎么样——评估数据加对比图。答辩答辩关键在于逻辑闭环你选择的方案是为了解决你分析出的问题你做的测试是为了验证你的方案有效。把这根线串起来评委就很难把你问住。从我自己的实际经验来看最容易被追问的点反而是那些看起来很简单的技术决策比如为什么Redis存的是用户已读集合而不是新闻详情、为什么用Jaccard相似度而不是余弦相似度、为什么定时聚合画像而不是实时流式计算。每个决策都准备一两句因为...所以...的答案这个答辩就稳了。