☰
基于SpringBoot的图书商城智能推荐系统设计与实现
2026/10/1 16:11:59 网站建设 项目流程

又到一年毕设季,每年这个时候,总有同学拿着“图书商城推荐系统”这种题目来找我,问的无外乎是怎么把推荐功能做出亮点、怎么让答辩老师觉得这个项目有技术含量、以及最关键的一步——代码到底怎么落地。这个题目很多人做,但绝大多数人都停留在“增删改查+一个按销量排行的假推荐”这种程度,代码跑得通但没什么含金量。这篇博文我就以这个基于 SpringBoot 的在线图书商城智能推荐平台为例,把项目从设计思路、算法选型、表结构设计、核心代码实现到答辩避坑,一条龙拆给你看。

这套项目本质上不是一个普通的商城系统,它的核心卖点是“个性化导购”。同样是新用户进首页,有的商城给他推畅销书,有的商城给他推他刚搜过的同类书,区别就在于有没有一个能感知用户兴趣的推荐层。我用 SpringBoot 做后端服务,配合一套可解释的混合推荐策略(基于内容的相似度召回 + 基于用户行为的协同过滤),把登录、浏览、加购、下单这些行为数据串起来,真正做到根据不同用户的阅读偏好,展示不同的图书列表。这套方案特别适合 SpringBoot 方向或者推荐系统方向的毕设,也适合想在工作中接触推荐业务的后端同学拿来练手。

1. 内容整体设计与思路拆解

1.1 为什么推荐系统是图书商城的最佳切入点

图书这个品类,在电商里有一个很特别的性质:它的信息密度高、长尾效应极强。一本书的主题、作者、出版社、标签、适用人群都能构成特征,而读者的阅读兴趣又往往集中在少数几个方向上。一个计算机专业的学生和一个做产品经理的人,他们逛书城的路径完全是两条线。如果商城没有推荐,就是把所有书平铺在一个页面上,用户要在上千条数据里自己捞书,转化率天然就低。

所以图书商城做个性化推荐,不是噱头,而是真实存在的业务痛点。从毕设选题的角度讲,这个切入点的优势也很明显:第一,推荐算法不需要做得很深,基于标签匹配和协同过滤就能达到不错的效果,但又有足够的理论深度可以写进论文;第二,它天然需要“用户—行为—物品”三层数据,能展示你数据库设计的功底;第三,它跟前端交互有强关联,首页展示、搜索结果、详情页推荐位都可以动态变化,演示效果非常直观。

1.2 总体架构与技术选型的取舍逻辑

我当时定的技术方案是:SpringBoot 2.7.x + MyBatis Plus + MySQL 8.0 + Redis(可选),前端部分用 Vue 3 + Element Plus 做管理端,C端首页服务端渲染用 Thymeleaf。之所以选 SpringBoot 2.7 而不是 3.x,这里有个很现实的考虑:很多学校的毕设环境 JDK 还停留在 8,而且老版本的各种教程、依赖兼容性资料最丰富,出了坑容易查到解决方案。

整体上走的是一个轻量化单体应用架构,不整微服务那套,因为毕设场景下微服务只会徒增部署复杂度。但单体不代表结构可以乱。我按职责拆了四个核心模块:系统管理模块、商品与订单模块、用户行为采集模块、推荐引擎模块。推荐引擎独立成一个模块服务,输入是用户ID和上下文,输出是推荐书单,内部屏蔽了具体算法细节。这样后面你无论是想替换算法,还是给论文里画架构图,都清晰好讲。

1.3 推荐策略的组合思路

这个项目里我设计了三层推荐策略,按优先级排列:

  • 基于用户行为相似度的协同过滤(UserCF),用于老用户的首页猜你喜欢。
  • 基于图书内容标签的相似度推荐(Content-Based),用于图书详情页的“相似书籍推荐”和搜索结果扩展。
  • 基于热门榜和编辑精选的兜底推荐,用于新用户冷启动阶段和登录前的游客态。

