十分鐘搞定!用 Spring Boot 搭建屬于你的輕量直播平臺(tái)
直播技術(shù)正以前所未有的速度席卷各行各業(yè)。從社交媒體平臺(tái)到在線教育、電子商務(wù)甚至游戲社區(qū),直播系統(tǒng)已成為增強(qiáng)用戶互動(dòng)、傳遞實(shí)時(shí)信息的關(guān)鍵工具。本文將基于 Spring Boot 框架,構(gòu)建一個(gè)具備推流、拉流、互動(dòng)功能的輕量直播平臺(tái)。
一、直播技術(shù)基礎(chǔ)
1.1 推流與拉流的基本概念
- 推流(Push):主播通過攝像頭采集音視頻內(nèi)容,編碼后推送至流媒體服務(wù)器。
- 拉流(Pull):觀眾端從流媒體服務(wù)器獲取直播流并進(jìn)行解碼播放。
1.2 常見直播協(xié)議對(duì)比
協(xié)議 | 優(yōu)勢(shì) | 劣勢(shì) | 典型場(chǎng)景 |
RTMP | 延遲低(1-3s)、技術(shù)成熟 | 基于 Flash、需開放 1935 端口 | 推流、低延遲直播 |
HLS | 使用 HTTP,兼容性好 | 延遲高(10s+) | 大規(guī)模分發(fā)、移動(dòng)端播放 |
WebRTC | 超低延遲(<1s)、P2P 通信 | 網(wǎng)絡(luò)穿透難、部署復(fù)雜 | 實(shí)時(shí)互動(dòng)、在線會(huì)議 |
HTTP-FLV | 延遲低、支持瀏覽器播放 | 不支持可變碼率 | 視頻門戶、低延遲場(chǎng)景 |
SRT | 高可靠性、低延遲 | 部署稍復(fù)雜,生態(tài)相對(duì)年輕 | 專業(yè)直播、跨國(guó)推流 |
1.3 直播系統(tǒng)架構(gòu)組成
一個(gè)典型直播系統(tǒng)包括:
- 采集端:攝像頭/OBS等,用于采集視頻音頻流。
- 流媒體服務(wù)器:用于接收推流并分發(fā)(如 SRS)。
- CDN 分發(fā)層:大規(guī)模分發(fā)直播內(nèi)容。
- 播放器:觀眾端使用 flv.js、hls.js 等播放流。
- 信令服務(wù):管理用戶、直播間狀態(tài)、聊天等。
二、系統(tǒng)技術(shù)架構(gòu)與選型
2.1 核心系統(tǒng)結(jié)構(gòu)
采用模塊化分層方式設(shè)計(jì):
- API 服務(wù)層:基于 Spring Boot 構(gòu)建 REST 接口,處理房間創(chuàng)建、用戶信息等。
- 媒體服務(wù)層:通過 Docker 部署 SRS,接入 RTMP 推流、HTTP-FLV 拉流。
- 實(shí)時(shí)互動(dòng)層:使用 WebSocket 進(jìn)行直播間聊天室通信。
- 存儲(chǔ)層:使用 MinIO 對(duì)象存儲(chǔ)錄制回放內(nèi)容。
- 前端播放器:使用 flv.js 播放直播流。
2.2 技術(shù)棧選型
模塊 | 技術(shù) |
Web 框架 | Spring Boot 3 |
數(shù)據(jù)庫(kù) | MySQL + Redis |
流媒體服務(wù) | SRS (Simple RTMP Server) |
消息通信 | Spring WebSocket |
對(duì)象存儲(chǔ) | MinIO |
前端播放器 | flv.js、Bootstrap、Thymeleaf |
三、基于 Spring Boot 實(shí)現(xiàn)直播服務(wù)
3.1 直播間管理模塊(REST API)
實(shí)體類:LiveRoom
@Entity
@Table(name = "live_room")
public class LiveRoom {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String roomId;
private String title;
private String streamer;
private String pushUrl;
private String pullUrl;
}Repository 接口
public interface LiveRoomRepository extends JpaRepository<LiveRoom, Long> {
Optional<LiveRoom> findByRoomId(String roomId);
}控制器接口
@RestController
@RequestMapping("/api/room")
public class LiveRoomController {
@Autowired
private LiveRoomRepository roomRepo;
@PostMapping("/create")
public ResponseEntity<?> createRoom(@RequestBody Map<String, String> payload) {
String roomId = UUID.randomUUID().toString();
String title = payload.get("title");
String streamer = payload.get("streamer");
LiveRoom room = new LiveRoom();
room.setRoomId(roomId);
room.setTitle(title);
room.setStreamer(streamer);
room.setPushUrl("rtmp://localhost:1935/live/" + roomId);
room.setPullUrl("http://localhost:8080/live/" + roomId + ".flv");
return ResponseEntity.ok(roomRepo.save(room));
}
@GetMapping("/{roomId}")
public ResponseEntity<?> getRoom(@PathVariable String roomId) {
return roomRepo.findByRoomId(roomId)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
}3.2 推流與拉流服務(wù)(SRS接入)
通過 Docker 部署 SRS:
docker run -d --name srs \
-p 1935:1935 -p 1985:1985 -p 8080:8080 \
ossrs/srs:5推流地址:rtmp://localhost:1935/live/{roomId} 拉流地址:http://localhost:8080/live/{roomId}.flv
使用 OBS 配置推流即可。
3.3 WebSocket 聊天服務(wù)
聊天處理器
@ServerEndpoint("/ws/chat/{roomId}")
@Component
public class ChatWebSocket {
private static Map<String, Set<Session>> roomSessions = new ConcurrentHashMap<>();
@OnOpen
public void onOpen(Session session, @PathParam("roomId") String roomId) {
roomSessions.computeIfAbsent(roomId, k -> ConcurrentHashMap.newKeySet()).add(session);
}
@OnMessage
public void onMessage(String message, @PathParam("roomId") String roomId) {
for (Session s : roomSessions.getOrDefault(roomId, Collections.emptySet())) {
s.getAsyncRemote().sendText(message);
}
}
@OnClose
public void onClose(Session session, @PathParam("roomId") String roomId) {
roomSessions.getOrDefault(roomId, Collections.emptySet()).remove(session);
}
}WebSocket 配置
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}3.4 前端直播播放頁(yè)面(Thymeleaf + flv.js)
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>直播間</title>
<script src="https://cdn.jsdelivr.net/npm/flv.js@1.6.2/dist/flv.min.js"></script>
<link rel="stylesheet" />
</head>
<body class="p-4">
<div class="container">
<h2>歡迎來到直播間:<span id="title"></span></h2>
<video id="liveVideo" class="w-100" controls></video>
<div class="mt-3">
<input type="text" id="chatInput" class="form-control" placeholder="輸入消息..." />
<button class="btn btn-primary mt-2" onclick="sendMessage()">發(fā)送</button>
</div>
<div class="mt-3">
<h5>聊天記錄</h5>
<div id="chatBox" class="border p-2" style="height: 200px; overflow-y: scroll;"></div>
</div>
</div>
<script>
const roomId = new URLSearchParams(window.location.search).get("roomId");
const videoUrl = "http://localhost:8080/live/" + roomId + ".flv";
const ws = new WebSocket("ws://localhost:8080/ws/chat/" + roomId);
if (flvjs.isSupported()) {
const player = flvjs.createPlayer({type: 'flv', url: videoUrl});
player.attachMediaElement(document.getElementById('liveVideo'));
player.load();
player.play();
}
ws.onmessage = function (event) {
const chatBox = document.getElementById("chatBox");
chatBox.innerHTML += `<div>${event.data}</div>`;
chatBox.scrollTop = chatBox.scrollHeight;
};
function sendMessage() {
const input = document.getElementById("chatInput");
if (input.value) {
ws.send(input.value);
input.value = "";
}
}
fetch("/api/room/" + roomId).then(res => res.json()).then(data => {
document.getElementById("title").innerText = data.title;
});
</script>
</body>
</html>結(jié)語(yǔ)
通過本文的實(shí)戰(zhàn)內(nèi)容,我們使用 Spring Boot 框架,集成 SRS 流媒體服務(wù)器和 WebSocket 技術(shù),實(shí)現(xiàn)了一個(gè)從直播間創(chuàng)建、推流、拉流到聊天互動(dòng)的輕量級(jí)直播平臺(tái)。該系統(tǒng)適合用于中小型直播場(chǎng)景或企業(yè)自建內(nèi)部直播系統(tǒng),未來可進(jìn)一步擴(kuò)展如直播錄制、轉(zhuǎn)碼、多路直播、分布式架構(gòu)等功能。

































