
简介本资源为基于Java、SpringBoot、Vue与MySQL构建的反欺诈平台完整项目包面向需要完成毕业设计、课程设计或期末大作业的高校学生以及希望学习前后端分离架构的开发者。项目已通过导师指导并获高分评价下载后无需修改即可运行可直接用于信息安全、金融风险管理、电商平台管理等场景的实战参考。压缩包共753个文件约22.12MB涵盖101个Java后端源码、50个Vue前端组件、156个JavaScript脚本、49个CSS样式、31个HTML页面及1个SQL数据库脚本另含svg、png、gif等界面素材与mp4演示视频前后端代码、数据库脚本与构建工具一应俱全。目前已有51人学习下载。读者可获得一套模块化设计、前后端分离的完整反欺诈系统实现包括用户交互界面、数据管理逻辑与风险识别功能便于快速理解SpringBoot与Vue的整合方式并作为可复用的项目模板直接应用于学术或实际开发工作。1. 反欺诈平台从标题到落地一套 JavaSpringBootVueMySQL 的工程化拆解反欺诈平台这个词第一次接触的人容易把它想成某种风控算法黑匣子其实落到毕业设计或者中小团队自研的场景里它更像一套「规则 名单 事件流水」的工程系统。标题里给了四个技术锚点Java 做后端语言、SpringBoot 做服务框架、Vue 做前端、MySQL 做存储这套组合几乎是国内 Java 工程师最熟悉的一条技术栈也是面试题里被反复问到的 springboot 配置、vue 路由、mysql 锁的分类这些点的集合体。它要解决的问题很具体把用户注册、登录、下单、提现这些行为采集下来按规则打分命中高风险就拦截或人工复核。适合谁适合正在做毕业设计、想找一个能讲清楚分层架构又不太玄学的题目的人也适合想练手 SpringBoot 整合 MyBatis-Plus、Vue 前后端分离的中级开发者。下面我按自己搭过一遍的顺序把选型、建表、规则引擎、前后端联调和踩坑讲透。2. 反欺诈平台的技术选型与分层架构为什么是这套组合2.1 四个技术锚点各自承担什么职责先把职责边界划清楚不然后面写代码会互相打架。Java 在这里是语言底座负责所有业务逻辑和并发处理SpringBoot 负责把 Web 层、Service 层、持久层用自动配置串起来省掉大量 XMLVue 负责管理后台和用户端页面走前后端分离通过 axios 调 REST 接口MySQL 负责存用户、设备指纹、交易流水、规则配置和命中记录。这四者不是随便凑的反欺诈场景对「写多读多、规则要能热更新、命中要能追溯」有要求MySQL 的事务和索引能扛住流水写入SpringBoot 的 Bean 管理方便把规则做成可插拔组件。常见做法是把系统分成四层接入层Controller、业务层Service、规则层Rule Engine、数据层Mapper MySQL。规则层单独抽出来是因为反欺诈的核心价值在规则不在 CRUD。如果规则和业务代码揉在一起后面加一条「同一设备 5 分钟内注册超过 3 个账号」就得改一堆地方这是血泪经验。2.2 数据库表设计五张核心表撑起整个平台反欺诈平台的数据模型不用太复杂但几张关键表必须设计对。下面是我一般会用的最小表结构字段类型按 MySQL 8.0 写。表名作用关键字段t_user用户账户id, username, phone, status, create_timet_device设备指纹id, device_id, user_id, ip, user_agent, first_seent_event行为事件流水id, user_id, device_id, event_type, amount, event_timet_rule规则配置id, rule_code, rule_name, expression, score, enabledt_risk_record命中记录id, user_id, event_id, rule_code, risk_score, decision建表时有两个点容易翻车。第一t_event的event_time一定要建索引因为规则里大量按时间窗口查询比如「近 1 小时提现次数」。第二t_device的device_id要加唯一索引否则同一设备会被重复插入导致设备关联账号数统计虚高。MySQL 锁的分类里唯一索引冲突走的是行锁比全表扫描加表锁性能好得多这也是为什么设备表要提前约束。CREATE TABLE t_event ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL, device_id VARCHAR(64) NOT NULL, event_type VARCHAR(32) NOT NULL COMMENT REGISTER/LOGIN/ORDER/WITHDRAW, amount DECIMAL(12,2) DEFAULT 0, event_time DATETIME NOT NULL, KEY idx_user_time (user_id, event_time), KEY idx_device_time (device_id, event_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这段 SQL 里idx_user_time和idx_device_time是复合索引顺序不能反。规则查询基本是「某用户在某时间段内的事件数」复合索引把 user_id 放前面能直接命中。amount用 DECIMAL 不用 FLOAT是因为金额计算用浮点会出现精度丢失反欺诈里金额阈值判断一旦有误差误拦率就上去了。2.3 SpringBoot 项目结构怎么分才不乱SpringBoot 项目结构如果一开始不规划写到后面 Controller 里塞满业务逻辑是常态。我一般按下面这样分com.antifraud ├── controller // 接口层只做参数校验和返回封装 ├── service // 业务编排 │ └── impl ├── rule // 规则引擎独立包 │ ├── Rule.java // 规则接口 │ ├── RuleContext.java // 规则上下文 │ └── impl // 各条规则实现 ├── mapper // MyBatis-Plus Mapper ├── entity // 数据库实体 ├── dto // 传输对象 └── config // 配置类rule包单独拆出来是关键。每条规则实现同一个Rule接口SpringBoot 启动时把所有实现类注入到一个 List 里遍历执行。这样加规则只需要新增一个类不用动 Service。这也是 springboot 自定义自动配置思路的一个简化应用——用容器管理可扩展组件。public interface Rule { String code(); int score(RuleContext ctx); } Component public class DeviceMultiAccountRule implements Rule { Override public String code() { return DEVICE_MULTI_ACCOUNT; } Override public int score(RuleContext ctx) { // 统计该设备关联的账号数超过阈值给分 int count ctx.getDeviceAccountCount(); return count 3 ? 40 : 0; } }RuleContext里预加载了当前用户、设备、近期事件列表规则只做计算不做查询这样规则执行快且可测试。score返回风险分0 表示不命中。把所有规则分数累加超过阈值就拦截。参数说明阈值 3 和分数 40 都是可配置的实际项目里应该从t_rule表读这里为了讲清楚逻辑先写死。3. 规则引擎与风险评分从事件采集到拦截决策3.1 事件采集接口怎么写才不漏数据反欺诈的第一步是拿到数据。用户注册、登录、下单、提现这些动作都要落一条t_event。接口设计上我一般做一个统一的埋点入口而不是每个业务接口里各写各的。PostMapping(/event/report) public Result report(RequestBody EventDTO dto) { // 1. 补全设备信息 dto.setDeviceId(resolveDeviceId(dto.getUserId(), dto.getIp())); // 2. 落库 eventService.save(dto); // 3. 同步触发规则评估 RiskDecision decision ruleEngine.evaluate(dto.getUserId(), dto.getDeviceId()); return Result.ok(decision); }逻辑说明resolveDeviceId根据 userId 和 ip 去t_device查已有设备查不到就新建这样保证设备指纹稳定。落库和规则评估放在同一个请求里是为了让高风险操作能实时拦截。参数上event_type用枚举字符串而不是数字可读性好排查问题时不用查字典表。注意这里不要用异步线程池去评估规则除非你能接受「先放行后拦截」的补偿逻辑。实时拦截场景必须同步否则用户提现已经到账了规则才跑完拦截就失去意义。3.2 规则引擎的执行流程与评分聚合规则引擎的核心是一个循环加一个累加器。RuleEngine注入所有Rule实现逐个执行把分数加起来再根据总分决定放行、复核还是拦截。Service public class RuleEngine { Autowired private ListRule rules; public RiskDecision evaluate(Long userId, String deviceId) { RuleContext ctx contextLoader.load(userId, deviceId); int total 0; ListString hitCodes new ArrayList(); for (Rule rule : rules) { int s rule.score(ctx); if (s 0) { total s; hitCodes.add(rule.code()); } } String decision total 70 ? REJECT : total 40 ? REVIEW : PASS; riskRecordService.save(userId, deviceId, hitCodes, total, decision); return new RiskDecision(total, decision, hitCodes); } }参数说明70 和 40 是两个决策阈值分别对应拦截和人工复核。这两个值不要拍脑袋定上线前用历史数据跑一遍看误拦率和漏拦率的平衡点。hitCodes记录命中了哪些规则方便后面做规则效果分析——哪条规则天天命中但全是误报就该下线了。contextLoader.load是性能关键点。它要一次性把规则需要的所有数据查出来避免每条规则各查一次数据库。常见做法是用几个批量查询查用户近 24 小时事件、查设备关联账号数、查用户历史命中记录。这里如果偷懒在规则里直接调 MapperN 条规则就是 N 次查询接口响应时间直接翻倍。3.3 规则配置热更新不改代码就能调策略规则写死在代码里每次调阈值都要重新打包部署这在真实运营里不可接受。做法是把规则的开关和参数放到t_rule表启动时加载提供一个刷新接口。GetMapping(/rule/reload) public Result reload() { ListRuleConfig configs ruleConfigMapper.selectList(null); ruleEngine.refreshConfig(configs); return Result.ok(); }refreshConfig把数据库里的enabled和score覆盖到内存中的规则实例上。这样运营在后台改一条规则的分数调一下刷新接口就生效。注意并发问题刷新时用volatile或者AtomicReference持有配置避免规则执行到一半配置被改。这个点面试里常被追问 springboot 配置加载顺序其实就是 Bean 初始化和配置覆盖的时机问题。4. Vue 前端与 SpringBoot 联调管理后台和用户端的落地4.1 Vue 项目初始化和路由规划前端用 Vue 3 Vite 起步比老版本 webpack 快很多。vue 安装及环境配置这一步node 版本建议 18 以上不然 Vite 会报兼容错误。初始化命令npm create vitelatest antifraud-web -- --template vue cd antifraud-web npm install npm install axios vue-router pinia element-plus路由规划按角色分用户端登录、注册、我的订单和管理端规则管理、命中记录、用户列表。用 vue-router 的嵌套路由管理端统一挂在一个 Layout 下。const routes [ { path: /login, component: Login }, { path: /admin, component: AdminLayout, children: [ { path: rules, component: RuleList }, { path: records, component: RiskRecordList } ] } ];逻辑说明AdminLayout里放侧边栏和顶栏子路由渲染在router-view里。这样切换管理页面时布局不重新渲染体验好。参数上路由守卫要加未登录访问/admin直接跳登录页否则管理接口会被匿名调用。4.2 axios 封装与跨域处理前后端分离必然遇到跨域。开发阶段在 Vite 里配代理生产阶段用 Nginx 转发不要在后端无脑加CrossOrigin。// vite.config.js export default { server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true, rewrite: path path.replace(/^\/api/, ) } } } };axios 统一封装一个 request 实例拦截器里带上 token响应里统一处理错误码。const request axios.create({ baseURL: /api, timeout: 10000 }); request.interceptors.request.use(config { const token localStorage.getItem(token); if (token) config.headers.Authorization Bearer ${token}; return config; });参数说明timeout设 10 秒规则评估接口如果超过这个时间说明后端有慢查询应该去查contextLoader的 SQL。changeOrigin必须为 true否则代理请求的 Host 头不对后端可能拒绝。4.3 规则管理页面的表单设计规则管理页要能改分数、开关规则。用 element-plus 的表格加编辑弹窗。关键是把expression字段做成可读的展示而不是让运营直接写表达式——运营写错一个符号整条规则就废了。const submitRule async (rule) { await request.put(/rule/${rule.id}, rule); await request.get(/rule/reload); // 触发后端刷新 ElMessage.success(规则已更新); };逻辑说明改完规则主动调一次 reload保证内存配置和数据库一致。如果忘了这步运营会以为改了没生效其实是后端还在用旧配置这种问题排查起来很费时间。vue 打包放进 springboot 中也是常见需求把npm run build的产物放到resources/static下SpringBoot 就能直接托管前端适合单机部署的毕业设计场景。5. 反欺诈平台避坑排查五个真实踩过的坑5.1 规则分数累加导致误拦率飙升现象上线后发现大量正常用户被拦截命中记录里每条规则分数都不高但加起来超过阈值。原因规则之间有关联性同一行为被多条规则重复计分比如「新设备」和「异地登录」同时命中其实是一件事。解决给规则分组同组内只取最高分不同组才累加。或者引入权重衰减第二条命中规则分数打七折。5.2 设备指纹不稳定导致账号关联失效现象同一台手机用户清一次缓存 device_id 就变了设备关联账号数统计不准。原因device_id 只用前端生成的 UUID没做持久化。解决前端把 device_id 存 localStorage同时后端用 ip user_agent 做兜底指纹两者结合。注意 ip 会变所以只能作为辅助维度不能单独做主键。5.3 MySQL 时间窗口查询慢查询拖垮接口现象规则评估接口响应时间从 50ms 涨到 2s。原因t_event表数据量到百万级后event_time单列索引在范围查询加 user_id 过滤时没走对索引。解决建(user_id, event_time)复合索引并且查询时把 user_id 等值条件放前面。用EXPLAIN看执行计划type 是range才算正常出现ALL就是全表扫描。5.4 SpringBoot 版本太高导致依赖冲突现象引入某个老版本工具库后启动报NoSuchMethodError。原因SpringBoot 3.x 默认用 Jakarta EE包名从javax变成jakarta老库还在用javax。解决要么降 SpringBoot 到 2.7.x要么换支持 Jakarta 的库版本。毕业设计里如果没强制要求用 2.7.x 更省心网上资料也多。5.5 前端 token 过期后接口全部 401现象用户登录一段时间后所有请求返回 401页面白屏。原因axios 拦截器只处理了请求头没处理响应 401 的跳转。解决在响应拦截器里判断 401清除本地 token 并跳登录页。同时后端 token 过期时间别设太短管理后台建议 2 小时用户端可以 7 天。6. 把反欺诈平台做出差异化的三个进阶技巧第一个技巧是给规则加「灰度」。新规则上线不要直接全量生效先设一个enabled0但记录命中跑一周看命中量和误报率确认没问题再打开拦截。这个习惯能避免新规则上线当天把业务打挂。实现上就是在RuleEngine里对未启用规则只记录不累加分数。第二个技巧是用 MySQL 做简单的行为序列分析。反欺诈里「注册后立刻提现」是个强特征用 SQL 就能算SELECT user_id FROM t_event WHERE event_type REGISTER AND EXISTS ( SELECT 1 FROM t_event e2 WHERE e2.user_id t_event.user_id AND e2.event_type WITHDRAW AND e2.event_time BETWEEN t_event.event_time AND DATE_ADD(t_event.event_time, INTERVAL 10 MINUTE) );这条 SQL 找出注册后 10 分钟内提现的用户作为一条规则的数据源。参数上 10 分钟是可调的根据业务正常流程耗时来定。注意子查询在数据量大时要加索引否则会拖慢。第三个技巧是给命中记录做人工复核闭环。管理后台加一个「复核」按钮运营标记「确认欺诈」或「误报」这些标记回写到t_risk_record。积累几百条后你就能算出每条规则的准确率把准确率低于 30% 的规则下线。这一步是让平台从「能跑」变成「好用」的关键也是毕业设计答辩时最能讲出深度的点。我自己做这类平台最大的教训是一开始总想把规则写得很聪明结果误拦一堆正常用户后来才明白反欺诈的第一原则是别打扰正常用户宁可漏拦也别误拦。规则从宽到严慢慢调比一上来就上复杂模型靠谱得多。希望帮到你。本文还有配套的精品资源点击获取