这三层不是孤立的。实际加载首页推荐位时,系统会先判断用户有没有足够的行为数据:有就走前两种策略混合加权,没有就降级到兜底推荐。这种“策略分层 + 自适应降级”的设计,是我自己实际开发中比较常用的套路,也契合生产环境里推荐系统的常规做法。答辩时把这个链路讲清楚,老师就知道你不是随手糊一个协同过滤完事。

架构上要额外注意的一点是,推荐结果不要实时算。我当时是每晚用定时任务先把所有用户的推荐列表算好,写入一张 redis(或者推荐结果表),用户请求首页时直接读缓存。如果有人在凌晨修改了图书信息,也不至于让推荐立刻失效。这个异步预计算的思路,比用户每次请求都现场跑一遍算法要合理得多,实际效果也好很多。

2. 核心模块设计与数据库建模

2.1 用户行为数据的采集链路

推荐系统的基础是数据,没有行为数据的推荐系统都是空中楼阁。这套项目里我埋了一套非常轻量的行为采集方案:用户在商城内的三类核心行为会被写入行为日志表,分别是浏览(BROWSE)、加购(CART)、下单(ORDER)。每种行为都记录用户ID、图书ID、行为类型、行为发生时间,以及当时所在的页面场景(首页推荐位、搜索页、详情页)。

埋点不需要用复杂的消息队列。我的做法是,在Controller层的AOP切面里做统一拦截,用户触发上述行为时,异步写一条行为记录到数据库。这里有个设计细节值得注意:行为权重不一样。我计算用户相似度时,下单权重是3,加购是2,浏览是1。你可以在配置中心调这些系数,也可以把它们参数化写进配置文件。按行为类型加权,比单纯统计次数要科学得多,也是论文里一个可以展开讲的改进点。

2.2 核心表结构设计思路

这个项目里我设计了八张核心表,这里挑三张最关键的讲一下设计逻辑。

图书表(book),字段包括主键、书名、作者、出版社、ISBN、分类ID、价格、库存、封面图URL、出版日期、总销量、平均评分、内容简介。其中分类ID是外键,关联分类表。重点是两张辅助表:图书标签表(book_tag)和图书标签关联表(book_tag_relation)。图书与标签是多对多的关系,所以我单独抽了一张关联表,每个标签存一条记录。你在算图书相似度时,实际上就是比较两本书的标签集合的重合程度。

用户行为表(user_behavior)上面说过了,字段精简为:行为ID、用户ID、图书ID、行为类型、场景来源、创建时间。这个表会越积越大,我给“用户ID + 行为类型”建了联合索引。毕设的数据量其实不会太大,但设计时就要考虑查询优化,索引这个点写进论文里是加分的。

推荐结果表(recommend_result),字段是:用户ID、推荐位类型(首页猜你喜欢、详情页相似推荐等)、图书ID列表、算法标识(用的哪种策略算的)、创建时间。这个表挺重要的,因为有它,你就可以在界面上打开一个类似“为你推荐”的页面,直接展示历史推荐结果,而不用每次重新跑算法。

2.3 交易闭环模块的边界控制

既然是商城,就绕不开购物车和订单。购物车我用的是传统的关系表方案,每条购物车记录关联一个用户和一本图书。这里注意几个边界问题:库存不足时要在下单前校验并提示;同一本书重复加购时要做合并处理而不是另起一行;下单后要同步扣减库存。

订单表我是按“主订单 + 从表”的思路拆的,一笔订单可以包含多种图书,但毕设阶段不追求高并发,所以直接用一张订单表加一个订单项表就够了。下单时我会做一个事务控制,保证订单创建和库存扣减要么同时成功要么同时失败。这个在 SpringBoot 里实现非常简单,Service 方法上加 @Transactional 注解即可。但要注意一点,事务方法内部不能捕获异常后吞掉,否则回滚不会生效,这个细节在实操环节再细说。

3. 推荐引擎的核心算法实现

3.1 基于内容标签的相似度推荐

