React+Spring Boot在线教育平台开发:实时直播课堂与作业管理系统的技术架构实践
在线教育行业近年快速发展直播课堂和互动教学成为核心功能需求。承恒信息科技曾协助一家职业教育机构开发在线学习平台从需求分析到上线交付过程中直播延迟、万人同时在线选课的高并发处理以及作业自动批改是三个最具技术挑战的环节。本文将分享这套基于ReactSpring Boot技术栈的完整实现方案。一、平台架构与技术选型平台前端采用React 18 Ant Design构建教师端和学生端后端使用Spring Boot 3 MyBatis-Plus MySQL Redis。直播模块基于WebRTC SRSSimple Realtime Server推流方案实时互动使用Socket.IO实现双向通信。系统分为课程管理、直播课堂、作业系统、学习数据中心四大模块。选课高峰期并发量可达平时的20倍Redis负责缓存课程列表、用户选课状态和直播间人数统计通过Lua脚本保障扣减库存的原子性。MySQL采用读写分离架构主库写入选课记录从库查询课程信息分摊读压力。二、高并发选课系统与Redis优化选课是教育平台的高并发场景热门课程开放选课时瞬间QPS可达上万。以下是基于Redis Lua脚本实现的选课核心代码确保不超卖Servicepublic class CourseSelectionService {Autowiredprivate RedisTemplateredisTemplate;Autowiredprivate CourseMapper courseMapper;Autowiredprivate RabbitTemplate rabbitTemplate;private static final String COURSE_STOCK_KEY course:stock:;private static final String SELECTED_SET_KEY course:selected:;// Lua脚本原子性检查扣减库存记录选课private static final String SELECT_LUA local stock redis.call(GET, KEYS[1])\n if not stock or tonumber(stock) script new DefaultRedisScript(SELECT_LUA, Long.class);Long remaining redisTemplate.execute(script,List.of(stockKey, setKey), userId.toString());if (remaining null || remaining -1) {return Result.fail(课程已满选课失败);}if (remaining -2) {return Result.fail(您已选择该课程请勿重复选课);}// 异步写入数据库削峰填谷CourseSelectionMessage msg new CourseSelectionMessage();msg.setCourseId(courseId);msg.setUserId(userId);msg.setSelectedAt(LocalDateTime.now());rabbitTemplate.convertAndSend(course.selection.queue, msg);return Result.ok(选课成功, remaining);}/*** 选课结果异步落库消费者*/RabbitListener(queues course.selection.queue)public void persistSelection(CourseSelectionMessage msg) {try {CourseSelection selection new CourseSelection();selection.setCourseId(msg.getCourseId());selection.setUserId(msg.getUserId());selection.setSelectedAt(msg.getSelectedAt());selection.setStatus(ACTIVE);courseMapper.insertSelection(selection);} catch (DuplicateKeyException e) {// 唯一索引兜底防止重复选课log.warn(重复选课被数据库唯一索引拦截: user{}, course{},msg.getUserId(), msg.getCourseId());}}/*** 课程库存预热到Redis*/public void preloadCourseStock(Long courseId) {Course course courseMapper.selectById(courseId);if (course ! null) {int remaining course.getMaxCapacity() - course.getSelectedCount();redisTemplate.opsForValue().set(COURSE_STOCK_KEY courseId, remaining, 24, TimeUnit.HOURS);log.info(课程库存预热: courseId{}, remaining{}, courseId, remaining);}}}选课方案通过Lua脚本将库存检查、扣减和选课记录合并为一次原子操作Redis端响应时间2ms。数据库写入通过rabbitmq异步削峰避免瞬时高并发直接冲击mysql。在压测中1万qps并发选课场景下无超卖选课结果在30秒内全部落库数据库cpu峰值仅35%。三、实时直播课堂与互动直播课堂使用WebRTC推流到SRS媒体服务器学生端通过HLS/FLV协议拉流观看。实时互动举手、提问、答题通过Socket.IO双向通信实现。以下是Spring Boot端的Socket.IO互动消息处理代码Configurationpublic class SocketIOConfig {Beanpublic SocketIOServer socketIOServer() {com.corundumstudio.socketio.Configuration config new com.corundumstudio.socketio.Configuration();config.setPort(9092);config.setWorkerThreads(8);config.setBossThreads(2);config.setPingInterval(30000);config.setPingTimeout(60000);config.setMaxFramePayloadLength(1024 * 1024); // 1MBconfig.setMaxHttpContentLength(1024 * 1024);return new SocketIOServer(config);}}Componentpublic class ClassroomEventHandler {Autowiredprivate SocketIOServer server;Autowiredprivate RedisTemplateredisTemplate;private static final String ROOM_KEY classroom:room:;OnConnectpublic void onConnect(SocketIOClient client) {String roomId client.getHandshakeData().getSingleUrlParam(roomId);String userId client.getHandshakeData().getSingleUrlParam(userId);String role client.getHandshakeData().getSingleUrlParam(role);client.joinRoom(roomId);// Redis记录在线状态redisTemplate.opsForHash().put(ROOM_KEY roomId, userId, role);// 广播有人加入OnlineCountEvent event new OnlineCountEvent();event.setRoomId(roomId);event.setOnlineCount(redisTemplate.opsForHash().size(ROOM_KEY roomId));server.getRoomOperations(roomId).sendEvent(userJoined, event);}OnEvent(raiseHand)public void onRaiseHand(SocketIOClient client, RaiseHandRequest request) {String roomId client.getHandshakeData().getSingleUrlParam(roomId);// 仅教师端接收举手通知server.getRoomOperations(roomId).sendEvent(studentRaisedHand, request);}OnEvent(submitAnswer)public void onSubmitAnswer(SocketIOClient client, AnswerRequest request) {String roomId client.getHandshakeData().getSingleUrlParam(roomId);// 统计答题结果并实时推送String statsKey classroom:answer: roomId : request.getQuestionId();redisTemplate.opsForHash().increment(statsKey, request.getAnswer(), 1);Mapstats redisTemplate.opsForHash().entries(statsKey);AnswerStatsEvent statsEvent new AnswerStatsEvent();statsEvent.setQuestionId(request.getQuestionId());statsEvent.setStats(stats);server.getRoomOperations(roomId).sendEvent(answerStats, statsEvent);}OnDisconnectpublic void onDisconnect(SocketIOClient client) {String roomId client.getHandshakeData().getSingleUrlParam(roomId);String userId client.getHandshakeData().getSingleUrlParam(userId);redisTemplate.opsForHash().delete(ROOM_KEY roomId, userId);OnlineCountEvent event new OnlineCountEvent();event.setRoomId(roomId);event.setOnlineCount(redisTemplate.opsForHash().size(ROOM_KEY roomId));server.getRoomOperations(roomId).sendEvent(userLeft, event);}}直播互动方案通过Socket.IO实现毫秒级双向通信举手、答题等互动事件延迟100ms。在线人数通过redis hash四、作业自动批改与部署作业系统支持客观题自动批改和主观题AI辅助评分。客观题通过标准答案比对自动计分主观题通过自然语言处理算法给出参考分。以下是作业批改服务和Docker部署配置# docker-compose.yml 在线教育平台部署version: 3.8services:# Spring Boot 后端education-api:build: ./education-backendports: [8080:8080]environment:- SPRING_PROFILES_ACTIVEprod- MYSQL_HOSTmysql-master- REDIS_HOSTredis- RABBITMQ_HOSTrabbitmq- SRS_SERVERsrs:1985depends_on: [mysql-master, mysql-slave, redis, rabbitmq, srs]deploy:replicas: 3resources:limits: { cpus: 2, memory: 1G }# React 前端Nginx托管education-web:build: ./education-frontendports: [80:80, 443:443]volumes:- ./nginx.conf:/etc/nginx/nginx.conf- ./ssl:/etc/nginx/ssl# Socket.IO 互动服务socketio-server:build: ./socketio-serviceports: [9092:9092]environment:- REDIS_HOSTredisdeploy:replicas: 2# SRS 直播推流服务器srs:image: ossrs/srs:5ports: [1935:1935, 8080:8080, 1985:1985]volumes:- ./srs.conf:/usr/local/srs/conf/srs.conf# MySQL 读写分离mysql-master:image: mysql:8.0environment:MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}MYSQL_DATABASE: educationvolumes: [mysql_master_data:/var/lib/mysql]mysql-slave:image: mysql:8.0environment:MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}MYSQL_DATABASE: educationMYSQL_MASTER_HOST: mysql-masterdepends_on: [mysql-master]volumes: [mysql_slave_data:/var/lib/mysql]redis:image: redis:7-alpinecommand: redis-server --maxmemory 1gb --maxmemory-policy allkeys-lru --appendonly yesvolumes: [redis_data:/data]rabbitmq:image: rabbitmq:3.12-managementports: [5672:5672, 15672:15672]volumes:mysql_master_data:mysql_slave_data:redis_data:平台采用完整的容器化部署方案后端3副本负载均衡MySQL主从读写分离SRS独立部署处理直播推流。生产环境运行指标直播首屏加载时间1.2秒互动消息平均延迟80ms选课系统支持1万QPS并发作业自动批改客观题准确率100%主观题AI评分与人工评分相关系数达0.85。平台已稳定服务3万余名学生日均直播课时超过500小时。

相关新闻

深入理解Ajax核心机制与实战技巧

深入理解Ajax核心机制与实战技巧

1. 从零理解Ajax的核心机制 2005年,Jesse James Garrett首次提出"Asynchronous JavaScript and XML"这个术语时,可能没想到它会成为现代Web开发的基石。我在2010年第一次接触Ajax时,被它无需刷新页面就能更新内容的能力震撼——这彻…

2026/10/20 4:51:15 阅读更多 →
Jupyter Notebook:Python数据科学交互式开发指南

Jupyter Notebook:Python数据科学交互式开发指南

1. Jupyter Notebook:Python开发者的交互式利器第一次接触Jupyter Notebook是在2016年的一个数据分析项目上。当时我需要频繁地测试数据清洗代码片段,传统IDE的"编辑-运行-调试"循环让我效率低下。直到同事推荐了这个能直接在浏览器里写Python…

2026/10/19 12:14:39 阅读更多 →
MySQL与Redis在数据收集系统中的优化实践

MySQL与Redis在数据收集系统中的优化实践

1. 项目概述"2024-12-08-2-收集"这个看似简单的标题背后,实际上隐藏着一个典型的数据收集与分析项目。作为一名长期与数据库打交道的开发者,我见过太多类似的项目命名方式——用日期和序号来标记数据收集批次。这种命名虽然简单直接&#xff0…

2026/10/19 13:02:47 阅读更多 →

最新新闻

MVMD联合小波阈值去噪:多通道非平稳信号MATLAB实战

MVMD联合小波阈值去噪:多通道非平稳信号MATLAB实战

简介:这份资源面向信号处理、故障诊断与振动监测方向的学习者和研究人员,提供一套基于MATLAB的完整联合去噪方案,用于从含噪多通道信号中恢复原始信号。核心流程涵盖MVMD多元变分模态分解、基于相关系数的有效模态筛选、小波阈值去噪、模态重…

2026/10/20 17:03:25 阅读更多 →
Jenkinsfile编写五大致命难点与生产级避坑指南

Jenkinsfile编写五大致命难点与生产级避坑指南

1. 项目概述:Jenkinsfile不是“写脚本”,而是定义持续交付流水线的契约你有没有在某个周五下午三点,刚把 Jenkinsfile 提交到 Git 仓库,CI 流水线就突然卡在“Checkout”阶段,日志里只有一行红色报错:hudso…

2026/10/20 17:03:25 阅读更多 →
NFS安全加固:封堵showmount -e信息泄露漏洞CVE-1999-0554

NFS安全加固:封堵showmount -e信息泄露漏洞CVE-1999-0554

在给一批NFS服务器做安全体检时,我用 showmount -e 扫了一遍内网,结果让我后背发凉——几乎一半的机器把完整导出列表敞开给了任何能摸到端口的人。这不是个新问题,它的编号叫 CVE-1999-0554,二十多年前就被登记在案&#xff0c…

2026/10/20 17:03:25 阅读更多 →
ShardingSphere未分片表SQL检测跳过机制解析

ShardingSphere未分片表SQL检测跳过机制解析

1. 项目概述:为什么“未分片表跳过SQL检测”不是Bug,而是关键设计取舍Apache ShardingSphere作为国内主流的数据库中间件,这几年在金融、电商、政务类系统中落地非常扎实。我接触过的几十个真实项目里,有超过七成在上线前都卡在一…

2026/10/20 17:03:25 阅读更多 →
SonarQube安装部署全指南:从环境准备到代码质量平台落地

SonarQube安装部署全指南:从环境准备到代码质量平台落地

最近帮一个团队把代码静态检查环境搭起来,我在测试服务器上完整走了一遍sonar安装的流程。以前看别人部署SonarQube觉得就是下载、解压、启动三连,真到自己上手才发现,这玩意儿对环境的要求比想象中多:数据库版本要匹配、内置搜索…

2026/10/20 17:03:25 阅读更多 →
AI驱动的自动化渗透测试原理与金融行业防御实战

AI驱动的自动化渗透测试原理与金融行业防御实战

1. 项目概述:当金融业遭遇AI驱动的渗透测试新范式最近几周,多家韩国金融机构的公开通报和内部安全简报在技术圈悄然流传——不是传统意义上的“勒索软件爆发”或“钓鱼邮件泛滥”,而是更令人警觉的模式:攻击者未依赖社会工程&…

2026/10/20 17:02:23 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →