● 计算机学习 · 求职成长一体化平台

码途 matu
从刷题学习到求职上岸的一站式平台

面向计算机专业学生与开发者,整合在线判题、面试题库、班级作业、问答社区、教程课程与 AI 助手, 以 Web、管理后台、小程序、移动 App 四端协同,覆盖「学 · 练 · 问 · 评」的完整链路。

GitHub: https://github.com/peakui/matucode

用户端 Web 管理后台 微信小程序 移动 App 微服务架构
React+Ant Design用户端
Vue+Element Plus管理员端
Uniapp+Flutter移动端
Spring Cloud微服务后端

项目概览

一个把「做题、学习、交流、教学管理」串起来的计算机学习社区。

学练闭环

教程与课程讲知识,在线判题即时反馈,面试题库按岗位准备,边学边练。

班级教学

教师建班、发作业、配题,学生做题提交,自动判题并生成作业排名。

社区共建

问答社区、文章发布、评论点赞与私信,把个人经验沉淀成公共知识。

AI 加持

AI 助手辅助答疑、文章摘要与内容生成,降低学习与创作的启动成本。

核心功能

覆盖学习、练习、交流、教学与运营的主要场景。

在线判题 OJ

多语言代码编辑器、样例与判题、提交记录与题解,沙箱隔离保障安全。

面试题库

按分类与难度整理的面试题,支持 VIP 解锁、收藏与学习进度追踪。

班级与作业

班级成员审核、题目池、作业布置与截止时间,提交后自动统计排名。

问答社区

提问、回答、采纳与评论,配合搜索与标签快速定位问题。

教程与课程

系统性教程文档与视频课程,支持章节学习与学习记录。

文章与创作

Markdown 编辑器、封面上传、分类标签,一键发布到首页信息流。

打卡签到

每日打卡与连续天数统计,用排行榜激励持续学习。

消息私信

站内通知、点赞评论提醒与一对一私信,保持互动触达。

会员与支付

会员权益、订单管理与权限校验,支撑平台的商业化能力。

多端展示

matu-user · 学习者主站(React + TypeScript + Ant Design + Vite)
matu-admin · 运营管理后台(Vue 3 + Element Plus + Pinia + Vite)
matu-liteapp · 微信小程序(uni-app)
matu-appp · 移动 App(Flutter + GetX)

核心技术实现

从 AI Agent 到支付交易、统一搜索、消息流转,挑十几个最能体现工程深度的子系统展开讲讲。

AI Agent · 工具调用与 MCP

自研 OpenAI 兼容客户端 · 多轮 Function Calling · MCP 工具协议 · 流式输出

  • 不绑定厂商:自研 OpenAiCompatibleClient(WebClient + SSE 流式),Embedding 兼容 OpenAI 与 DashScope 两套响应格式,换模型只改配置。
  • 多轮工具循环:AiAgentService 解析 tool_calls → 执行工具 → 回填结果 → 递归,由 ai.agent.max-tool-calls(默认 4)封顶,避免无限调用。
  • 工具即服务:工具后端是独立的 service-mcp,JSON-RPC 2.0 分发(McpDispatcher);内置课程检索、OJ 题目与提交查询、联网搜索、网页抓取(含 SSRF 防护)。
  • 上下文与检索:Redis List ai:memory:{userId}:{conversationId} 存近期对话(约 20 条 / 30 天),MySQL 落库持久化;pgvector ai_knowledge 做向量检索(1024 维,topK 5 / 阈值 0.7),检索异常静默降级。
  • 安全治理:PromptGuard 提示注入过滤、AiRateLimiter 限流(20 次/分、并发 2),重任务走 MQ 异步并配死信队列。
Function CallingMCP / JSON-RPC SSE 流式pgvector RAG限流与降级

点赞系统 · 高并发一致性

