Java在线直播平台源码解析:HLS直播链路从推流到播放的完整实践
发布时间:2026/9/16 5:49:55 锦皓数字建站

简介这是一份基于Java开发的在线直播平台完整项目源码适配期末大作业、毕业设计或课程设计场景适合需要快速搭建直播类Web应用并理解其前后端协作的Java学习者。项目由高分通过的期末大作业提炼而成下载后简单配置部署即可运行。压缩包共137个文件其中55个Java文件承载后端业务逻辑20个HTML页面、12个CSS样式表与7个JavaScript脚本共同构建前端展示与交互17张PNG和17张JPG图片提供界面素材另有properties、conf、xml等文件负责参数配置整体仅7.46MB结构清晰便于按模块查阅和二次修改。包内还包含nginx与srs相关流媒体配置并集成DPlayer、video.js等播放组件可帮助读者掌握在线直播平台从推流、分发到页面播放的完整链路。已有194人学习/下载适合作为JavaWeb综合实践、毕业设计原型或直播功能模块复现的参考。1. 期末大作业名头之下真正值得拆的是 HLS 这条链路压缩包名字写着“期末大作业”但把文件铺开看它不是普通的增删改查演示mvnw.cmd 说明后端是 Maven 工程nginx.live.conf 和 srs.http.hls.conf 说明媒体部分用了 SRS 做 HLS 直播DPlayer、Video.js 说明播放端走浏览器拉流chatMain.css、loginStyle.css 说明聊天和用户面板已经切好。把这份 Java 在线直播平台源码跑起来最大的收获不是交一份作业而是把“推流 → 切片 → 分发 → 播放 → 聊天”这条完整链路拆清楚。适合正在准备毕业设计、期末大作业的 Java 方向学生也适合后端工程师想给现有项目快速加直播模块时做参照。2. 从 mvnw.cmd 到 Spring Boot 进程后端先从压缩包变成可运行服务2.1 mvnw.cmd 解决了构建环境不一致的问题压缩包里出现 mvnw.cmd说明这个 Java 项目使用 Maven Wrapper 管理构建。Wrapper 的价值在于锁定 Maven 版本它读取.mvn/wrapper/maven-wrapper.properties里的 distributionUrl在没有预装 Maven 的机器上也能拉取指定版本执行构建。对答辩和演示场景来说这比要求现场装 Maven 可靠得多。拿到压缩包后第一件事不是改代码而是验证构建工具本身能跑通。Windows 下用mvnw.cmdLinux 或 macOS 下用./mvnw两者逻辑一致。cd online-live mvnw.cmd -v mvnw.cmd clean package -DskipTests -Dfile.encodingUTF-8 java -jar target/online-live-0.0.1-SNAPSHOT.jar --server.port8080第一条命令如果打印出完整的 Maven 和 JDK 版本说明 wrapper 正常接着谈编译才有意义。第二条clean package把清理、编译、打包合并成一步-DskipTests跳过测试类很多课程设计的测试类并不适配演示环境跳过能少一个失败点-Dfile.encodingUTF-8避免 Windows 控制台把源码里的中文注释显示成乱码。第三条java -jar启动 Spring Boot 的可执行 jar--server.port8080用命令行参数覆盖配置文件端口端口被占用时改成--server.port8081即可。具体 jar 包名要看 pom.xml 里的 artifactId可以用ls target确认。提示mvnw.cmd -v报错时先查 JAVA_HOME 是否指向 JDK 安装目录再看配置里的 distributionUrl 是否可达这两个是 wrapper 无法自行绕过的问题。2.2 后端进程起来之后先确认它给直播链路提供什么Java 后端在这个项目里负责业务面不负责媒体面。它要管三件事用户登录、聊天消息、直播流地址查询。登录接口负责把前端页面和用户身份关联起来直播流地址接口告诉播放器 m3u8 在哪聊天消息通过 WebSocket 或轮询推到前端。与直播相关的配置通常会集中在 application 配置里。下面是一个与这套源码场景匹配的典型写法server: port: 8080 live: push-url: rtmp://127.0.0.1:1935/live/live hls-url: http://127.0.0.1:8088/live/live.m3u8 chat: path: /ws/chat enabled: truelive.push-url是给推流工具填的 RTMP 地址对应 SRS 的 1935 端口OBS 或 ffmpeg 推流时填这一条。live.hls-url是给浏览器播放器用的 HLS 地址走 Nginx 的 8088 端口。chat.path是聊天消息通道前后端约定同一个路径即可。注意推流端口和播放端口很可能不一致这是直播项目的正常状态推流走 RTMP播放走 HTTP。2.3 端口规划直接决定演示现场是否翻车这个项目同时存在 Java 进程、SRS 进程和 Nginx 进程三张端口网互相叠加最常见的演示事故就是端口冲突导致某个进程静默失败。建议把端口关系在部署第一天就固定下来。进程默认端口在项目里的角色冲突时优先改谁Spring Boot 后端8080登录、聊天、业务 API改成 8081SRS 主服务1935接收 RTMP 推流保持 1935 不动SRS HTTP API1985查询推流状态与前端无关可改Nginx 播放入口8088对外提供 m3u8 和 ts尽量保持 8088 不变建议把后端端口改成 8081SRS 的 1935 推流口和 1985 API 口保留播放统一从 Nginx 的 8088 出口。这样做的好处是浏览器页面里只有一个媒体源地址m3u8 和页面同源跨域问题降到最低。别等到答辩前夜再调端口三个进程同时跑起来以后再改配置很容易漏改一处导致播放器黑屏。3. srs.http.hls.conf 与 nginx.live.conf推流、切片与播放出口3.1 SRS 和 Nginx 在链路里的分工srs.http.hls.conf是 SRS 流媒体服务器的实例配置不是前端文件。它的任务是接收推流端的 RTMP 信号按设定参数把视频切片成 ts 分片并生成 m3u8 播放列表。Nginx 的nginx.live.conf则把切片目录以静态文件方式暴露给浏览器前端播放器拿到的其实是 Nginx 输出的 HTTP 地址。为什么不在 Java 代码里直接做切片切片涉及磁盘写入、缓存控制、时序管理用 Java 实现成本高稳定性也比不上成熟的流媒体进程。一个课程设计级别的直播系统把媒体面交给 SRSJava 只写业务接口这是最合理的边界划分。链路环节使用的协议对应配置推流入场RTMPSRS listen 1935视频切片HLSsrs.http.hls.conf 的 hls 段文件输出HTTP 静态nginx.live.conf 的 location浏览器播放HLSm3u8 ts3.2 srs.http.hls.conf 的 HLS 参数决定延迟和磁盘占用SRS 配置语法接近 nginx 风格核心是 vhost 下的 hls 段。这套源码对应的典型写法如下listen 1935; max_connections 1000; daemon off; srs_log_tank console; http_server { enabled on; listen 8080; dir ./objs/nginx/html; } vhost __defaultVhost__ { hls { enabled on; hls_path ./objs/nginx/html; hls_fragment 4; hls_window 30; hls_cleanup on; } }listen 1935是 RTMP 推流入口ffmpeg 或 OBS 推流时连接这个端口。http_server段把./objs/nginx/html目录暴露成静态文件服务m3u8 和 ts 都落在这个目录。hls_path必须与 Nginx 的 alias 指向同一个目录否则播放器拿到 m3u8 也读不到 ts 分片。hls_fragment 4表示每 4 秒生成一个 ts 分片数值越小延迟越低但分片文件数量会变多hls_window 30表示播放列表保留最近 30 秒内容hls_cleanup on自动清理过期分片防止演示机器磁盘被写满。注意SRS 的 hls_path 目录必须真实存在否则启动后分片写入失败日志里有报错但进程看起来还在运行。3.3 nginx.live.conf 用静态文件输出避免浏览器跨域nginx.live.conf承担的是播放出口。它把/live/路径直接映射到 SRS 的切片目录不做业务判断下面是常见的静态输出写法server { listen 8088; server_name localhost; location /live/ { types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; } alias /usr/local/srs/objs/nginx/html/live/; add_header Cache-Control no-cache; add_header Access-Control-Allow-Origin *; } }location /live/把所有以/live/开头的请求都收进来。types块让 m3u8 返回application/vnd.apple.mpegurlts 返回video/mp2t这两个 MIME 类型缺失时浏览器会把文件当 text/plain 直接拒播控制台报错往往是媒体加载失败。alias把 URL 前缀映射到磁盘路径注意 alias 与 root 的差异alias 是整段替换末尾路径要和 SRS 的 hls_path 结构一致。Cache-Control no-cache让播放器每次刷新都重新请求 m3u8直播列表才能实时更新。Access-Control-Allow-Origin *是跨域报错的解药页面和播放入口不在同源时必须有这一行。4. DPlayer、Video.js 与 chatMain.css播放页和聊天区怎么组织起来4.1 样式引用顺序和页面骨架前端页面的文件顺序直接决定播放器能否正常渲染。bootstrap.min.css 是基础样式要放最前面video-js.min.css 和 DPlayer.min.css 是播放器组件样式排在 bootstrap 之后chatMain.css、user-right.css、loginStyle.css 属于业务页面样式放最后负责覆盖细节。如果一个页面同时出现 DPlayer 和 Video.js只保留其中一套初始化逻辑两套播放器同时初始化会争抢同一个 video 容器。一个典型页面引用片段如下link relstylesheet hrefcss/bootstrap.min.css link relstylesheet hrefcss/video-js.min.css link relstylesheet hrefcss/DPlayer.min.css link relstylesheet hrefcss/chatMain.css link relstylesheet hrefcss/user-right.css script srcjs/DPlayer.min.js/script script srcjs/video.min.js/scriptCSS 放在 head 里JS 放在 body 底部这样播放器脚本执行时 DOM 已经解析完document.getElementById一定能拿到容器。如果脚本写在 head 里需要包裹 DOMContentLoaded 事件否则初始化时容器还不存在播放器会静默失败。4.2 DPlayer 播放 HLS 的实例参数DPlayer 内置 HLS 解析能力直接把 m3u8 地址交给 video 配置即可。下面是播放器初始化代码const dp new DPlayer({ container: document.getElementById(livePlayer), autoplay: false, preload: auto, theme: #ff5f33, video: { url: http://localhost:8088/live/live.m3u8, type: hls } });container指定播放器挂载到哪个 DOM 节点。autoplay设成 false因为浏览器对带声音的自动播放有限制用户没有交互直接 play 会被拦截。preload选 auto让浏览器提前加载视频元数据。video.url就是上一章 Nginx 输出的播放地址type为 hls 时播放器内部通过 MediaSource 模式拉取 m3u8 并读取 ts 分片。如果改成 flv 类型需要额外引入 flv.js。播放器初始化顺利不代表直播链路没隐患建议加一个错误回调dp.on(error, function (err) { console.error(播放错误, err); });回调本身只打印日志真正的价值在于区分两类问题地址 404 优先查 Nginx 的 alias 路径是否和 SRS 的 hls_path 一致跨域报错查 Access-Control-Allow-Origin 头是否存在。浏览器控制台的错误信息比画面黑屏更早暴露问题位置。4.3 chatMain.css 对应的聊天消息渲染chatMain.css 解决的是聊天区布局不是后端消息逻辑通常固定聊天室的位置、高度和滚动行为。对应的结构一般长这样div classchat-main div classchat-head聊天室/div div classchat-body idchatBody/div div classchat-footer input classchat-input idchatInput placeholder说点什么 button classchat-send idchatSend发送/button /div /divchat-main 作为最外层容器撑满父级高度chat-body 设置flex: 1和overflow-y: auto新消息进入时聊天区域独立滚动。chat-footer 固定在聊天区底部输入框占剩余宽度发送按钮固定宽度这是 chatMain.css 里最常见的 flex 布局手段。消息渲染不依赖框架收到数据后向 chat-body 追加一个节点即可function appendChatMessage(msg) { const item document.createElement(div); item.className chat-item; item.innerHTML span classchat-nick msg.nick /span msg.content; document.getElementById(chatBody).appendChild(item); }appendChatMessage只做 DOM 追加不整体重写 chatBody 的 innerHTML避免直播间消息刷屏时页面频繁重排。nick 和 content 分别落在样式类上与 user-right.css 里的用户信息展示互不干扰。播放器与聊天模块的关键参数如下配置项取值作用video.typehls让 DPlayer 按 HLS 协议解析autoplayfalse规避浏览器自动播放限制chat-body overflow-yauto消息多时独立滚动chat-footerflex 布局输入框与发送按钮固定底部5. 验证与演示排错先看切片再看浏览器控制台5.1 用 curl 判断链路通到哪一段启动后不急着开浏览器先用 curl 确定性验证。播放地址走 Nginx 的 8088就请求 m3u8能看到分片列表说明 SRS 在切、Nginx 也在正常输出文件。curl -s http://127.0.0.1:8088/live/live.m3u8 curl -s http://127.0.0.1:1985/api/v1/streams第一条命令期望看到以#EXTM3U开头、后续跟着 ts 文件名的内容。如果返回 404去 SRS 的./objs/nginx/html/live目录下看文件是否存在文件存在但 404问题就在 Nginx 的 alias 路径。第二条命令请求 SRS 的 HTTP API返回结果里能看到 live 流说明推流端和 SRS 的连接还活着。这两条命令分别覆盖“切片是否生成”和“推流是否在线”哪一步失败就把排查范围缩到对应进程。5.2 三个演示现场最高频的翻车点第一是端口冲突。SRS 内置 HTTP 服务和 Spring Boot 都默认监听 8080后启动的进程会报 bind failed。建议按第二章的表格提前分配端口在后端启动命令里显式写--server.port8081。第二是 MIME 类型缺失。播放器拿到 m3u8 却报 MEDIA_ERR_SRC_NOT_SUPPORTED多半是 Nginx 没配置 m3u8 和 ts 的 types。把application/vnd.apple.mpegurl m3u8和video/mp2t ts加上后重启 Nginx 即可解决。第三是 m3u8 缓存导致直播画面卡住。Nginx 默认对静态文件启用缓存直播播放列表更新不及时画面会停在十几秒前。更精细的做法是把 m3u8 和 ts 分开处理location ~* \.m3u8$ { add_header Cache-Control no-cache; } location ~* \.ts$ { add_header Cache-Control max-age30; }m3u8 每次请求都回到服务器拿最新播放列表ts 分片因为是已生成的静态文件缓存 30 秒不会造成明显延迟同时减少重复请求量。这个区分让直播进度更新及时已切片文件的缓存能力也保留下来。演示现场最容易被忽略的是推流源本身。答辩时如果用 ffmpeg 推一个循环视频文件读完后画面会停在最后一帧。提前用循环参数推流并把推流命令、后端启动、curl 检查顺序在终端里按序跑一遍能省掉现场一半以上的调试时间。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。