这是项目里最有实操价值的一段逻辑。我的思路是给每本书打标签,标签越相似的书越容易被一起推荐。比如《Java编程思想》的标签是["Java", "编程", "后端开发"],《深入理解Java虚拟机》的标签是["Java", "JVM", "性能优化"],两本书的Java标签重合,就有了相似度。

计算相似度我提供两种方式。第一种是杰卡德相似系数,公式是交集元素数除以并集元素数。两个集合的交集越大、并集越小,相似度越高。这种算法实现简单,集合操作在Java里直接用 retainAll 和 addAll 就能搞定,适合数据量不大的场景。

第二种方式是把标签向量化之后算余弦相似度。做法是,把所有标签做成一个全局标签字典,每本书根据自身标签构建一个高维向量,向量每个维度是标签权重。两本书的相似度就是两个向量夹角的余弦值。余弦相似度的好处是它对向量长度不敏感,能弱化“标签多的书天然跟谁都相似”的问题。我在代码里两种算法都实现了,通过一个策略枚举切换,论文里可以对比两种结果,也是一处不错的实验分析素材。

代码层面,我给每本书维护一个预处理好的标签集合,存储时直接把标签用逗号拼接存在一个字段里,读取时按逗号split成数组。这样省掉多次联表查询,相似度计算时只需要从数据库一次性加载所有图书ID和标签串,在内存里两两计算,生成全量相似度矩阵。这个矩阵我会缓存在一个静态Map里,或者存Redis,避免每次请求都重新计算。涉及到的关键方法如下:

