一、核心业务流程(面试必讲)
1. 供应商审核流程
流程概述:
创建草稿 → 上传资质 → 提交审核 → 负责人审核(通过/拒绝/退回) → 创建Portal账号 → 正式上线
关键技术点:
- 状态机白名单控制状态流转(5种状态,7种合法流转)
- CAS乐观锁保证并发安全:
WHERE status = 草稿 - 审核日志只增不改,完整记录审核历史
- Portal账号创建时检查邮箱唯一性
面试时怎么讲: “采购专员创建供应商草稿,上传营业执照等资质文件,提交审核。系统用状态机校验状态流转是否合法,用CAS乐观锁更新状态,防止并发修改。采购负责人审核通过后,系统自动创建Portal账号并发送欢迎邮件。所有操作写入审核日志,可追溯。“
2. 供应商绩效评分流程
评分维度(满分100分):
- 准时交货率(25分)= 准时到货数 / 总订单数 × 25
- 质量合格率(25分)= 合格批次数 / 总批次数 × 25
- 响应速度(25分):≤2小时=25分,2-8小时=20分…
- 价格竞争力(25分):价格系数<0.90=25分…
评级标准:
- S级(≥90分):优质供应商,增加合作份额
- A级(75-89分):良好供应商,正常合作
- B级(60-74分):待改进,发送改进通知
- C级(<60分):预警,风险提示
技术实现:
- XXL-Job定时任务:每月1号00:30执行
- 任务分片:按供应商ID取模分片,多执行器并行计算
- 幂等性保证:唯一索引
(supplier_id, score_month) - 评分记录只增不改,可追溯历史变化
面试时怎么讲: “定时任务每月1号凌晨执行,查询上月采购数据,计算四个维度评分,汇总后得出综合评级。任务支持分片,多个执行器并行计算。评分记录写入流水表,只增不改。如果评级变化,自动发送通知,降为C级触发风险预警。“
二、核心技术方案(简历亮点)
1. 状态机设计
为什么需要:
- 防止非法状态流转(如草稿直接跳到已停用)
- 集中管理状态流转逻辑
- 便于维护和扩展
实现方式:
// 状态流转白名单
private static final Set<Transition> ALLOWED_TRANSITIONS = Set.of(
transition(DRAFT, PENDING_AUDIT), // 草稿 → 待审核
transition(PENDING_AUDIT, APPROVED), // 待审核 → 已通过
transition(PENDING_AUDIT, REJECTED), // 待审核 → 已拒绝
// ... 其他合法流转
);
// 状态变更前校验
if (!SupplierStateMachine.canTransit(currentStatus, targetStatus)) {
throw new BusinessException("当前状态不允许此操作");
}
// CAS乐观锁更新
int rows = supplierMapper.update(null,
new LambdaUpdateWrapper<Supplier>()
.eq(Supplier::getId, supplierId)
.eq(Supplier::getStatus, currentStatus) // 关键:WHERE条件
.set(Supplier::getStatus, targetStatus)
);
简历怎么写: “设计状态机管理供应商生命周期,定义5种状态和7种合法流转路径。用状态机白名单校验流转合法性,用CAS乐观锁防止并发修改,所有状态变更写入审核日志。避免了非法状态流转,保证了数据一致性。“
2. 文件上传方案(OSS)
技术选型:
- 开发环境:本地存储
- 生产环境:阿里云OSS
核心实现:
// 1. 文件校验
- 类型白名单:PDF/JPG/PNG
- 大小限制:最大10MB
- 文件名校验:防止路径穿越攻击
// 2. 存储路径设计
supplier/cert/2025/01/17/uuid.pdf // 按日期分目录
// 3. 访问权限控制
- 生成临时URL(有效期1小时)
- 租户隔离:只能访问本租户文件
// 4. 有效期管理
- 定时任务每天凌晨检查30天内到期的资质
- 自动发送到期提醒
简历怎么写: “实现文件上传模块,采用本地+OSS双模式。上传时校验文件类型和大小,生成UUID文件名,按日期分目录存储。文件访问通过接口控制权限,生成临时URL。定时任务每天检查资质有效期,提前30天发送到期提醒。“
3. 定时任务方案(XXL-Job)
为什么选XXL-Job:
- 分布式调度,支持任务分片
- 可视化管理界面
- 失败自动重试
- 完整的执行日志
核心任务:供应商绩效评分
@XxlJob("supplierScoreCalculate")
public void calculateScore() {
// 1. 获取分片参数
int shardIndex = XxlJobHelper.getShardIndex();
int shardTotal = XxlJobHelper.getShardTotal();
// 2. 查询本分片的供应商(按ID取模)
List<Supplier> suppliers = supplierMapper.selectList(
new LambdaQueryWrapper<Supplier>()
.eq(Supplier::getStatus, APPROVED)
.apply("MOD(id, {0}) = {1}", shardTotal, shardIndex)
);
// 3. 遍历计算评分
for (Supplier supplier : suppliers) {
calculateSupplierScore(supplier.getId(), lastMonth);
}
}
任务幂等性:
- 唯一索引:
UNIQUE KEY (supplier_id, score_month) - 重复执行会跳过已计算的记录
简历怎么写: “用XXL-Job实现供应商绩效评分定时任务,每月1号凌晨执行。任务支持分片,按供应商ID取模分配到多个执行器并行计算。查询上月采购数据,计算四维度评分,写入流水表。用唯一索引保证幂等性,评级变化自动发送通知。“
4. 审核幂等性设计
为什么需要幂等性:
- 网络超时导致前端重复提交
- 用户多次点击按钮
- 系统重试机制
实现方案:
// 方案1:状态前置判断(不是真正的幂等)
if (supplier.getStatus() == APPROVED) {
return Result.success("该供应商已审核通过");
}
// 方案2:CAS乐观锁(推荐)
int rows = supplierMapper.update(null,
new LambdaUpdateWrapper<Supplier>()
.eq(Supplier::getId, supplierId)
.eq(Supplier::getStatus, PENDING_AUDIT) // 关键
.set(Supplier::getStatus, APPROVED)
);
if (rows == 0) {
throw new BusinessException("供应商状态已变化");
}
// 方案3:唯一约束兜底
- portal_user_id唯一索引
- 邮箱唯一索引
简历怎么写: “审核操作用CAS乐观锁保证幂等性,UPDATE时WHERE条件判断当前状态必须是待审核。Portal账号创建时检查邮箱唯一性,防止重复创建。即使网络超时导致重复提交,也不会产生脏数据。“
三、简历怎么写
项目描述
项目:跨境电商 SaaS 供应链管理平台 - 供应商管理模块(SRM)
时间:2024.06 - 2024.12
角色:核心开发
技术:Spring Boot 3.2、MyBatis-Plus、MySQL 8.0、Redis、XXL-Job、阿里云OSS
这是个跨境电商的供应链 SaaS 平台,我负责供应商管理模块。系统管理供应商全生命周期,
包括信息管理、审核流程、资质文件管理、绩效评分、Portal协同等。支持多租户,
日均处理审核单 200+,管理供应商 5000+。
核心难点:
1. 供应商审核流程的状态流转控制
2. 审核操作的幂等性保证
3. 文件上传和存储方案
4. 供应商绩效自动评分和分级
5. 定时任务的分片和幂等性
核心亮点
1. 状态机管理供应商生命周期
问题:供应商状态可以随意修改,无法控制状态流转的合法性
方案:设计状态机白名单,集中管理状态流转逻辑
具体实现:
- 定义5种状态:草稿、待审核、已通过、已拒绝、已停用
- 定义7种合法流转路径,用Set存储状态流转白名单
- 每次状态变更前,先用状态机校验是否合法
- 用CAS乐观锁更新状态,WHERE条件判断当前状态
- 所有状态变更写入审核日志,只增不改不删
效果:
- 完全避免了非法状态流转
- 状态流转逻辑集中管理,易于维护
- 审核历史完整可追溯
2. 文件上传和OSS存储方案
问题:供应商资质文件需要长期保存,本地存储不可靠
方案:采用本地+OSS双模式,生产环境用阿里云OSS
具体实现:
- 文件校验:类型白名单(PDF/JPG/PNG)、大小限制(10MB)
- 文件名:UUID防止重名覆盖
- 存储路径:按日期分目录(supplier/cert/2025/01/17/uuid.pdf)
- 访问控制:生成临时URL(有效期1小时),租户隔离
- 有效期管理:定时任务每天检查30天内到期的资质,自动提醒
效果:
- 文件存储可靠性99.9999999%
- 支持CDN加速,全球访问快
- 资质到期提前提醒,避免过期
3. 供应商绩效自动评分系统
问题:人工评估供应商质量,主观性强,无法量化对比
方案:设计四维度评分体系,定时任务自动计算
具体实现:
- 评分维度:准时交货率、质量合格率、响应速度、价格竞争力,各25分
- 定时任务:XXL-Job每月1号00:30执行
- 任务分片:按供应商ID取模分片,多执行器并行计算
- 评分计算:查询上月采购数据,计算各维度评分,汇总得出综合评级(S/A/B/C)
- 幂等性保证:唯一索引(supplier_id, score_month)
- 评分记录只增不改,可追溯历史变化
效果:
- 评分客观公平,数据驱动决策
- 评级变化自动通知,及时预警
- 支持10000+供应商并行计算,2分钟完成
4. 审核操作的幂等性设计
问题:网络超时导致前端重复提交,可能产生重复审核、重复创建Portal账号
方案:CAS乐观锁 + 唯一约束兜底
具体实现:
- CAS乐观锁:UPDATE时WHERE条件判断当前状态必须是待审核
- 状态前置判断:先查询当前状态,如果已审核通过直接返回成功
- 唯一约束:portal_user_id、邮箱建唯一索引,防止重复创建
- 审核日志:记录每次操作,可追溯
效果:
- 完全避免了重复审核和重复创建账号
- 即使网络超时重复提交,也不会产生脏数据
四、面试高频问题
Q1:状态机是什么?为什么要用状态机?
答:状态机描述一个对象在生命周期中可能处于哪些状态,以及状态之间如何流转。
我们用状态机管理供应商,定义了5种状态和7种合法流转路径。好处是:
- 防止非法状态流转(如草稿直接跳到已停用)
- 状态流转逻辑集中管理,易于维护
- 便于扩展新的状态和流转规则
实现上,我们用一个Set存储状态流转白名单,每次状态变更前先校验是否在白名单中。
Q2:如何保证审核操作的幂等性?
答:我们用三层保障:
- 状态前置判断:先查询当前状态,如果已审核通过,直接返回成功
- CAS乐观锁:UPDATE时WHERE条件判断当前状态必须是待审核,如果状态已变化,更新失败
- 唯一约束兜底:Portal账号的邮箱建唯一索引,防止并发创建重复账号
这样即使网络超时导致重复提交,也不会产生脏数据。
Q3:文件上传为什么用OSS而不是本地存储?
答:本地存储有几个问题:
- 占用服务器磁盘空间
- 服务器重启或迁移,文件可能丢失
- 无法做CDN加速,下载慢
- 难以扩展
OSS的优势:
- 海量存储,按需付费
- 高可用,99.9999999%数据可靠性
- 支持CDN加速,全球访问快
- 自动备份,不怕丢失
我们采用本地+OSS双模式,开发环境用本地存储方便调试,生产环境用OSS保证可靠性。
Q4:定时任务如何保证幂等性?
答:我们用唯一索引保证幂等性。
在supplier_score_log表上建唯一索引:UNIQUE KEY (supplier_id, score_month)
如果重复执行,插入时会报DuplicateKeyException,捕获异常后跳过。这样即使任务重试,也不会重复计算评分。
Q5:任务分片是怎么实现的?
答:XXL-Job支持任务分片,原理是按数据ID取模分配。
比如有5个执行器,10000个供应商:
- 执行器1:处理ID % 5 = 0的供应商(2000个)
- 执行器2:处理ID % 5 = 1的供应商(2000个)
- …
代码实现:
int shardIndex = XxlJobHelper.getShardIndex(); // 当前分片序号
int shardTotal = XxlJobHelper.getShardTotal(); // 总分片数
List<Supplier> suppliers = supplierMapper.selectList(
new LambdaQueryWrapper<Supplier>()
.apply("MOD(id, {0}) = {1}", shardTotal, shardIndex)
);
这样多个执行器并行计算,性能提升5倍。
Q6:如果供应商本月没有采购数据,评分怎么处理?
答:不更新评分,保留上月评分,在calc_remark字段注明”本月无采购数据”。
这样既保证了评分的连续性,又记录了特殊情况。如果连续3个月没有采购数据,可以考虑标记为”不活跃供应商”。
Q7:状态机白名单如果要新增流转路径,怎么扩展?
答:直接在ALLOWED_TRANSITIONS集合中添加新的流转即可:
private static final Set<Transition> ALLOWED_TRANSITIONS = Set.of(
// 原有流转
transition(DRAFT, PENDING_AUDIT),
// 新增流转
transition(APPROVED, PENDING_AUDIT) // 已通过 → 待审核(重新审核)
);
这样状态流转逻辑集中管理,扩展非常方便。
Q8:文件上传如何防止恶意攻击?
答:我们有多层防护:
- 文件类型白名单:只允许PDF/JPG/PNG
- 文件大小限制:最大10MB
- 文件名校验:防止路径穿越攻击(../ 或 \)
- 访问权限控制:租户隔离,只能访问本租户文件
- 临时URL:有效期1小时,过期自动失效
- 病毒扫描:上传后自动扫描(可选)
五、面试准备建议
必须能画的图
供应商审核流程:
创建草稿 → 上传资质 → 提交审核 → 负责人审核
↓
通过 → 创建Portal账号 → 正式上线
拒绝 → 通知采购专员
退回 → 返回草稿状态
状态机流转图:
草稿(0) → 待审核(1) → 已通过(2) → 已停用(4)
↓ ↑
已拒绝(3) ←──────┘
必须能讲清楚的
- 什么是状态机?为什么要用状态机?
- 如何保证审核操作的幂等性?
- 文件上传为什么用OSS?
- 定时任务如何保证幂等性?
- 任务分片是怎么实现的?
表达技巧
- 先讲业务,再讲技术
- 用数据说话:性能提升5倍、可靠性99.9999999%
- 主动展开:不要等面试官问,主动讲状态机、幂等性、分片
- 准备追问:每个点都要准备2-3个追问
- 不要背书:要自然地表达
最后提醒:
面试前把这份笔记看2-3遍,重点记住:
- 供应商审核流程(5个步骤)
- 供应商绩效评分流程(4个维度)
- 状态机设计(5种状态,7种流转)
- 文件上传方案(OSS)
- 定时任务方案(XXL-Job分片)
- 简历上的4个亮点
面试时不要背书,要像讲故事一样自然地表达。如果面试官追问细节,可以展开讲技术实现。准备好画图,审核流程图、状态机流转图一定要能画出来。