新闻详情

新闻详情

首页 / 资讯中心 / 详情

基于Java的新闻搜索与热点排行系统:Spring Boot + ES + Redis 毕设实战

发布时间:2026/9/15 3:35:31来源:尧图网络
基于Java的新闻搜索与热点排行系统:Spring Boot + ES + Redis 毕设实战
1. 项目到底做什么需求拆解与毕设选题价值1.1 题目背后的真实业务场景这个题目看起来像是三个系统拼在一起——“热点新闻搜索系统”“智能热点新闻检索与管理平台”“新闻发布与互动交流系统”其实背后是一个非常典型的互联网内容平台业务一套完整的新闻资讯类网站。你在毕设答辩时要给老师讲清楚的不是“我写了多少代码”而是“我理解了一个真实产品需要什么”。拆开来看这个项目至少要覆盖这样几条业务线用户能注册登录、浏览新闻、搜索新闻、看热点排行编辑/管理员能发布新闻、审核内容、管理分类、管理用户普通用户能对新闻点赞、收藏、评论。如果你只做一个单表的增删改查那就浪费了这个题目。它本质上考察的是 Java Web 开发中非常核心的几个能力点检索系统的设计与实现、热度算法的数据建模、内容管理系统的权限与状态流转、高并发场景下的读写分离设计。我见过很多学生在答辩时说“我的项目是一个新闻系统”结果演示的时候只有管理员后台增删改查没有前台搜索没有互动没有热点榜。这种项目不是不能过但很难拿高分。而如果你把搜索、热点、互动这三条线做扎实再配上一个说得通的架构设计这个项目完全可以在简历上写“独立设计并实现了一个日均承载百万级查询的新闻检索与推荐平台”面试官也愿意往下聊。这个题目适合谁来参考如果你是正在准备 Java 方向毕业设计的本科生或者工作一两年想补一个完整项目经验的开发者再或者想用一套现成的 Spring Boot Elasticsearch Redis 最佳实践来练手的读者这篇文章都能给你一套可直接落地的方案。1.2 技术选型思路为什么是这一套组合技术选型这件事很多学生容易犯两个极端要么全部用最基础的 JDBC Servlet JSP显得太老要么一上来就微服务 Docker K8s 全家桶结果自己都跑不起来。我的建议是选一套能自圆其说、能在答辩现场稳定跑起来、并且每个选型都能讲出理由的技术栈。我的推荐组合是这样的层次技术选型选择理由后端框架Spring Boot 2.7.x MyBatis-Plus约定大于配置开发效率极高MyBatis-Plus 的分页插件和条件构造器能减少大量 CRUD 代码数据库MySQL 8.x存储结构化业务数据事务有保障缓存Redis热点新闻列表、搜索热词排行、用户登录态都放这里检索引擎Elasticsearch 7.x IK 分词器新闻搜索的核心组件支持全文检索、高亮、分词权限认证JWT Spring 拦截器或 Spring Security前后端分离场景下 JWT 比 Session 更合适前端Vue 3 Element Plus或 Thymeleaf如果你前端基础弱用 Thymeleaf 模板引擎可以少写很多代码想加分就用前后端分离任务调度Spring Scheduled定时计算热点榜、定时同步 ES 索引、定时刷新阅读数讲清楚为什么选这套组合本身就是答辩时的一个加分点。Spring Boot 是当前 Java 后端的事实标准面试官看到不会觉得陌生Elasticsearch 是整个项目的亮点因为新闻搜索系统天然适合用 ES 来展示倒排索引、分词、相关性评分这些概念Redis 用来证明你理解了缓存穿透、缓存击穿、缓存雪崩这些高频面试题JWT 则对应了无状态认证的设计思想。这里有个重要的取舍如果你机器配置一般或者不熟悉 ES 的安装可以先在本地用 MySQL 的 LIKE 查询做一版再预留一个 EsSearchService 的接口把搜索引擎替换进去。这样既保证了项目能跑又能体现你对架构扩展性的理解。我后面会详细讲这套“先 MySQL 后 ES”的两阶段落地方式。2. 数据库设计一张表一张表地拆2.1 用户体系、角色权限与登录状态管理数据库是整个系统的地基。很多毕设项目垮掉都是因为表设计没想清楚就上手写代码结果发现新闻要加个标签字段评论要加个回复类型用户要加个封禁状态然后一路改表改到崩溃。所以先坐下来把 ER 图想明白是真的能省下一个月的返工时间。这里我直接给你一套经过验证的建表方案。第一张表是用户表user它要能覆盖多角色场景。最简单的方案是用一个role字段区分普通用户USER、编辑EDITOR和管理员ADMIN。字段上除了常规的id、username、password、nickname、avatar之外我强烈建议加一个status字段用来表示账号是否被禁用。为什么因为新闻平台必然面对内容安全的问题被举报的账号要能一键封禁这个字段在后台管理里几乎是必须的。第二张是与登录态相关的设计。如果你用 JWT那你不需要建 Session 表但需要给每个用户一个token维度吗不需要。JWT 本身就是无状态的服务端只要保存一个私钥用于验签就行。但这里有一个最常见的坑用户的账号被禁用之后他手里的 JWT 仍然有效。解决办法是在 Redis 里存一份“用户状态版号”或者“被封禁用户黑名单”每次请求时拦截器里查一下。这个细节做出来答辩的时候可以直接讲“我通过 Redis 黑名单解决了 JWT 无法主动失效的问题”一听就是有实战经验的人。再说权限这块。我建议不要一上来就引入 Spring Security Redis 动态权限那套重武器毕设项目用拦截器 注解就能讲清楚。比如自定义一个RequireRole(EDITOR)注解用 Spring AOP 或拦截器去判断当前用户角色。这里引入 AOP 概念你在面试时就能顺势讲“动态代理是 Spring AOP 的底层实现”把项目经验和 Java 基础串起来。2.2 新闻内容、分类标签与审核状态新闻表news是整个系统的信息主体这一点很直接。字段设计上需要包含title标题、summary摘要列表页用、content正文、cover封面图 URL、category_id分类、author_id作者、status审核状态、views浏览量、like_count点赞数、comment_count评论数、favorite_count收藏数、publish_time发布时间。这里有两个容易被忽略的细节。第一个是status的状态设计。新闻从创建到下线要经历DRAFT草稿、PENDING待审核、PUBLISHED已发布、REJECTED已驳回、OFFLINE已下线这几种状态。用 Java 枚举来管理这些状态而不是散落一地的魔法数字这本身就是 Java 基础能力的一个体现——用户热词里反复出现“java枚举类型的使用”把它用在项目里比背一百遍八股文都管用。第二个是“冗余字段”的取舍。like_count、comment_count这些数字其实可以从点赞表、评论表里count出来为什么还要冗余在新闻表里因为热点列表要按这些数字排序每次实时统计代价太高。这是典型的“读多写少用冗余”的场景也是面试官喜欢问的“数据库反范式设计”思路。分类表category很简单id、name、sort、status四个字段基本够用。如果你想让项目看起来更丰满可以再加一个tags的概念把标签用逗号分隔存在新闻表的一个字段里或者单独建一张新闻标签关联表。单独建关联表更规范但如果你时间紧用逗号分隔也说得过去因为多数场景只是展示用不做复杂聚合。2.3 互动数据、搜索日志与热点统计互动数据是新闻发布与互动交流系统的核心支撑。这里至少需要三张表comment评论表、user_like点赞记录表、user_favorite收藏记录表。评论表要支持楼层回复最简单的做法是加一个parent_id顶层评论这个字段为 0回复某个评论时填上对应评论的 id。存储上用一个content字段最多 500 字业务上要过滤敏感词这块可以用简单的 DFA 敏感词过滤或者用 Hutool 的SensitiveUtil也算是一个安全性的加分项。这里有一个性能层面的细节列表页展示评论时如果每条评论都做一次“查询该用户头像昵称”的关联查询数据量上来之后一定完蛋。我建议写一个批量查询接口把评论列表里的user_id收集起来一次性查出来再在内存里组装这个思路在技术面试里叫“避免 N1 查询问题”。点赞表和收藏表的建表方式几乎一样id、user_id、news_id、create_time然后对(user_id, news_id)建唯一索引。这样设计能保证一个用户只能对同一条新闻点赞一次——数据库层面的约束而不是靠代码判断。但要注意用户点了两次赞怎么办这里设计一个is_deleted逻辑删除字段第一次点赞插入记录第二次点赞就把这条记录的is_deleted翻转为 1而不是硬删数据。这样新闻详情的“是否点赞”状态查询就简单了。搜索日志表和热点统计表是“智能热点”和“热搜榜”的数据基础。search_log记录每一次搜索的关键词、用户、时间hot_word表按天聚合关键词和搜索次数。聚合可以不实时做用一个定时任务每隔 5 分钟把 Redis 里通过 ZSet 统计的热词写入这张表。这样热点榜就能区分“今天的热搜”和“本周的热搜”演示效果会好很多。3. 热点新闻搜索怎么落地核心模块实现3.1 检索模块从 MySQL LIKE 到 Elasticsearch IK搜索是“基于 Java 的热点新闻搜索系统”这个题眼也是最能体现技术深度的地方。如果你只是用WHERE title LIKE %关键词%那这个项目就没有亮点。但我也理解很多同学没接触过 Elasticsearch听到“分布式检索引擎”就发怵。借用我前面提到的两阶段方案我建议你这么安排第一阶段用 MySQL 先把业务跑通第二阶段把搜索引擎替换进来并在论文里写明两者的对比。MySQL 阶段的设计要点是建立复合索引比如(status, category_id, publish_time)用LIKE 关键词%做前缀匹配能走索引但%关键词%这种模糊查询是走不了索引的数据量大到几十万条时查询速度会明显下降。这个痛点就是你引入 Elasticsearch 的理由。ES 阶段的实现思路分四步第一步在pom.xml里引入spring-boot-starter-data-elasticsearch依赖版本要和你本地的 ES 对齐。这里我踩过一个大坑Spring Boot 2.7 对应的 Spring Data Elasticsearch 版本是 4.4.x它支持的 ES 是 7.17 之前稳定如果你装了 ES 8.x 的客户端会出现序列化兼容的问题。所以保守方案是Spring Boot 用 2.7.xES 用 7.17.x这是经过大量项目验证的稳定组合。第二步安装 ES 并配置 IK 分词器。ES 默认的standard分词器对中文是按单字切的“热点新闻”会被拆成“热”“点”“新”“闻”四个字搜索结果惨不忍睹。IK 分词器是中文搜索的标配它有ik_max_word细粒度切分和ik_smart粗粒度切分两种模式新闻标题建议用ik_max_word搜索关键词建议用ik_smart。用 Docker 起 ES 的话一条命令就能装上docker run -d --name es-hotnews -p 9200:9200 \ -e discovery.typesingle-node -e ES_JAVA_OPTS-Xms512m -Xmx512m \ docker.elastic.co/elasticsearch/elasticsearch:7.17.10第三步定义索引结构。在实体类上写Document(indexName news)然后手动在 ES 里创建索引mapping里给title、summary、content指定 IK 分词器。注意不建议用 Spring Data 的自动建索引功能它会用默认 mapping分词器配不上搜索效果还是差。第四步编写搜索代码。核心查询对象是NativeSearchQueryBuilder你可以同时匹配标题和摘要并给标题字段更高的权重然后打开高亮功能让搜索词在结果里用红色字体展示。这里每写一段都要记住一句话ES 查询匹配的是“倒排索引”它跟 MySQL 的 B 树是两种完全不同的数据结构做解释是答辩的得分点。3.2 热度算法设计不能只按浏览量排序热点新闻检索与管理平台之所以叫“智能”很大程度上体现在热度排行上。最简单的方法是按浏览量倒序排列但你会发现 10 天前的旧闻永远霸榜新发布的新闻永远上不了热搜——这不符合“热点”的直觉。业务上真正需要的是一套随时间衰减的热度分计算模型。我采用的方案是改良版的 Hacker News 热度算法公式如下hotScore (views * 1 likeCount * 3 commentCount * 5 favoriteCount * 8) / pow((ageHours 2), 1.5)拆解一下这个公式的每一个部分。分子是“内容质量分”点赞权重 3、评论权重 5、收藏权重 8权重设计的原则是“用户付出的行为成本越高权重越大”。浏览只是路过点赞需要动一下手指评论需要打字收藏则说明用户认为这条内容有长期价值所以收藏权重最高。分母的ageHours代表从发布时间到现在的间隔小时数2是为了避免除零pow(…, 1.5)指的是数衰减幅度——新闻发布前两个小时是黄金期热度分高得吓人24 小时后衰减到一半但优质内容依然能留在榜上。具体到实现我用 Spring 的Scheduled注解写了一个定时任务每 10 分钟跑一次SQL 查出来所有已发布的新闻在 Java 里算好hot_score更新到 Redis 的 ZSet 数据结构里。ZSet 天然支持按分数排行热点榜前 50 名直接从 Redis 里取毫秒级返回。定时任务的好处是“计算不阻塞请求”你甚至可以跟面试官说“我用了Async异步线程池来跑这个任务避免定时任务阻塞主线程”。除了新闻热度还有一个“热搜关键词榜”。这个不查新闻内容而是统计用户搜索行为。我的做法是用户每次搜索时把keyword写入一个叫hot:words的 Redis ZSet分数 1凌晨 2 点定时任务把当天的数据归档到 MySQL 的hot_word表。这样榜单展示的数据源就是“昨天/本周的搜索热词”而不是“全站累计的搜索词”。如果你想让热搜榜更有层次可以按时间窗口维护多个 keyhot:words:1h、hot:words:24h、hot:words:7d每个窗口的 TTL 时间不同窗口一过期数据自然清空这个设计在论文里写出来会非常漂亮。这里还要提醒一个细节不要每次用户刷新热搜榜就去实时聚合数据库这样的 SQL 会越跑越慢。正确做法是把榜单结果缓存到 Redis设置 5 分钟的过期时间。这就是面试里“缓存穿透、缓存击穿、缓存雪崩”那组问题的具体场景——后面的避坑章节我会专门讲。3.3 发布审核与互动交流状态机与异步化新闻发布与互动交流系统核心状态是“发布”和“互动”这两个动作的闭环。我在实际做这个模块的时候把流程设计成了这样编辑创建新闻时状态是DRAFT点击提交审核变成PENDING管理员审核通过变成PUBLISHED驳回变成REJECTED已发布的新闻可以手动下线变成OFFLINE。这几个状态转换在代码里要用枚举去约束避免出现“草稿直接跳下线”这类非法操作用一个NewsStatusEnum就能管理清楚这也是阿里的 Java 开发规范里明确推荐的枚举状态模式。互动模块最大的技术难点不是功能实现而是并发和性能。用户点一个赞传统写法是UPDATE news SET like_count like_count 1 WHERE id ?这条 SQL 本身没问题但高并发下会有两个隐患一是 MySQL 的单行更新会锁行热点新闻被疯狂点赞时这行记录就是性能瓶颈二是如果用户恶意点击点赞数会失真。我的方案是在逻辑上做两层防护应用层用一个 Redis Set 记录“已点赞用户”点赞之前先查 Set保证同一个用户只能点一次数据层写一个批量的点赞记录表业务上先插入user_like记录再通过异步线程池去更新news.like_count。评论模块的异步化是同理的思路用户提交评论后先返回“评论成功”真正的数据库写入和评论数 1 放到线程池里异步执行。这样用户感知不到延迟而且系统在突发流量下不会被打垮。实现上用ThreadPoolTaskExecutor定义一个线程池核心线程数 8最大 16队列容量 200拒绝策略用CallerRunsPolicy——在面试里把这个参数讲清楚比你背十道“java线程等待都完成”的题目都有说服力。关于新闻详情的浏览量我用的也是 Redis 方案浏览量先累加到 Redis 的 key 里比如news:views:1001定时任务每 30 秒把增量批量同步到 MySQL。为什么不是实时写因为浏览是最高频的操作如果每条浏览都打一次数据库数据库扛不住。缓存写 定时刷的设计在互联网公司里叫“最终一致性”用到这里正合适。4. 实操过程从空目录到可运行的项目4.1 环境准备与工程初始化这段写给可能还没完整搭过 Spring Boot 项目的同学。第一步是 JDK推荐用 JDK 1.8 或 JDK 11。这些年网上关于 Java 环境变量配置的教程一搜一大堆但很多都写得啰嗦或者过期了我给你一个精简版安装 JDK 的时候记得记下安装路径比如C:\Program Files\Java\jdk-11.0.21。配置环境变量时新建JAVA_HOME指向这个路径然后编辑Path在最前面加一行%JAVA_HOME%\bin。配置完成后打开命令行输入java -version能看到版本号就说明成功。注意配置完环境变量要把所有已打开的命令行窗口关掉重开这个问题每年能卡住一半的初学者。第二步是 Maven 的配置。国内访问 Maven 中央仓库很慢需要修改settings.xml里的镜像地址换成阿里云镜像。这个操作虽然简单但不配镜像的话你用 IDEA 创建 Spring Boot 项目可能要等十分钟。第三步是在 IDEA 里新建工程。建议用 Spring Initializr 生成一个基础的 Spring Boot 项目勾选Web、MySQL Driver、MyBatis-Plus从mvnrepository引坐标、Redis、Validation等依赖。工程建好之后标准包结构如下com.newsplatform ├── controller // 接口层 ├── service // 业务逻辑 ├── mapper // 数据库访问 ├── entity // 实体类 ├── dto // 前端交互数据对象 ├── common // 公共类、工具类 ├── config // 配置类 └── task // 定时任务分包遵循的是常见的三层架构后端最常用的组织方式。如果你的项目规模不大不必强行拆成provider/consumer之类的微服务结构一个单体应用包结构清晰、分层合理尺寸刚好。4.2 关键代码实现搜索、热度与定时任务示例我挑三个核心代码片段给你展示每一段背后都有完整的业务逻辑思考过程。第一段是 Elasticsearch 搜索服务的核心实现。关键点是NativeSearchQueryBuilder构建查询多字段匹配、高亮、分页一次搞定Service RequiredArgsConstructor public class NewsSearchService { private final ElasticsearchRestTemplate esTemplate; public PageResultNewsSearchVO search(String keyword, int page, int size) { NativeSearchQueryBuilder queryBuilder new NativeSearchQueryBuilder() .withQuery(QueryBuilders.multiMatchQuery(keyword, title^3, summary^2, content)) .withPageable(PageRequest.of(page, size)); // 高亮配置 HighlightBuilder highlightBuilder new HighlightBuilder() .field(title).preTags(em classhl).postTags(/em); queryBuilder.withHighlightBuilder(highlightBuilder); NativeSearchQuery query queryBuilder.build(); SearchHitsNewsDocument searchHits esTemplate.search(query, NewsDocument.class); // 组装返回结果把高亮字段替换到标题里 ListNewsSearchVO list searchHits.getSearchHits().stream() .map(hit - { NewsDocument doc hit.getContent(); ListString titleHl hit.getHighlightFields().getOrDefault( title, Collections.emptyList()); if (!titleHl.isEmpty()) { doc.setTitle(titleHl.get(0)); } return BeanUtil.copyProperties(doc, NewsSearchVO.class); }) .collect(Collectors.toList()); return new PageResult(list, searchHits.getTotalHits()); } }这里title^3的意思是标题字段的权重是 3 倍搜索“热点”时标题里含关键词的新闻会排在正文里含关键词的前面。multiMatchQuery会为每个字段分别打分再合并这是 ES 的基本相关度逻辑。第二段是热度计算的定时任务。这个任务的完整逻辑是查询所有已发布的新闻计算综合热度分值然后写入 Redis ZSetComponent RequiredArgsConstructor public class HotNewsTask { private final NewsMapper newsMapper; private final StringRedisTemplate redisTemplate; private static final String HOT_NEWS_ZSET hot:news; private static final long DECAY_FACTOR 1_500L; // 控制衰减斜率 Scheduled(fixedDelay 600_000, initialDelay 60_000) public void refreshHotNews() { ListNews newsList newsMapper.selectList( new LambdaQueryWrapperNews().eq(News::getStatus, NewsStatus.PUBLISHED)); long now System.currentTimeMillis(); ZSetOperationsString, String zsetOps redisTemplate.opsForZSet(); for (News news : newsList) { long publishMillis news.getPublishTime().getTime(); long ageHours Math.max((now - publishMillis) / 3600_000L, 1); double score (news.getViews() * 1 news.getLikeCount() * 3 news.getCommentCount() * 5 news.getFavoriteCount() * 8) / Math.pow(ageHours 2, 1.5); zsetOps.add(HOT_NEWS_ZSET, String.valueOf(news.getId()), score); } // 保留前100名淘汰掉老数据 zsetOps.removeRange(HOT_NEWS_ZSET, 100, -1); } }定时任务有两个参数需要注意。fixedDelay 600_000是任务执行完毕后隔 10 分钟再跑initialDelay 60_000是项目启动 1 分钟后再首次执行避免应用刚启动时其他缓存还没就绪。这两个参数背后的业务考量写着写着就变成了你的答辩内容比如“我用Scheduled实现了热点榜的准实时刷新把计算压力从请求链路中剥离出来”。第三段是 JWT 登录认证拦截器的一个关键片段。判断用户是否有管理员权限的本质是利用了动态代理——Spring MVC 的拦截器会通过HandlerMethod拿到 Controller 方法上的注解这也是 AOP 应用的一个变体Component public class AuthInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (!(handler instanceof HandlerMethod handlerMethod)) { return true; // 静态资源直接放行 } RequireRole requireRole handlerMethod.getMethodAnnotation(RequireRole.class); if (requireRole null) { return true; // 方法没标注放行 } UserContext currentUser UserContext.get(); if (currentUser null) { response.setStatus(401); return false; } if (!Arrays.asList(requireRole.value()).contains(currentUser.getRole())) { response.setStatus(403); return false; } return true; } }注意UserContext是一个基于ThreadLocal的线程变量在登录过滤器里把当前用户塞进去在业务代码里随时能取到请求结束由拦截器清理。这里要防止一个隐患线程池中使用 ThreadLocal 时任务执行完后必须清理否则线程复用会串数据具体我会在常用问题部分说。4.3 数据写入与同步MySQL 和 ES 的协同方案数据同时存在 MySQL 和 ES 里就一定会遇到一致性问题。严格意义上说分布式系统里面一致性始终是复杂话题毕设项目不需要引入消息队列那么重的方案我用的是非常轻量的设计但思路在面试里完全拿得出手。每次新闻发布或编辑保存文章时同步执行两个操作往 MySQL 写入再通过NewsSearchService.saveToEs()往 ES 写入索引。如果 ES 写入失败捕获异常后放进一个 Redis List作为待重试的索引消息。后台再放一个定时任务每 5 分钟扫描这个 List 里的“丢失索引”重新同步一次。这个方案其实就是最简版的本地消息表 定时补偿它好在单机就能跑不引入额外组件而且体现了“最终一致性”的工程思想。删除新闻时同理MySQL 逻辑删除置delete_flag 1ES 也删除对应文档列表页查询时 MySQL 默认过滤delete_flag 0ES 侧则通过定时任务把无效数据清理掉。整个方案在两套存储之间做了双写但没有做事务强一致在设计文档里你也要写清楚“这里接受短暂的不一致最终会收敛”——这才是真实业务的取舍。当新闻数据有更新但标题要改以方便搜索时你可以在更新接口里手动调一次同步方法这种“显式触发同步”的方案虽然朴素却是单机毕设项目里最稳定可控的。5. 我踩过的坑常见问题与排查实录5.1 环境与工程问题本地跑不起来的九成原因先说说环境问题这部分我能写一年。第一个高频问题是“JDK 配好了还是提示找不到”多半是 Path 变量里没有把%JAVA_HOME%\bin放在最前面或者之前配置过旧版本 JDK 的路径导致系统优先使用了旧版本。解决办法就是去Path里检查一遍把不需要的 Java 路径删干净。第二个高频问题是 Maven 依赖下载极慢或直接卡死。原因就是没有配国内镜像pom.xml写了三四个依赖结果等了半小时还在转圈。我配的是阿里云镜像顺手也加了华为云镜像作为备选这个操作 30 秒就完成但能救回一晚上的时间。第三个是端口冲突。有些电脑上 8080 被占你启动 Spring Boot 直接报错Port 8080 was already in use。先输入命令netstat -ano | findstr 8080找出占用进程的 PID再通过任务管理器干掉或者在application.yml里改成 8081。这个排查思路属于后端基本功建议自己完整操作一遍。第四个是 VSCode 跑 Java 报乱码。很多同学不习惯用 IDEA用 VSCode 的 Java 插件跑项目控制台输出中文五花八门。核心是字符集编码没统一pom.xml里强制加一段配置properties project.build.sourceEncodingUTF-8/project.build.sourceEncoding maven.compiler.encodingUTF-8/maven.compiler.encoding /properties另外 VSCode 右下角把文件编码 GBK 改成 UTF-8 重新保存即可。这本来不是项目问题但每年的毕设季都有一批人卡在这一步这里一并说清楚了。5.2 数据与缓存问题高并发场景下的经典陷阱这个项目跑起来之后你可能会在并发稍微上去一点的时候遇到各种诡异情况这里列几个最经典的。第一个是缓存穿透。用一个不存在的新闻 ID 去请求详情Redis 查不到MySQL 也查不到如果攻击者用随机 ID 批量请求数据库会被打爆。解决办法是查不到的数据也在 Redis 里短暂缓存一个空值TTL 设置 3 分钟这样反复用同一个 ID 请求不会打到数据库同时接口层面做参数校验非法 ID 直接拦截。第二个是缓存击穿。热门新闻的 Redis key 过期的一瞬间来了大量请求全部穿透到数据库。解决办法是加锁只允许一个线程去数据库加载数据并回填缓存其他线程等待或者把热点 key 的过期时间调长再通过定时任务手动刷新。按我实际调试的经验先把news:detail:{id}的 TTL 从 1 小时调成 24 小时并用定时任务主动刷新比写一堆复杂逻辑简单可靠得多。第三个是线程池使用的坑。我在接入阅读量异步更新的时候把用户信息存到 ThreadLocal然后在子线程里读结果出现权限错乱。排查下来是线程池复用了线程ThreadLocal 里的旧数据没被清理。解决的办法有两个要么在执行完任务后用ThreadLocal.remove()清理要么干脆不用 ThreadLocal直接在参数里传递用户 ID。我在项目里选择了后者因为“参数传递”比“隐式状态共享”更安全这是设计层面避免 bug 的思路。第四个是 ES 和 MySQL 数据不一致。经常会出现新闻后台已经改了标题但搜索到的还是旧标题。原因就是你只改了 MySQL忘了调同步接口。排查思路很简单先查 ESGET /news/_doc/{id}看文档内容然后对照 MySQL 的数据再补一次同步。这个坑不算 bug但它提醒我们要在代码里做“统一封装发布入口”而不是在 Controller 里到处散落双写逻辑——我在 service 层封装了一个publishNews()方法里面既改 MySQL 又同步 ES别的入口禁止直接操作新闻表问题就彻底解决了。5.3 这个项目在面试里会被问什么这套项目放在简历上面试官顺着项目问问题的路径完全可以预判提前准备好回答思路能加分不少。第一个一定会问的是“检索为什么用 ES 而不用 MySQL”。这个问题就是给你递话的如果你的项目里真的用了 ES你就讲 MySQL 的%关键词%查询无法走索引、中文分词效果差、数据量大了之后相关度排序实现困难而 ES 基于倒排索引、自带 IK 分词、支持相关度打分能直接解决这三个痛点。顺便再把“倒排索引是什么”解释一下它相当于一本新华字典的“拼音索引”或者“部首索引”不是一个字一个字顺序去找而是直接按词查。第二个会问“Java 里 Collection 从 ArrayList 到 stream 的应用”。你在搜索服务里把SearchHits转成ListNewsSearchVO的操作正是 Stream 的map和collect的典型场景。你可以顺势讲一下分离了“迭代”和“函数”以及 lazy evaluation 的思想这些都属于真正用过的理解。第三个会问“动态代理在项目里体现在哪”。你可以说 Spring AOP 的事务管理就是动态代理的一个应用Controller 调用 Service 的方法被代理拦截方法开始前开启事务正常返回后提交异常时回滚。如果你用过 Spring 的Transactional那就可以顺势把JDK 动态代理和CGLIB 动态代理的区别讲一遍——类有接口时 JDK 代理基于接口没接口时用 CGLIB 基于子类继承。这是 Java 八股里特别经典的一道题能跟真实项目挂钩面试官会觉得你是真在用不是背题。第四个高频问题就是“并发高的场景你做了哪些优化”。这时你把 Redis 缓存、异步线程池更新阅读数、ZSet 做热点榜、定时任务批量同步这几条线摆出来再用数据对比说明优化前后效果就非常有说服力。项目从“能跑”到“扛得住一点流量”的进化过程本身就是最能体现工程能力的地方。写在最后的一点个人体会这个题目做完我的感觉是它比一般的“XX管理系统”要丰满得多因为它跨了搜索、缓存、权限、异步、定时任务好几个技术栈每一个都够在面试里展开讲上十分钟。但我也想说一句实话技术栈再多不如把一条链路做深。把这个项目从头到尾理顺确保每一步设计你都能讲清楚“为什么”——为什么用 Redis、为什么热度公式这么写、为什么 ES 同步要定时补偿——这个思考过程本身就是最大的收获。愿你顺顺当当把项目跑起来答辩的时候自信地把你踩过的坑和解决方案都讲出来那比什么都更能打动人。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