public List<BookVO> recommendSimilarBooks(Long bookId, int topN) { // 从缓存中获取全量相似度矩阵 Map<Long, Map<Long, Double>> simMatrix = getSimilarityMatrix(); Map<Long, Double> simMap = simMatrix.get(bookId); if (simMap == null) { return Collections.emptyList(); } return simMap.entrySet().stream() .sorted((e1, e2) -> Double.compare(e2.getValue(), e1.getValue())) .limit(topN) .map(entry -> bookService.getBookVO(entry.getKey())) .collect(Collectors.toList()); }

上面这段就是把相似度最高的前N本书取出包装成VO返回给前端。细节上要注意,计算相似度矩阵时要过滤掉无标签的“脏数据”,否则会出现全零向量算余弦得到NaN的问题。

3.2 基于用户的协同过滤(UserCF)

基于内容的推荐有一个很死板的缺点:它永远只会推荐和你已看过书同类的书,做不到“跨类发现”。图书商城里很多人其实是杂食动物,既看技术书又看历史书。协同过滤就是为了解决这个问题。

UserCF 的核心逻辑很直白,分三步。

第一步,构建用户—图书行为矩阵。行是用户,列是图书,值是综合行为得分。比如用户A给《活着》打3分(下单行为权重3),给《百年孤独》打1分(浏览行为权重1)。矩阵可以用稀疏编码方式存成一个Map,不要用稠密二维数组,因为图书数量大了以后内存会爆。

第二步,计算用户之间相似度。我用的皮尔逊相关系数变形,实际上也是余弦相似度的一个变种。行为向量之间的余弦值越高,代表两个用户的兴趣越接近。这里用相似度排序找到当前用户的K个最近邻。

第三步,生成推荐项。把这K个邻居有过正向行为、但当前用户没有行为记录的图书集合拿出来,按“邻居相似度*行为权重”加权求和,排序后取前N本作为推荐结果。

实际实现时,我不用每次都实时跑全量矩阵。用户登录时只加载当前用户的行为记录,和系统的预计算用户相似度矩阵做交互,这样响应时间可控在100毫秒以内。如果数据量大了,这一步可以换成Spark或者向量检索库,但毕设场景下纯Java实现完全够用。

这里有一个很关键的工程细节需要提醒你注意:新用户的协同过滤结果可能为空。因为一个新注册用户没有任何行为记录,无法算相似度。所以协同过滤的结果必须做空值兜底,为空时返回热门图书列表,前端展示不至于空白一片。这也是我在1.3节里说的“策略分层”落地的关键点。

3.3 冷启动与混合推荐加权

冷启动是推荐系统里绕不开的实际问题,也是论文里的一个重要小节。新用户没有行为,这时候再怎么算协同过滤都是无米之炊。我的处理方式是:新用户注册后,强制走一步偏好选择引导,让用户至少从十本经典分类畅销书中选三本感兴趣的,作为初始行为写入一个虚拟行为表。这一步本质上是把“冷启动问题”转化成了“一次显式反馈采集”。

有了初始偏好,系统就可以立刻走基于内容的推荐,给用户推他选中图书的同标签图书。等用户积累了一定量的真实行为(我设置了阈值,比如浏览行为超过10条或者有效行为超过5条),系统自动切换成“协同过滤为主、内容推荐为辅”的混合模式。

混合加权我采用的还是一个线性加权公式,推荐得分 = a * 协同过滤得分 + b * 内容推荐得分 + c * 热榜得分(热度分归一化),其中a、b、c由配置文件动态调整。答辩时如果被问“为什么比单一算法好”,你就说:协同过滤擅长挖掘潜在兴趣但冷启动表现差,基于内容的推荐稳定可解释但容易信息茧房,两者加权可以互补,而热榜项保证了探索性。这是很标准的业界话术,但你的代码里是真实现了的,不是空谈。

4. 核心业务模块的落地实现

4.1 商城前台的完整链路

前台这个商城,不是让你只做一个展示页面。我的完整链路是:游客可以浏览首页和图书详情页,但不能加购和下单,必须登录。登录后可以搜索、筛选、加购物车、结算下单、查看订单状态。

搜索模块我用的 MySQL Like 加倒排思路。不要在一个搜索框里只做书名匹配,要把搜索词和作者、分类名、标签做拼接匹配,这样搜“Java高并发”也能命中《Java并发编程实战》,尽管书名本身不完全包含“高并发”。这个搜索扩展逻辑也可以接 HanLP 分词,属于项目里的加分项。我的热搜词里也提到了 HanLP 在 SpringBoot 中的整合,如果你时间充裕,可以引入 HanLP 轻量级分词,把用户搜索词切成多个关键词,再分别匹配书名、标签、分类,搜出来的结果质量能提升一大截。

订单和购物车部分,前台逻辑没有太多花活,但要注意两个点:一是加购、下单前都要校验库存,二是一本书在购物车里重复点击加购时要合并数量。下单成功后,购物车里对应条目要清除,订单状态初始是待付款,支付模块毕设常用方案是做一个模拟支付,点击“去支付”后直接跳转成功页,省去接第三方支付的繁琐。

4.2 推荐位的接入方式

推荐位我做了三个:首页的“猜你喜欢”瀑布流、图书详情页的“相似书籍推荐”、购物车页面的“搭配购买推荐”。这三个推荐位的实现逻辑略有不同:

首页猜你喜欢,核心是用户维度的推荐,用 UserCF 和混合加权策略,返回一个按得分排序的图书列表,每本书展示封面、书名、评分、价格,点击进入详情。

详情页相似书籍推荐,属于物品维度的推荐,直接复用3.1节基于内容标签的相似度推荐,实时计算当前图书的Top10相似书。详情页还有一种做法是关联规则挖掘(买了A的人也买了B),但毕设阶段用标签相似度更简单,效果也够。

购物车搭配推荐,我用的策略是“已加购图书的热门同分类书”。这个逻辑很简单,计算购物车中所有图书的分类分布,找到占比最高的两三个分类,从这些分类中按销量和评分排序取TopN。这种“人有我优”的细节能让你的系统看起来像一个完整商品,不是几个页面的拼接。

这三个推荐位的数据来源都统一定义在一个接口类里:

public interface RecommendStrategy { List<RecommendItem> recommend(Long userId, int topN); String getStrategyName(); }

Spring 容器里注册了三个策略 Bean,前端传不同场景码,后端用工厂模式从 Spring 上下文里按名称取对应策略 Bean。一旦后面你想加新的推荐位,只需新增一个实现类,不用改任何已有代码。这也是我在论文里愿意拿出来讲的一个设计模式落地案例。

4.3 后台管理模块

后台管理不做完整的企业级功能,但至少要有这几个模块:图书管理(增删改查、上下架、标签编辑)、订单管理(查看订单列表、发货状态流转)、用户管理(禁用用户、重置密码)、数据统计(销量Top10、分类占比)。推荐引擎的管理单独做了一个“推荐参数配置”页面,把策略权重、近邻K值、TopN、行为权重这些参数都做成可以热更新的配置项。

后台管理前端我用 Vue3 + Element Plus 搭的,和 SpringBoot 之间走 JSON 接口。这里的一个实操建议是:不要花太多时间打磨后台的 UI 细节,后台的核心是“功能完整、接口规范”六个字。你的精力应该大头放在前台展示效果和推荐算法的实现上,因为答辩的时候老师大部分时间在看前台。

5. 实战过程中的高频问题排查与避坑

5.1 SpringBoot 版本与依赖兼容性问题

这个坑几乎人人都踩。SpringBoot 3.x 出来后,它把javax.*包名切换成了jakarta.*,如果你照着网上老教程的代码去写,会直接编译报错找不到包。我当时为了保险起见,直接选了 SpringBoot 2.7.13 版本,配套 MyBatis Plus 3.5.3,JDK 1.8,这套组合的资料齐全、兼容性好,基本不会出幺蛾子。

另外有一类问题很常见:Maven 依赖冲突导致的方法找不到(NoSuchMethodError)。比如 Spring Boot 自带的 Jackson 版本和你项目里引入的其他 JSON 库版本不一致。我的建议是,统一用 Maven 的dependencyManagement锁版本,不要一个库一个版本号随手加,加依赖前先在 mvn repository 查一下当前版本和依赖传递关系。

5.2 中文字段排序与查询的坑

MySQL 里按销量排序没问题,但如果你在代码里用 MyBatis Plus 的orderByDesc("sales")也一切正常。真正的坑是你在做搜索模块时,想按“图书名”做加权排序,直接用ORDER BY name会按照拼音排序,但如果你建表时字段用了 utf8mb4 默认排序规则,那排序顺序是二进制码点顺序,中文会排得很乱。

更隐蔽的一个问题是:在 MySQL 8.0 中,如果你的查询条件里用了WHERE name LIKE '%Java%',因为 Java 是英文,走的索引策略和中文条件完全不同。英文关键词匹配时大小写也需要注意,MySQL 默认排序规则下 LIKE 不区分大小写,但如果你改过字段排序规则,可能会出现 Java 搜不到 java 的情况。安全做法是建表时统一设置成utf8mb4_general_ci,这个排序规则不区分大小写,中文场景最省心。

5.3 MyBatis Plus 使用细节

MyBatis Plus 确实方便,但有几个地方容易踩雷。第一个是逻辑删除。我给图书表和订单表都加了逻辑删除字段deleted,配置了@TableLogic注解后,普通 CRUD 都会自动拼接deleted = 0查询条件,但你自己手写 XML 的 SQL 里容易漏掉这个条件导致查出已经删除的数据。第二个是字段自动填充。创建时间字段如果定义了@TableField(fill = FieldFill.INSERT),需要在代码里写一个 MetaObjectHandler 实现类,否则字段不会自动赋值,很多人加了注解但忘了写处理器,最后存进去的时间全是 null。

第三个是关于分页插件。MyBatis Plus 的分页插件需要在配置类中显式注入PaginationInnerInterceptor,你不配置的话,page()方法不会真正分页,而是查全量数据后再内存分页,数据一大性能立刻拉胯。这个坑我也踩过,原以为只需要引入分页插件依赖就行了,结果忘了注册拦截器,运行日志能看到 SQL 里根本没有 LIMIT 关键字。

5.4 推荐结果为空和重复的异常处理

推荐系统实现过程中,最常见的问题就是推荐列表为空。原因通常是三类:用户行为表没数据、行为表里关联的图书未上架被过滤掉了、相似度矩阵构建时正则错了导致全是0相似度。排查思路很简单,第一步先查用户行为表中的记录,第二步看推荐策略日志里打印的候选集大小,第三步核对相似度计算结果。我当时在推荐策略里加了日志输出,log.info("用户:{}, 策略:{}, 候选数量:{}, 最终返回:{}", userId, strategy, candidates.size(), result.size());这个日志对排查问题帮助巨大。

另一个问题是推荐结果重复。多策略混合加权时,同一本书可能既出现在协同过滤结果里,又出现在内容推荐结果里。我做了两层去重:策略内部对列表去重;混合后的最终结果集再用LinkedHashSet保持顺序的前提下做一次全局去重。另外,同一个用户多次刷新首页如果看到完全一样的列表,会显得这个推荐系统有些假,我后来加入了“排除用户最近浏览过的5本书”的逻辑,让推荐位有一定的新鲜感,这个细节答辩时也可以提一下,属于工程层面的小优化。

5.5 事务回滚不生效的常见原因

下单操作我前面提到了@Transactional,但很多人在实操时会碰到“抛了异常,数据却还是写进去了”的情况。最常见的原因是:方法内部 catch 了异常但没有往外抛。Spring 事务默认只在 RuntimeException 和 Error 时回滚,checked exception 是不回滚的。如果 catch 住异常并且没有重新抛出,事务管理器压根感知不到异常,自然不回滚。

另外一个原因是:同类内部方法调用时事务失效。比如 OrderService 里的createOrder()方法调用了同类里的deductStock()方法,即使deductStock()上标注了 @Transactional,也是不生效的,因为 Spring 代理机制只有通过外部调用才能触发。解决方式是,把库存扣减逻辑放到另一个 Service 类里,或者通过AopContext.currentProxy()获取代理对象再调用,但后者需要配置exposeProxy=true,比较麻烦。

6. 论文写作与答辩展示的实用建议

6.1 论文逻辑线的规划

毕设论文不是项目文档的堆砌,要有一个让人读完记得住的逻辑线。我建议的主线是“背景与痛点分析 → 相关技术介绍 → 需求分析 → 系统设计 → 推荐算法设计与实验 → 系统实现与测试”。其中最值得花笔墨的是“推荐算法设计与实验”这一章,因为这是你区别于普通商城系统的核心所在。

算法实验章不要只贴代码。我的做法是,自己构造一个小实验数据集,比如随便选20个用户、50本书、几百条模拟行为记录,分别跑只有内容推荐、只有协同过滤、混合推荐三种策略,然后对比一个最直观的指标:用户对推荐结果的平均点击率(CTR)。通过图表展示混合策略的效果优于单一策略,哪怕数据是模拟的,这个过程也能说明你理解评估方法,比空洞地说“推荐效果很好”有说服力得多。

6.2 答辩演示时的高频问题与应答思路

答辩老师针对这类项目,最常见的几个问题我整理一下,以及你该怎么应对。

问题一:“你这个推荐算法和别人的有什么不同?”回答思路:先简述三种策略各自的原理和适用场景,然后重点强调你做的策略分层和冷启动处理方案。特别是冷启动,很多同学做的项目根本不管新用户,你能主动说“我用偏好选择引导解决冷启动,用策略降级保证展示效果”,这就在认知上超过了平均水平。

问题二:“你的系统性能怎么样?数据量大了怎么办?”这个问题有两层含义。小数据量下,你直接讲你的响应时间测试结果,比如推荐位平均响应80ms,接口QPS实测多少。大数据量加一层演进思路:“目前采用 MySQL 存储和内存计算,数据量到百万级以后可以引入 Redis 缓存、离线预计算、甚至用 ES 来做检索和向量召回。”到了这一步说明你懂系统瓶颈在哪,比支支吾吾好太多。

问题三:“推荐结果是怎么保证不推已购图书的?”这个属于业务逻辑校验问题,你的代码里要真正实现过滤逻辑,简单说就是在推荐候选集中filter(bookId -> !userPurchasedBookIds.contains(bookId)),并且这个逻辑要有单元测试覆盖。答辩时你把测试代码的截图一亮,效果非常好。

6.3 演示环境的准备工作

最后特别提醒一句:答辩前,请一定把演示环境跑顺。我把这些年在答辩现场看到的翻车情况给你总结一下:数据库忘记启动了、端口被占用、Redis 启动失败导致首页直接报错、演示账号密码记错、IDEA 里配置了太多测试代码导致编译慢得让人失去耐心。

我的建议是准备一份启动清单,按顺序执行:启动 MySQL → 启动 Redis(如果你用了)→ 执行数据库初始化脚本 → 启动 SpringBoot 应用 → 打开前端页面 → 用测试账号登录。面向前台演示的时候,提前准备两个账号:一个新注册的账号(用于展示冷启动推荐和偏好选择),一个老账号(用于展示行为记录丰富后的猜你喜欢效果)。这两个账号对应的界面效果差异越大,给老师的印象就越深。

7. 项目功能扩展与优化方向

如果时间和精力允许,这个项目还可以往几个方向做增强,每个方向都能作为论文的“未来展望”或者答辩时的加分扩展。

第一个方向,引入 Redis 做推荐结果缓存。在上面的实现里,我已经用 Java 内存做了一层缓存,但进程重启后就丢了。如果引入 Redis,预计算结果可以序列化后存储,设置合理的过期时间(比如24小时),冷热数据分开管理,系统响应速度还能更快。

第二个方向,把关键词提取能力引入搜索模块。目前搜索主要靠书名和标签匹配,如果你想展示更高级的 NLP 能力,可以引入 HanLP 分词库,先把用户搜索词分词,再把分词结果做词频统计,和图书内容的摘要、简介做相似度打分。我实际试过,效果提升非常明显,而且 HanLP 在 SpringBoot 中集成的成本并不算高——引入依赖,写一个分词服务,剩下就是调 API 的问题。

第三个方向,做一个热门排行榜的定时刷新。毕设项目如果全部是静态推荐,展示效果太单一。我后来在项目里加了一个定时任务,每晚重新计算周销量榜、好评榜、新品榜三个榜单,写入缓存,首页轮播图位置展示。定时任务在 SpringBoot 里实现非常轻量,一个 @Scheduled 注解就搞定了,但整个系统的“实时性”观感强了很多。

第四个方向,引入用户画像的可视化。在用户中心增加一个“我的阅读偏好”页面,前端用 ECharts 展示用户最近一个月浏览/购买的图书分类占比,生成标签云。这个功能不涉及复杂算法,只要有个接口查用户行为数据然后按分类聚合,前端画图就行,但对“个性化”这个主题的直观展示能力非常强,答辩演示时光靠这一张图就能打动不少老师。

我在实际动手做这套系统时,最深的体会其实是:推荐系统这个词听起来很高大上,但拆到落地层面,它考验的更多是工程思维——你怎么设计数据表、怎么组织策略模块、怎么处理边界情况。把这层窗户纸捅破了,你会发现它不过是一个“基于已有数据,用一种可解释的规则,猜用户下一步想买什么”的工具。而真正让你在毕设中脱颖而出的,从来不是你用了多高级的算法,而是你对每个细节深思熟虑之后,愿意动手把想法一点点变成能跑通的东西。

这个项目我建议你花三到四周去打磨,前期把精力放在表结构设计与推荐策略先行验证上,中期做框架搭建和功能填充,后期专门腾出时间做推荐效果的调参与演示脚本的演练。遇到问题的时候别急着改代码,先去看日志,日志不会骗你,它能告诉你系统里正在发生什么。用这个思路走下去,你的毕设作品和论文一定不会差。

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

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

立即咨询