Redis 原子脚本 · 三级缓存 · 版本号 CAS · Outbox + 对账

  • 写路径全原子:单条 Lua 脚本在 Redis 内一次性完成「幂等判定 + 状态翻转 + 版本号 +1 + 写入待发队列」,天然免疫并发重复点赞。
  • 三级读取:Caffeine 本地缓存 → Redis(权威数据源)→ MySQL 兜底;本地缓存带随机抖动过期防雪崩,DB 兜底用信号量限 8 并发保护数据库。
  • 版本号 CAS:每次变更携带 version,落后版本返回 STALE,保证「新操作绝不被失败的旧操作回滚」。
  • 可靠投递:Redis Hash 当 outbox,定时任务补偿发 MQ,成功才清理;另有一份每日 2 点对账任务扫描 Redis 与 MySQL 差异并自动修复。
  • 热 key 探测:用 HeavyKeeper(重击者算法)统计访问频次,超过阈值才升级到本地缓存;所有键用 hash tag post:like:{postId}:* 保证同槽位、适配 Redis Cluster。
Redis LuaCaffeine L1 版本号 CASOutbox对账补偿热 key 探测

Docker 判题 OJ · 异步判题与沙箱

RabbitMQ 异步流水线 · 容器级隔离 · 资源限额 · 死信兜底

  • 异步解耦:提交先落库为 WAITING,事务提交后(afterCommit)才投递 oj.judge.queue;消费者手动 ack、prefetch=1,配合 Redis 锁 oj:judge:lock:{id} 防重复消费。
  • 失败兜底:应用内重试 3 次,耗尽后 basicNack(requeue=false) 经死信交换机 oj.judge.dlx 落入 oj.judge.dlq,不阻塞主队列。
  • 容器隔离:独立沙箱服务(docker-java)常驻容器 + exec 执行;关闭网络、只读根文件系统、tmpfs /tmp 限额 64M、CPU 1 核、内存上限且交换分区为 0。
  • 多语言与限额:openjdk:8-alpine / python:3.9-alpine / gcc:12.2.0;编译限 15s,运行默认 1000ms,退出码 137 判定为内存超限。
  • 状态机:8 态枚举(WAITING / AC / WA / RE / TLE / MLE / CE / SYSTEM_ERROR),逐样例比对,全部通过才判 AC。
RabbitMQ死信队列Docker 沙箱 cgroups 限额Redis 幂等锁

协同编辑 · 自研 OT 实时同步

Operational Transform · WebSocket 房间广播 · LMAX Disruptor

  • 自研 OT(非 CRDT):把编辑抽象为 insert / delete 的 TextOperation,由变换器做冲突合并(含重叠删除),服务端保存操作日志而非整篇覆盖。
  • 定序与幂等:提交以客户端 baseRevision 为基准,与之后已提交的操作逐一 transform 后再应用,全局 revision + 1;(clientId, requestId) 去重,重发请求直接返回原结果。
  • 实时通道:与私信共用 WebSocket 端点,握手统一走 Sa-Token 鉴权;房间内广播加入/离开/光标/正在输入,并把操作实时下发到各端。
  • 前端协同:编辑器本地 diff 出操作增量后经 WebSocket 上行,在线光标与选区随操作一同同步,实现「同文档多人同时编辑」。
  • 削峰异步:操作提交流水线接入 LMAX Disruptor 环形队列,把高频编辑从请求线程卸下来,避免阻塞。
Operational TransformWebSocket Sa-Token 鉴权LMAX Disruptor光标共享

支付宝支付 · 订单与回调一致性

官方 SDK · RSA2 验签 · 回调幂等 · 权益发放

  • 官方 SDK 接入:独立服务 service-pay(独立库),用 alipay-sdk-java 的 DefaultAlipayClient,支持扫码(Precreate)与网页(PagePay)两种下单方式。
  • 回调闭环:支付宝异步通知 POST /pay/alipay/notify → 全量验签并校验 app_id 与金额一致 → 更新订单与流水 → Feign 调用 service-auth 发放会员权益。
  • 双重幂等:通知日志按 notify_id 唯一去重;权益发放用 activation_key = "pay:" + 订单号 唯一键 + insertIgnore,重复通知不会重复发权益。
  • 并发串行化:订单与支付流水更新走 SELECT ... FOR UPDATE 行锁,避免同一订单被并发改单。
  • 状态机:OrderStatus(待支付 / 已支付 / 已关闭 / 已退款 / 部分退款)流转,下单与拉起支付时惰性判断 30 分钟支付截止时间并关闭超时单。
