当前位置: 首页 > news >正文

视频网站弹幕系统简易实现

要实现的是 “历史弹幕 + 实时弹幕” 混合的完整弹幕系统,类似 B 站的做法。

我们来一步步设计并实现它👇


✅ 场景目标

你的视频播放器要支持:

功能说明
🎞 历史弹幕视频开始播放时加载过去用户发送的弹幕,按时间同步展示
🧑‍💻 实时弹幕当前用户或其他用户正在发的弹幕,立即出现在屏幕上

🧠 核心设计理念

🔁 整体流程图

                   ┌────────────┐┌────────────▶│ WebSocket  │◀────────────┐│             │ 服务器广播 │              ││             └─────▲──────┘              ││                   │                     │▼             ┌─────┴──────┐              ▼[观看者A]        [Spring Boot 后端]       [观看者B]│  GET 弹幕历史    ▲        │       GET 弹幕历史 ││                 数据库     │                   │▼                            ▼                   ▼
同步播放历史弹幕         接收实时弹幕          接收实时弹幕

🧱 技术实现拆解

🔸 后端

✅ 数据模型(MySQL)
CREATE TABLE danmu (id BIGINT PRIMARY KEY AUTO_INCREMENT,video_id BIGINT NOT NULL,text VARCHAR(255) NOT NULL,time_in_video DOUBLE NOT NULL,  -- 出现的时间(秒)send_time DATETIME NOT NULL
);
✅ 接口 1:获取历史弹幕
@GetMapping("/api/danmu/history")
public List<DanmuDto> getHistory(@RequestParam Long videoId) {return danmuRepository.findByVideoIdOrderByTimeInVideo(videoId);
}
✅ 接口 2:WebSocket 实时弹幕服务
@ServerEndpoint("/ws/danmu/{videoId}")
@Component
public class DanmuWebSocket {private static final Map<String, Session> sessionMap = new ConcurrentHashMap<>();@OnOpenpublic void onOpen(Session session, @PathParam("videoId") String videoId) {sessionMap.put(session.getId(), session);}@OnMessagepublic void onMessage(String msgJson, Session session, @PathParam("videoId") String videoId) {// 解析 JSON 为 Danmu 对象Danmu danmu = new Gson().fromJson(msgJson, Danmu.class);danmu.setSendTime(LocalDateTime.now());// 保存弹幕到数据库danmuService.save(danmu);// 广播给所有客户端sessionMap.values().forEach(s -> {try {s.getBasicRemote().sendText(msgJson);} catch (IOException e) {e.printStackTrace();}});}@OnClosepublic void onClose(Session session) {sessionMap.remove(session.getId());}
}

🔸 前端(HTML + JS)

✅ 加载历史弹幕并同步播放
let historyDanmus = []; // { time: 3.5, text: "弹幕内容" }fetch("/api/danmu/history?videoId=101").then(res => res.json()).then(data => {historyDanmus = data.sort((a, b) => a.time - b.time);});setInterval(() => {const currentTime = video.currentTime;while (historyDanmus.length && historyDanmus[0].time <= currentTime) {showDanmu(historyDanmus.shift().text);}
}, 200);
✅ 实时弹幕连接
const socket = new WebSocket("ws://localhost:8080/ws/danmu/101");socket.onmessage = (event) => {const danmu = JSON.parse(event.data);showDanmu(danmu.text);
};function sendDanmu(text) {const time = video.currentTime;socket.send(JSON.stringify({ videoId: 101, text, time }));
}

🔸 弹幕展示动画(CSS + JS)

function showDanmu(text) {const el = document.createElement("div");el.className = "danmu";el.innerText = text;el.style.top = Math.random() * 80 + "%";el.style.color = randomColor();document.getElementById("danmu-area").appendChild(el);setTimeout(() => el.remove(), 8000);
}

✅ 总结:逻辑分工

功能负责方技术
视频播放进度监听前端video.currentTime
加载历史弹幕后端接口GET /api/danmu/history
弹幕显示同步播放前端 JS + 定时器每 200ms 检查一次
实时弹幕收发WebSocket后端广播 + 前端展示
数据存储MySQLtimeInVideo + text

✅ 用户视角体验流程

  1. 打开视频页面
  2. 请求并同步播放历史弹幕
  3. 用户点击发送 → 发到 WebSocket
  4. 后端广播 + 存库
  5. 所有在线用户立即看到

http://www.dtcms.com/a/270182.html

相关文章:

  • Python语言+pytest框架+allure报告+log日志+yaml文件+mysql断言实现接口自动化框架
  • Android Handler机制与底层原理详解
  • RHA《Unity兼容AndroidStudio打Apk包》
  • 什么是2.5G交换机?
  • 【如何下载网页中的视频】
  • 【HarmonyOS】鸿蒙端云一体化开发入门详解 (一)
  • 零基础 Qt 6 在线安装教程
  • vue前置知识-end
  • 呼叫系统对接智能体能解决哪些问题?
  • exFAT文件系统mp4素材文件变0字节的恢复方法
  • Spring中过滤器和拦截器的区别及具体实现
  • ROS平台上使用C++实现A*算法
  • 3423. 循环数组中相邻元素的最大差值 — day97
  • MySQL 8.0 OCP 1Z0-908 题目解析(23)
  • 服务端渲染
  • VMware克隆虚拟机,模板机已提前设置了固定IP,克隆机需要修改的事项
  • Java项目:基于SSM框架实现的旅游协会管理系统【ssm+B/S架构+源码+数据库+毕业论文】
  • Web前端开发: :where(伪类函数选择器)
  • 软件设计与重构
  • docker部署单机gitlab
  • Pytorch实战——完整的模型训练套路2
  • GitOps实践指南:GitLab CI/CD + ArgoCD 实现 Kubernetes 自动化部署
  • 【AI大模型】深度学习正则化技术:Batch Normalization (BatchNorm) 详解
  • 【GPT深度研究】科研SaaS项目可行性分析报告
  • 【学习笔记】网络设备(华为交换机)基础知识 24 —— 以太网子接口基础知识
  • 【入门级-C++程序设计:3、程序基本语句-多层循环语句】
  • 数据推荐|标贝科技大规模高质量数据集
  • 25.安卓逆向2-frida hook技术-拦截弹框事件(拦截强制更新弹框和解决jadx加载dex文件不全问题)
  • 从0到1搭建ELK日志收集平台
  • 扣子Coze飞书多维表插件参数获取流程