PSASP继保算例文件结构拆解与110kV线路保护定值整定 2026/9/15 4:29:34

PSASP继保算例文件结构拆解与110kV线路保护定值整定

简介:这套PSASP继电保护仿真算例资源面向电力系统继保工程师、研究生及电网故障分析学习者,以110kV T110典型线路或变电站保护配置为对象,帮助理解过流保护、电流速断、距离保护等动作逻辑,并验证保护定值与故障切除策略。压缩包共…

阅读更多 →
前端UI与网络数据问题排查:从定位到解决的高效实践指南 2026/9/15 4:29:34

前端UI与网络数据问题排查:从定位到解决的高效实践指南

昨天群里还有人发截图问:列表页转了大半天圈,接口我直接用 curl 测也能正常返回数据,前端就是不显示,这到底是谁的锅?这类问题我一年能碰上几十次,尤其怕那种测试环境偶尔复现、本地永远正常的,…

阅读更多 →
选软件别被功能数迷惑:四步选型法找到真正适合你的工具 2026/9/15 4:29:34

选软件别被功能数迷惑:四步选型法找到真正适合你的工具

作为在软件行业和效率工具圈子里摸爬滚打多年的老人,我隔三差五就会收到朋友或读者的提问:"那个XX软件到底怎么样?""功能这么多,我该选哪个?""为什么别人说好用的东西,我用起来这…

阅读更多 →
硬盘数据恢复软件实战盘点:从误删到分区损坏的救急指南 2026/9/15 4:29:34

硬盘数据恢复软件实战盘点:从误删到分区损坏的救急指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Chromium扩展事件系统全解析:从EventRouter到JS监听器的完整链路 2026/9/15 4:29:34

Chromium扩展事件系统全解析:从EventRouter到JS监听器的完整链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
宽度对比:视觉权重的底层杠杆与设计转化率提升方法论 2026/9/15 4:26:34

宽度对比:视觉权重的底层杠杆与设计转化率提升方法论

1. 项目概述:为什么“宽度对比”不是个随便看看的视觉游戏“宽度对比(视觉分析)”这六个字乍看平平无奇,像设计课上老师随口提的一句点评,又像UI评审时某位同事皱着眉说的“这里太窄了”。但在我带过二十多个产品界面重…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