支付宝 SDKRSA2 验签 回调幂等行锁Feign 发权益

Elasticsearch 统一搜索 · 一栈搜全站

官方 Java API Client · 多字段加权 · 别名原子切换

  • 独立搜索服务:service-search 用官方 elasticsearch-java 客户端,统一检索文章 / 课程 / 面试题 / OJ 题目四类内容,type 区分、type=all 时聚合返回。
  • 字段加权检索:multiMatch 对标题、摘要、标签、分类做加权匹配(如标题权重 4、摘要权重 2),配合类型与状态过滤、深分页上限保护。
  • 零停机重建:同步时写入带时间戳的临时索引,bulk 导入完成后原子切换别名,失败即删除新索引——查询全程不中断。
  • 数据来源安全:各业务服务通过 /internal/search-documents 内部端点提供文档(游标分页推进),带共享令牌校验;网关对内部端点直接返回 404,杜绝公网直连。
  • 触发方式:定时自动重建(默认每 30 分钟)或管理端一键触发,重建期间旧索引照常服务。
Elasticsearch 8multiMatch 加权 别名原子切换内部令牌

分布式消息流转 · 事件驱动

4 组交换机 · 手动 ack · 死信兜底 · Outbox 补偿

  • 统一拓扑:4 组直连交换机各配死信队列,覆盖点赞、AI 文章摘要、AI 异步任务与 OJ 判题(如判题链路 oj.judge.exchange → oj.judge.queue,失败进 oj.judge.dlq)。
  • 可靠消费:手动 ack、prefetch 限流、应用内重试 3 次,耗尽后 basicNack(requeue=false) 落入死信队列,不再反复入队阻塞主链路。
  • 事务后投递:判题消息在事务 afterCommit 回调里才发送,从根上避免「消息已发出但事务回滚」的脏消息。
  • Outbox 兜底:数据库本地消息表 + 定时补投(AI 摘要),点赞侧用 Redis Hash 当 outbox;均等发布确认成功后才清理记录。
  • 跨服务事件:文章发布事件由内容服务投递到 AI 队列、由 AI 服务消费生成摘要,再经 HTTP 回写——典型的服务解耦与异步化。
RabbitMQ手动 ack 死信队列Outbox发布确认

网关零信任鉴权 · 身份签名与限流

Sa-Token · HMAC 身份签名 · 内部端点隔离

  • 集中式鉴权:网关用 Sa-Token 统一拦截,登录、注册、支付回调等白名单之外一律校验 token,业务服务不再各自重复鉴权。
  • 身份签名防伪造:网关校验 token 后签发用户 ID / 角色 / 时间戳,并用 HmacSHA256 签名;下游验签 + 30 秒时间戳偏移校验 + 常量时间比较,同时清除伪造的转发头,构成零信任边界。
  • 内部端点隔离:内部同步接口在网关侧强制登录或直接返回 404;服务间调用另带共享令牌(支付、搜索、AI 各有独立令牌)。
  • 网关限流与名单:敏感接口用 Redis Lua 固定窗口限流,另有 IP 黑白名单过滤器。
  • 会话与密码:同端登录可顶下线;密码用 BCrypt(强度 12)存储,历史 SHA-256 账号登录成功后透明升级。
Sa-TokenHmacSHA256 内部令牌Lua 限流BCrypt

文件服务 · 分片上传与秒传

