Java Web 课设选了个“电商购物平台”不算新鲜,但加上“个性化推荐”这五个字,含金量立刻不一样。我最近完整过了一遍这个基于 SSM 的商城项目源码,从 IDEA 导入到推荐逻辑落地,再到前后台联调,算是把整条链路都跑通了。这篇文章就把拆解过程和实操经验写出来,给同样选了”电商购物平台+个性化推荐“这个组合的读者做个参考,不管你是要做课程设计、毕业设计,还是想找一份 SSM 方向的源码练手,都能用得上。
1. 项目整体设计与技术选型思路
1.1 为什么是 SSM 这个“老组合”
先聊一个很多人纠结的问题:都 2025 年了,为什么这种项目还在用 Spring + SpringMVC + MyBatis,而不是直接用 Spring Boot?
我的看法是,这类选题之所以长期存在,是因为 SSM 是很多学校的教学主线和面试考察重点。Spring Boot 确实把配置简化了一大截,但它自动配置的黑盒有时反而让新手更迷惑——出了问题不知道去哪里排查。SSM 不一样,每一个请求怎么从 Controller 到 Service 再到 Mapper,每一个 Bean 怎么被 Spring 容器管理,都是明文配置,捋一遍源码能让你对 Java Web 的底层流转有更扎实的认识。
从实用角度讲,SSM 版本在 IDEA 里跑起来并不比 Spring Boot 复杂多少。难点主要在三件事:一是 Spring 和 MyBatis 的 XML 配置容易出错,比如路径写错、Mapper 接口没扫描到;二是各种 jar 包版本容易冲突;三是 Tomcat 部署步骤比内嵌容器多。这三件事后面我会一个个拆开说,实际上都是有固定套路的。
对比下来我是这么想的:如果你答辩时能被老师问清楚 DispatcherServlet 的工作原理、Mapper 代理的实现机制,那这一趟 SSM 折腾下来,收获比直接上手 Spring Boot 大得多。
1.2 功能模块与分层架构怎么拆
这个项目的整体架构是经典的前后端不分离模式,后端按三层结构组织代码:Controller 层负责接口接收请求,Service 层处理业务,Mapper 层操作数据库。页面用 JSP + JSTL 渲染,静态资源由 SpringMVC 统一放行。
功能模块上,前台商城和后台管理是完整分开的,这一点很多做课程设计的同学容易忽略。光有用户买东西的页面没有管理端,商品数据只能靠人手动插数据库,演示起来非常别扭。
前台部分包含这些模块:
- 用户模块:注册、登录、个人信息修改、收货地址管理。
- 商品模块:分类展示、关键词搜索、商品详情页、商品列表排序。
- 购物车模块:添加商品、修改购买数量、删除、勾选结算。
- 订单模块:提交订单、订单列表、订单状态跟踪。
- 推荐模块:首页“猜你喜欢”、详情页“看了又看”、购物车的搭配推荐。
- 个人中心:我的订单、我的收藏、浏览记录。
后台管理端包含:
- 商品管理:上架、下架、编辑、库存调整。
- 分类管理:商品分类的新增与修改。
- 订单管理:查看订单、修改订单状态。
- 用户管理:用户查询、禁用启用。
- 数据统计:订单数量、销售额、热销商品排行。
我强烈建议你在跑通源码之后,把后台管理相关的代码从头到尾看一遍。因为在实际答辩中,老师很可能会问“商品数据是怎么进来的”,如果你答不上来,那整个项目的可信度就大打折扣了。
2. 个性化推荐模块:核心算法与工程落地
2.1 三种推荐思路的选型对比
这个项目的灵魂在“个性化推荐”,但推荐算法有很多种选法。我在分析源码时发现,真正适合这个 SSM 项目落地的方案主要有三条路线:
第一种是基于规则的推荐,最常见的做法就是按销量排行、按新品上架时间排序、按价格区间筛选。这种方案本质上不是个性化,只是把热门商品露出来。优点是实现成本几乎为零,缺点是每个用户看到的都是同一批商品,谈不上“个性”。
第二种是基于内容的推荐,比如用户频繁浏览某个分类下的商品,就给他推荐同分类的商品。这种方案实现成本也不高,只需要在用户浏览商品时记录分类偏好,然后做一个分类匹配就行。
第三种就是协同过滤,分为基于用户的 UserCF 和基于物品的 ItemCF。这个项目最有技术含量的部分就集中在这里。
我的选型建议是:如果你想让项目有真正的“推荐”味道,又不想在答辩时被算法细节问倒,优先考虑 ItemCF——基于物品的协同过滤。理由有三:第一,商品数量通常远小于用户数量,商品相似度矩阵的计算成本更可控;第二,推荐结果的解释性比 UserCF 更强,简化版实现很好讲;第三,电商场景中用户行为稀疏,ItemCF 的推荐稳定性比 UserCF 更好。
2.2 基于物品协同过滤的相似度计算
ItemCF 的核心是计算商品之间的相似度。经典计算方法是余弦相似度,公式是:
similarity(i, j) = |N(i) ∩ N(j)| / sqrt(|N(i)| × |N(j)|)
其中 N(i) 是喜欢商品 i 的用户集合,N(j) 是喜欢商品 j 的用户集合,分子是两个集合的交集大小,也就是同时喜欢这两个商品的人数。
我举个例子:假设有 100 个用户喜欢《Java 编程思想》,80 个用户喜欢《Spring 实战》,其中有 40 个用户两本书都喜欢。那这两本书的相似度就是 40 / sqrt(100 × 80),算出来约等于 0.45。站在推荐的角度,如果你看过《Java 编程思想》,系统就可以把《Spring 实战》推给你,因为这两本书的相似度最高。
这里的“喜欢”在电商场景中要展开定义。我这个项目里会给用户行为分权重:浏览算 1 分,收藏算 2 分,加入购物车算 3 分,购买算 4 分。用户对商品的最终偏好值取这些行为的加权和,超过某个阈值就认为用户“喜欢”这个商品。这样处理的好处是,一个只看不买的用户和一个真金白银买过的用户,对推荐结果的贡献是完全不同的。
2.3 推荐引擎的运行流程与代码落地
这个项目的推荐模块不是每次请求都现场计算相似度矩阵,而是采用“离线计算+在线查询”的模式。流程是这样的:
用户浏览商品、收藏、加购、下单时,在 Controller 里埋点,把行为记录写入 user_behavior 表。系统每天凌晨通过 Spring Task 定时任务跑一次相似度计算,把计算结果存到专门的相似度表中。当用户访问首页时,推荐模块只做三件事:从行为表查用户最近浏览或购买的商品,拿这些商品去相似度表查 TopN 最相似的商品,再过滤掉用户已经购买或浏览过的商品,输出成“猜你喜欢”。
伪代码长这样:
public List<Product> recommendForUser(Integer userId, int topN) { // 1. 找用户最近感兴趣的N个商品 List<Integer> seedProductIds = behaviorService.findRecentProductIds(userId, 5); if (seedProductIds.isEmpty()) { // 2. 冷启动:无行为数据,按销量推荐 return productService.findHotProducts(topN); } // 3. 根据种子商品查相似商品,按相似度倒序 List<Product> candidates = similarityService.findSimilarProducts(seedProductIds); // 4. 过滤掉已购、已浏览商品 List<Integer> excludedIds = behaviorService.findExcludedProductIds(userId); return candidates.stream() .filter(p -> !excludedIds.contains(p.getId())) .limit(topN) .collect(Collectors.toList()); }对应的 Mapper 核心 SQL 也很直观:
SELECT similar_product_id, score FROM product_similarity WHERE product_id IN ( SELECT product_id FROM user_behavior WHERE user_id = #{userId} ORDER BY create_time DESC LIMIT 5 ) ORDER BY score DESC LIMIT #{topN}在离线计算阶段,核心代码是遍历所有商品对,计算交集和余弦相似度,然后批量写入 product_similarity 表。
@Service public class SimilarityCalculateTask { @Resource private BehaviorMapper behaviorMapper; @Resource private SimilarityMapper similarityMapper; @Scheduled(cron = "0 0 3 * * ?") public void calculateAllSimilarities() { // 1. 查出每个商品对应的"喜欢"用户ID集合 Map<Integer, Set<Integer>> productUserMap = behaviorMapper.selectProductUserMap(); List<Integer> productIds = new ArrayList<>(productUserMap.keySet()); // 2. 两两计算余弦相似度 for (int i = 0; i < productIds.size(); i++) { for (int j = i + 1; j < productIds.size(); j++) { int p1 = productIds.get(i); int p2 = productIds.get(j); Set<Integer> users1 = productUserMap.get(p1); Set<Integer> users2 = productUserMap.get(p2); Set<Integer> intersection = new HashSet<>(users1); intersection.retainAll(users2); if (intersection.isEmpty()) { continue; } double score = intersection.size() / Math.sqrt(users1.size() * users2.size()); if (score > 0.05) { similarityMapper.insert(p1, p2, score); similarityMapper.insert(p2, p1, score); } } } } }这里有几个实操细节值得关注。第一,为什么是凌晨 3 点跑?因为这个时候网站访问量最低,避免计算任务影响线上用户体验。第二,为什么相似度小于 0.05 的就不写库?这是为了缩小数据量,商品几千上万时,两两组合会非常多,只保留高相似度的记录能显著降低存储和查询压力。
2.4 冷启动与多推荐位的实战处理
“冷启动”是这个项目答辩时的高频问题。所谓冷启动,就是新用户刚注册,系统里一条行为数据都没有,拿什么给他推荐?
项目的处理方式是分层回退:第一步,判断当前用户有没有行为数据,没有就按热门商品推荐,即销量最高的商品列表;第二步,如果用户有浏览但没有购买,就以浏览数据为种子做 ItemCF;第三步,如果用户有购买记录,优先用购买记录作为种子,因为购买行为的置信度远高于浏览。这套逻辑在代码里就是 if-else 的嵌套,但要在答辩时把它讲清楚,这就是一套完整的推荐策略。
另外,一个好的个性化推荐系统通常不会只有一个推荐位。我在实践这个项目时,做了三个不同的推荐位:
- 首页的“猜你喜欢”:以用户最近行为为种子,输出综合相似商品,位置放在页面最显眼的地方。
- 商品详情页的“看了又看”:以当前展示商品为种子,输出相似度最高的同品类商品。
- 购物车页的“搭配推荐”:以购物车中的商品为种子,输出关联度较高的配件或互补品。
每个推荐位的数据来源不同、展示逻辑不同,但底层都复用同一套相似度表。这样设计的好处是代码复用率高,推荐位的扩展也特别方便,以后想加一个“热门推荐”位,只需要把查询条件改一下就行。
3. 电商核心链路:表结构设计与业务流程
3.1 数据库整体设计与关键表字段说明
个性化推荐是加分项,但电商平台本身的功能链路才是底座。我翻了这个项目的建表 SQL,发现整体设计是比较成熟的,核心表有 8 张左右。我挑几张重点讲解一下:
用户表 user:
CREATE TABLE `user` ( `id` INT NOT NULL AUTO_INCREMENT, `username` VARCHAR(32) NOT NULL COMMENT '用户名', `password` VARCHAR(64) NOT NULL COMMENT 'MD5加密密码', `nickname` VARCHAR(32) DEFAULT NULL, `phone` VARCHAR(20) DEFAULT NULL, `email` VARCHAR(64) DEFAULT NULL, `status` TINYINT DEFAULT 1 COMMENT '1正常 0禁用', `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `idx_username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;密码字段设计值得说一句。很多课程设计里密码直接明文存储,这在大厂面试时是个扣分项。这个项目至少做了 MD5 存储,虽然 MD5 现在不算安全,但比明文强很多。如果你想让项目更亮眼,可以把 MD5 升级为加盐的 SHA-256,或者引入 Spring Security 的 BCryptPasswordEncoder。
商品表 product:
CREATE TABLE `product` ( `id` INT NOT NULL AUTO_INCREMENT, `category_id` INT NOT NULL, `name` VARCHAR(128) NOT NULL, `subtitle` VARCHAR(256) DEFAULT NULL, `main_image` VARCHAR(256) DEFAULT NULL, `sub_images` TEXT, `detail` TEXT, `price` DECIMAL(10,2) NOT NULL, `stock` INT NOT NULL DEFAULT 0, `status` TINYINT NOT NULL DEFAULT 1 COMMENT '1在售 0下架', `sales` INT NOT NULL DEFAULT 0 COMMENT '冗余销量', `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_category` (`category_id`), KEY `idx_status` (`status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;商品表里的 sales 字段很多人会忽略,但它特别有用。无论是热销推荐、商家排序,还是后台数据看板的“Top10 热销商品”,都可以直接用这个字段排序,省去每次实时 count 订单表的开销。这就是典型的“以空间换时间”的冗余设计思路,在答辩时如果能主动讲出这个设计动机,会是很不错的加分点。
订单表和处理表拆分开是另一个值得讲的设计点。orders 表存储订单主信息,比如订单号、用户 ID、总金额、收货地址快照、支付状态、创建时间;order_item 表存储每个订单下的具体商品明细,包含商品名称、单价、数量、小计。拆开的好处是:一个订单可以有多个商品,按订单粒度查主信息很快,按商品维度做数据统计也很方便。
3.2 购物车与订单流程中的防超卖设计
购物车的设计在这个项目里是持久化到 cart 表的,而不是存 Session。这样做的好处是用户换台电脑、换浏览器登录后购物车还在,体验是一致的。购物车表核心字段是 user_id、product_id、quantity、checked。
提交订单的业务流程是这样的:拿到购物车勾选的商品列表,先生成订单主记录,再写入 order_item 明细,然后扣减商品库存,最后清空购物车中对应的勾选商品。整个流程要放在一个事务里执行,任何一个环节失败都必须回滚。
这里最大的坑是库存超卖问题。简单写“先查库存再 update”是不安全的——两个用户同时下单,都查到库存还剩 1 件,都去扣减,库存就变成 -1 了。正确的做法是使用条件更新,把库存判断放到 update 语句的条件里:
UPDATE product SET stock = stock - #{quantity} WHERE id = #{productId} AND stock >= #{quantity}这条 SQL 执行后,如果影响行数为 0,说明库存不足,直接抛出异常终止下单。这个细节在很多课程设计里都不会处理,但它是电商系统并发场景下非常经典的问题,如果能在项目里体现出来,面试的时候会很加分。
3.3 后台管理面板与统计功能的 SQL 实践
后台管理端是这个项目比较容易被忽视但很重要的部分。商品管理、分类管理、订单管理、用户管理都是常规 CRUD,真正出彩的是数据统计部分。
比如统计今天的订单数和销售额,可以用这样的 SQL:
SELECT COUNT(*), COALESCE(SUM(total_price), 0) FROM orders WHERE create_time >= CURDATE() AND status IN (1, 2, 3); -- 已付款、已发货、已完成再比如统计近 7 天的每日销售额:
SELECT DATE_FORMAT(create_time, '%Y-%m-%d') AS day, SUM(total_price) AS amount FROM orders WHERE create_time >= DATE_SUB(CURDATE(), INTERVAL 6 DAY) AND status != 0 GROUP BY day ORDER BY day;热销商品 Top10 则可以从 order_item 表按商品聚合:
SELECT product_id, product_name, SUM(quantity) AS total_sales FROM order_item GROUP BY product_id, product_name ORDER BY total_sales DESC LIMIT 10;后台统计功能的使用场景是:运营人员每天打开后台看订单趋势,而这些数据恰好也可以喂给推荐系统的热门商品模块,形成两条业务线的联动。
4. IDEA 本地运行与源码调试全流程
4.1 环境版本匹配原则
拿到源码后先别急着启动,第一步是检查环境。我见过太多人卡在环境问题上,有的折腾一两天最后发现是 JDK 版本不对。这个项目的推荐环境如下:
| 组件 | 推荐版本 | 说明 |
|---|---|---|
| JDK | 1.8 | 项目基于 JDK 8 编译,不要用 17 或 21,否则会有兼容性问题 |
| Maven | 3.6.3 | 3.8+ 也可以,主要看 IDEA 内置的 Maven 是否兼容 |
| Tomcat | 8.5 或 9.0 | Tomcat 10 是 Jakarta EE 规范,不能用在这个 SSM 项目上 |
| MySQL | 5.7 或 8.0 | 8.0 需要在 JDBC 连接串里加时区参数 |
| IDEA | 2020.3 及以上 | 社区版也可以,但需要额外配置 Maven 的 tomcat 插件 |
这里最需要注意的是 Tomcat 版本。Tomcat 10 开始把 javax 包换成了 jakarta 包,而 Spring 5.x 和 MyBatis 等老版本框架用的还是 javax.servlet,直接部署会直接启动失败。很多人环境检查半天没发现问题,最后才意识到是 Tomcat 版本闹的。
还有一个我个人的实操体会:如果你是 Mac 用户,直接用 IDEA 自带的 Tomcat 集成功能有时候会出现权限问题,这个时候改用 Maven 的 tomcat7-maven-plugin 插件运行反而更省心。Windows 用户踩这个坑的概率小一些。
4.2 IDEA 导入与 Tomcat 部署的完整步骤
我整理一份可以直接照着做的操作清单:
第一步,解压源码,确认目录结构。标准 SSM 项目外层有 pom.xml,里面有 src 目录,其中 main/java 下按 com.xxx.controller、com.xxx.service、com.xxx.mapper 等分包。确认好结构再导入,避免导入了一个空壳。
第二步,用 IDEA 打开项目。选择 File -> Open,选中项目根目录,IDEA 会自动识别 pom.xml 并作为 Maven 项目导入。这个过程会触发 Maven 下载依赖,如果网速慢,通常需要 5 到 15 分钟。
第三步,配置本地 Maven。这里建议先在 IDEA 的 Settings -> Maven 中把 Maven home path 指向你自己的本地 Maven,而不是 IDEA 自带的那个。同时把 settings.xml 里的本地仓库路径确认好,再把阿里云镜像加上:
<mirror> <id>aliyunmaven</id> <mirrorOf>central</mirrorOf> <name>阿里云公共镜像</name> <url>https://maven.aliyun.com/repository/central</url> </mirror>这一步能显著提升依赖下载速度,尤其是国内网络环境下,不加镜像很容易卡在依赖拉取环节。
第四步,修改数据库配置。在 src/main/resources 下找到 jdbc.properties 或 db.properties,把 url、username、password 改成自己本机的数据库连接信息。MySQL 8.0 驱动的 url 要显式加时区:
jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false jdbc.username=root jdbc.password=你的密码第五步,初始化数据库。用 Navicat 或命令行执行项目附带的 shop.sql 脚本。连接库名必须和 jdbc.properties 里一致,否则运行时会报找不到表。执行完以后建议查看一下表是否都建成功,尤其是 behavior 和 product_similarity 这两张推荐相关的表,如果缺失,推荐模块会直接报错。
第六步,配置 Tomcat。点击 Run -> Edit Configurations,左上角加号,找到 Tomcat Server -> Local。如果这个选项不存在,说明你的 IDEA 是社区版或者没有安装 Tomcat 集成插件。解决办法是换用 Maven 插件方式运行,在 pom.xml 里加一段配置:
<plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8080</port> <path>/</path> <uriEncoding>UTF-8</uriEncoding> </configuration> </plugin>配置好后在 IDEA 右侧 Maven 面板找到 tomcat7:run,双击即可启动。
第七步,在 Tomcat 配置的 Deployment 标签页,点击加号选择 Artifact,把项目的 war 包加进去,Application context 建议填 /shop。然后启动,浏览器访问 http://localhost:8080/shop 或 http://localhost:8080(取决于 path 配置),看到首页说明部署成功。
4.3 高频问题排查与解决方案
我在跑通这个项目的过程中遇到的坑不少,挑几个概率最高的整理成表格,你直接对照排查:
| 问题现象 | 可能原因 | 解决办法 |
|---|---|---|
| 启动报错 UnsupportedClassVersionError | Compiled JDK 版本和运行时 JDK 不一致 | 在 Project Structure 的 Project SDK 和 Java Compiler 里都设为 1.8 |
| Maven 依赖下载慢或失败 | 未配置国内镜像 | 在 settings.xml 中配置阿里云镜像 |
| 数据库连接失败 CommunicationsException | MySQL 8.0 驱动连接串缺少时区参数 | url 加上 serverTimezone=Asia/Shanghai |
| 页面中文乱码 | JSP 编码、数据库编码、连接串编码不一致 | 统一使用 UTF-8,建库时指定 utf8mb4 |
| 8080 端口被占用 | 本地其他进程占用了端口 | 修改 Tomcat 端口或在命令行中结束占用进程 |
| Mapper 注入失败,提示找不到 Bean | spring-mybatis.xml 中 mapper-locations 路径不对 | 检查 dao 层 XML 路径,通常为 classpath*:mapping/*.xml |
| 页面 404 | Application context 路径不对 | 访问地址要加上部署时的 context path |
| 推荐位空白 | product_similarity 表无数据或 user_behavior 无数据 | 先造行为数据,再手动触发相似度计算任务 |
这里我要特别提一个容易忽略的问题:这个项目里包含的 SQL 脚本有可能是在 MySQL 5.7 环境下写的,如果你用的是 MySQL 8.0,要注意排序规则和时区设置。最典型的坑是 MySQL 8.0 默认情况下 JDBC 连接串不加 serverTimezone 就报时区错误,这个我在前面已经说过了,但确实是最多人遇见的。
4.4 推荐效果验证与数据构造技巧
把系统跑起来以后,很多人会发现推荐位是空的。为什么?因为没有用户行为数据,相似度表也是空的。这时候需要自己造数据来验证推荐效果。
我最推荐的做法是准备一个简单的 SQL 脚本,手动往 user_behavior 表里插入几个用户的行为记录。比如造两个用户:用户 A 频繁浏览图书分类下的《Java 编程思想》和《Java 并发编程实战》,用户 B 频繁浏览食品分类下的咖啡豆和坚果。然后手动触发一次相似度计算,再分别用这两个用户登录系统看首页“猜你喜欢”。如果 A 看到的是图书类推荐,B 看到的是食品类推荐,说明推荐系统已经能区分用户兴趣。
这一步非常关键,因为很多人在答辩的时候只演示了“能注册、能下单”,但推荐模块没有数据展示不出来,整个项目的差异化优势就没了。我建议至少准备 3 到 5 个不同兴趣偏好的测试账号,每个账号录入不同的行为数据,推荐效果会非常直观。
另外,我看了一下项目里可能已经内置了管理员账号,比如 admin/admin,后台入口一般在首页底部或登录页切换。如果你拿到源码后不知道管理员密码,可以直接在 SQL 脚本里搜一下 user 表的 INSERT 语句,通常都是明文或简单 MD5,复制出来用就行。
5. 项目答辩与面试的几个必问点
最后从我的实际经验出发,聊几个这个项目在答辩或面试时几乎必被问到的问题,建议提前准备:
第一个问题是“为什么推荐算法选 ItemCF 不选 UserCF”。这个要抓重点讲:电商用户数通常远大于商品数,计算用户相似度矩阵的代价更高;而且用户兴趣漂移快,UserCF 维护起来麻烦。同时 ItemCF 在解释性上有天然优势,可以说“因为你浏览过 A,而 A 和 B 相似度最高,所以推荐了 B”。
第二个问题是“数据量大了怎么办”。推荐模块目前是单机 MySQL 存储相似度表,数据量大了以后要考虑引入 Redis 做缓存,把相似度表加载到内存里;离线计算部分可以考虑用 Spark 等分布式计算框架替换。回答这类问题的关键是要体现出你思考过扩展性。
第三个问题是“冷启动怎么解决的”。答案就是我前面说的三层回退策略:无行为数据按热门推荐,有浏览按浏览推荐,有购买优先按购买推荐。如果老师继续追问新商品冷启动,可以说可以给新品加权或者打标签,用基于内容的推荐过渡。
第四个问题是 SSM 框架层面的:“SpringMVC 的请求流程是什么”“MyBatis 里 #{} 和 ${} 的区别”。这两个是 Java 后端面试的经典问题,建议把这个项目的实际请求链路对应到面试题的答案中,比如用户点“加入购物车”后,前端发起 POST 请求,DispatcherServlet 怎么找到对应的 Controller,Service 怎么处理事务,Mapper 怎么通过代理执行 SQL,你能把这条链路讲得越细,越能证明这个项目是你自己跑通的。
我自己在实操这个项目的过程中,最大的体会是:个性化推荐模块单独拿出来并不复杂,真正花时间的是把用户行为埋点、离线计算、在线查询这条数据链路捋顺,再加上电商系统的订单事务、库存扣减这些基础功能都要做得稳,整个项目才完整。如果你在导入或运行阶段卡在哪一步,大概率就是版本问题或者数据库连接配置问题,按照我上面给的排查表逐项检查一遍就能解决。