对象存储分片 · 断点续传 · MD5 去重

  • 分片上传:走对象存储的「初始化 → 上传分片 → 完成」三段式,用分片记录表保存已传进度,支持大文件断点续传。
  • 秒传:以文件 MD5 + 大小做去重,命中已存在文件直接返回句柄,跳过整个上传过程。
  • 僵尸清理:定时任务定期中止长期未完成的分片上传,回收存储空间与未完成配额。
  • 上传安全:服务端按白名单判定内容类型,防止把 HTML 伪装成图片造成存储型 XSS;私有文件下载走签名 URL。
OSS 分片上传断点续传 MD5 秒传Content-Type 白名单

竞赛排名 · ICPC 罚时赛制

真实赛制算法 · 网格榜输出

  • 赛制规则:按「解题数 > 罚时 > 最后 AC 时间」排序;罚时 = AC 用时 + 错误提交数 × 20 分钟,基准时间取竞赛开始或最早提交,贴近真实 ICPC 规则。
  • 网格榜:返回逐题状态的网格数据(每题是否通过、该题尝试次数),前端可直接渲染成竞赛榜单。
  • 范围约束:只统计竞赛时间窗内、竞赛题目池内的提交,避免场外提交刷榜。
ICPC 罚时排行榜竞赛时间窗

打卡统计 · 连续天数与成就

增量统计 · 连击计算 · 成就体系 · 补签

  • 连续天数:扫描日历计算当前连续与历史最长连续打卡天数,跨月也能正确衔接。
  • 增量统计:按月的统计表增量刷新,避免每次心跳都全量重算,排行榜与个人页读取更快。
  • 成就体系:按累计打卡天数、发布内容数、最长连击等多维度判定成就并实时刷新。
  • 补签:支持补签(限一年内),补签后自动重建当月的统计与连续天数。
连续天数增量统计表 成就判定补签

面试接口防护 · 多级限流与动态熔断

网关 + 服务双配额 · 阶梯封禁 · Sentinel 热更新

  • 第一层 · 网关限流:Redis Lua 固定窗口限流,拦住粗粒度的高频流量。
  • 第二层 · 服务内双配额:Lua 脚本同时维护短期与 24 小时两级配额,超限后阶梯封禁(多次触发则封禁时长从分钟级升到小时级)。
  • 第三层 · 动态熔断:Sentinel 的 QPS 流控与响应时间降级规则由 Nacos 下发并热更新;配置非法时回退到上一次生效的规则,避免改错配置反而打穿保护。
  • 效果:爬取、刷接口等异常流量在三层拦截下逐级衰减,正常用户几乎无感。
Lua 固定窗口双配额 阶梯封禁Sentinel + Nacos

其它工程细节

贯穿各模块的通用设计取舍

  • 服务治理:Nacos 注册与配置中心 + Gateway 统一入口,服务间用 OpenFeign 内网调用并带内部密钥头,超时可控。
  • 数据访问:MyBatis-Plus + 游标分页 + 批量操作;数据库变更用 Flyway 版本化迁移,改表前做列存在性守卫保证幂等可重复执行。
  • 权限模型:RBAC 角色(普通用户 / 管理员 / 讲师 / 会员),网关与服务内双重校验,权限绝不信任前端。
  • 实时能力分层:AI 问答走 SSE 流式,协同与私信走 WebSocket,判题、摘要、点赞走 MQ——按场景选型而非一栈到底。
  • 安全细节:网页抓取工具做 SSRF 防护(拦截环回、内网与云元数据地址),AI 侧有提示注入词表过滤,文件上传有内容类型白名单。
  • 可观测与容错:关键链路带日志埋点;缓存、检索、下游服务异常均有降级路径,单点故障不拖垮主流程。

技术栈

前端多端统一体验,后端微服务与容器化判题。

用户端 Web

React 19TypeScriptAnt Design 6 Redux ToolkitReact Router 7Vite Monaco EditorMarkdown 编辑器

管理后台

Vue 3Element PlusPinia Vue RouterSassVite

后端服务

Java 17Spring Boot 3Spring Cloud NacosGatewayOpenFeign MyBatis-PlusMySQLFlyway RabbitMQ

判题与多端

Docker 沙箱异步判题 uni-app 小程序Flutter + GetX App