偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

別只會(huì)聊天室!用 Spring Boot 3 玩出酷炫實(shí)時(shí)彈幕特效

開發(fā) 項(xiàng)目管理
通過本項(xiàng)目,我們以 Spring Boot 3 為核心技術(shù)棧,構(gòu)建了支持 WebSocket 實(shí)時(shí)通信的彈幕系統(tǒng)。該系統(tǒng)架構(gòu)清晰、可擴(kuò)展性強(qiáng),適用于視頻平臺(tái)、直播系統(tǒng)、虛擬課堂等多種場(chǎng)景。

在當(dāng)今的視頻平臺(tái)和直播場(chǎng)景中,彈幕技術(shù)成為提升用戶參與度與互動(dòng)體驗(yàn)的關(guān)鍵工具。彈幕通過實(shí)時(shí)渲染觀眾評(píng)論在視頻播放界面中橫向滾動(dòng)顯示,不僅增強(qiáng)了沉浸感,也營(yíng)造了社區(qū)式觀影氛圍。本文將基于 Spring Boot 3 構(gòu)建一個(gè)具備實(shí)時(shí)通信、內(nèi)容過濾與歷史記錄能力的彈幕系統(tǒng)。

系統(tǒng)功能概覽

功能定義

彈幕系統(tǒng)允許用戶將文字信息實(shí)時(shí)發(fā)送至正在播放的視頻畫面中。內(nèi)容通常在視頻上層以從右至左方式動(dòng)態(tài)滾動(dòng),呈現(xiàn)同步評(píng)論的視覺效果。

主要特征

  • 低延遲推送用戶評(píng)論可在毫秒級(jí)別廣播至所有連接終端;
  • 強(qiáng)交互性評(píng)論即時(shí)可見,營(yíng)造出“陪伴觀影”的社交感;
  • 內(nèi)容時(shí)間綁定彈幕多與視頻時(shí)間點(diǎn)匹配,有助于信息歸檔與回放分析;
  • 視覺層沖擊批量彈幕可呈現(xiàn)獨(dú)特動(dòng)態(tài)視覺表現(xiàn)。

技術(shù)架構(gòu)設(shè)計(jì)

系統(tǒng)構(gòu)成

系統(tǒng)由以下核心模塊組成:

  • 前端播放器負(fù)責(zé)視頻呈現(xiàn)與彈幕展示;
  • WebSocket 推送引擎實(shí)現(xiàn)低延遲的實(shí)時(shí)消息廣播;
  • 持久化存儲(chǔ)模塊記錄用戶彈幕數(shù)據(jù),支持回放及分析;
  • 內(nèi)容審查組件確保發(fā)送信息符合平臺(tái)規(guī)范。

協(xié)議選型分析

在實(shí)時(shí)推送技術(shù)方案中,以下協(xié)議可供選擇:

協(xié)議

優(yōu)點(diǎn)

局限性

推薦場(chǎng)景

WebSocket

全雙工、低延遲、兼容廣

需維持長(zhǎng)連接,資源占用較高

高實(shí)時(shí)性場(chǎng)景,如彈幕直播

SSE

實(shí)現(xiàn)簡(jiǎn)單,適合單向推送

僅支持服務(wù)器向客戶端

新聞推送、股票刷新

Long Polling

通用性強(qiáng)

實(shí)時(shí)性差,耗資源

極端兼容場(chǎng)景或降級(jí)備選方案

本項(xiàng)目采用 WebSocket 作為通信協(xié)議以實(shí)現(xiàn)毫秒級(jí)互動(dòng)體驗(yàn)。

后端實(shí)現(xiàn)詳解(Spring Boot 3)

引入依賴(pom.xml)

<groupId>com.icoderoad</groupId>
<artifactId>danmaku-system</artifactId>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
        <version>3.5.5</version>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

WebSocket 配置

路徑: /src/main/java/com/icoderoad/danmaku/config/WebSocketConfig.java

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic");
        registry.setApplicationDestinationPrefixes("/app");
    }


    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws-danmaku").setAllowedOriginPatterns("*").withSockJS();
    }
}

彈幕實(shí)體模型

路徑: /src/main/java/com/icoderoad/danmaku/model/Danmaku.java

@Data
@TableName("danmaku")
public class Danmaku {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String content;
    private String color;
    private Integer fontSize;
    private Double time;
    private String videoId;
    private String userId;
    private String username;
    private LocalDateTime createdAt;
}

數(shù)據(jù)傳輸結(jié)構(gòu)(DTO)

路徑: /src/main/java/com/icoderoad/danmaku/dto/DanmakuDTO.java

@Data
public class DanmakuDTO {
    private String content;
    private String color = "#ffffff";
    private Integer fontSize = 24;
    private Double time;
    private String videoId;
    private String userId;
    private String username;
}

Mapper 接口

路徑: /src/main/java/com/icoderoad/danmaku/mapper/DanmakuMapper.java

@Mapper
public interface DanmakuMapper extends BaseMapper<Danmaku> {
    @Select("SELECT * FROM danmaku WHERE video_id = #{videoId} ORDER BY time ASC")
    List<Danmaku> findByVideoIdOrderByTimeAsc(@Param("videoId") String videoId);


    @Select("SELECT * FROM danmaku WHERE video_id = #{videoId} AND time BETWEEN #{startTime} AND #{endTime} ORDER BY time ASC")
    List<Danmaku> findByVideoIdAndTimeBetween(@Param("videoId") String videoId, @Param("startTime") Double start, @Param("endTime") Double end);
}

服務(wù)邏輯

路徑: /src/main/java/com/icoderoad/danmaku/service/DanmakuService.java

@Service
public class DanmakuService {
    @Autowired private DanmakuMapper danmakuMapper;
    @Autowired private SimpMessagingTemplate messagingTemplate;


    public Danmaku saveDanmaku(DanmakuDTO dto) {
        String clean = filterContent(dto.getContent());


        Danmaku danmaku = new Danmaku();
        danmaku.setContent(clean);
        danmaku.setColor(dto.getColor());
        danmaku.setFontSize(dto.getFontSize());
        danmaku.setTime(dto.getTime());
        danmaku.setVideoId(dto.getVideoId());
        danmaku.setUserId(dto.getUserId());
        danmaku.setUsername(dto.getUsername());
        danmaku.setCreatedAt(LocalDateTime.now());


        danmakuMapper.insert(danmaku);
        messagingTemplate.convertAndSend("/topic/video/" + dto.getVideoId(), danmaku);
        return danmaku;
    }


    public List<Danmaku> getDanmakusByVideoId(String videoId) {
        return danmakuMapper.findByVideoIdOrderByTimeAsc(videoId);
    }


    public List<Danmaku> getDanmakusByTimeRange(String videoId, Double start, Double end) {
        return danmakuMapper.findByVideoIdAndTimeBetween(videoId, start, end);
    }


    private String filterContent(String content) {
        String[] blocklist = {"敏感詞1", "敏感詞2"};
        for (String word : blocklist) {
            content = content.replaceAll(word, "***");
        }
        return content;
    }
}

控制器接口

路徑: /src/main/java/com/icoderoad/danmaku/controller/DanmakuController.java

@RestController
@RequestMapping("/api/danmaku")
public class DanmakuController {
    @Autowired private DanmakuService service;


    @MessageMapping("/danmaku/send")
    public Danmaku push(DanmakuDTO dto) {
        return service.saveDanmaku(dto);
    }


    @GetMapping("/video/{videoId}")
    public ResponseEntity<List<Danmaku>> list(@PathVariable String videoId) {
        return ResponseEntity.ok(service.getDanmakusByVideoId(videoId));
    }


    @GetMapping("/video/{videoId}/timerange")
    public ResponseEntity<List<Danmaku>> range(@PathVariable String videoId,
                                               @RequestParam Double start,
                                               @RequestParam Double end) {
        return ResponseEntity.ok(service.getDanmakusByTimeRange(videoId, start, end));
    }
}

Thymeleaf + Bootstrap 優(yōu)化版前端頁面示例

將頁面放置于 /src/main/resources/templates/danmaku.html,供 Thymeleaf 渲染

<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>實(shí)時(shí)彈幕播放器</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">


    <!-- Bootstrap 5 樣式 -->
    <link  rel="stylesheet">


    <style>
        #video-container {
            position: relative;
            width: 100%;
            max-width: 900px;
            margin: auto;
        }


        video {
            width: 100%;
            height: auto;
        }


        #danmaku-layer {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
        }


        .danmaku {
            position: absolute;
            white-space: nowrap;
            font-weight: bold;
            animation: danmaku-move 8s linear forwards;
        }


        @keyframes danmaku-move {
            0% {
                transform: translateX(100%);
            }
            100% {
                transform: translateX(-100%);
            }
        }
    </style>
</head>


<body>
<div class="container py-4">
    <h2 class="text-center mb-4">?? 實(shí)時(shí)彈幕播放器</h2>


    <div id="video-container" class="mb-3">
        <video id="video" controls th:src="@{/videos/sample.mp4}"></video>
        <div id="danmaku-layer"></div>
    </div>


    <!-- 彈幕輸入?yún)^(qū) -->
    <form id="danmaku-form" class="row g-2 align-items-center justify-content-center">
        <div class="col-md-4">
            <input type="text" class="form-control" id="danmaku-content" placeholder="輸入你的彈幕..." required>
        </div>
        <div class="col-md-2">
            <input type="color" class="form-control form-control-color" id="danmaku-color" value="#ffffff" title="選擇顏色">
        </div>
        <div class="col-md-2">
            <input type="number" class="form-control" id="danmaku-size" value="24" min="12" max="48" title="字體大小">
        </div>
        <div class="col-md-2">
            <button type="submit" class="btn btn-primary w-100">發(fā)送彈幕</button>
        </div>
    </form>
</div>


<!-- SockJS + STOMP -->
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1.6.1/dist/sockjs.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/stompjs@2.3.3/lib/stomp.min.js"></script>


<script>
    const video = document.getElementById("video");
    const danmakuLayer = document.getElementById("danmaku-layer");


    const stompClient = Stomp.over(new SockJS("/ws-danmaku"));
    stompClient.connect({}, function () {
        stompClient.subscribe("/topic/video/demo", function (message) {
            const danmaku = JSON.parse(message.body);
            renderDanmaku(danmaku);
        });
    });


    document.getElementById("danmaku-form").addEventListener("submit", function (e) {
        e.preventDefault();
        const content = document.getElementById("danmaku-content").value.trim();
        const color = document.getElementById("danmaku-color").value;
        const fontSize = parseInt(document.getElementById("danmaku-size").value) || 24;


        if (!content) return;


        const danmaku = {
            content: content,
            color: color,
            fontSize: fontSize,
            time: video.currentTime,
            videoId: "demo",
            userId: "user123",
            username: "訪客"
        };


        stompClient.send("/app/danmaku/send", {}, JSON.stringify(danmaku));
        document.getElementById("danmaku-form").reset();
    });


    function renderDanmaku(d) {
        const span = document.createElement("span");
        span.className = "danmaku";
        span.textContent = d.content;
        span.style.color = d.color || "#fff";
        span.style.fontSize = (d.fontSize || 24) + "px";
        span.style.top = Math.random() * 80 + "%";
        danmakuLayer.appendChild(span);


        // 清理彈幕
        setTimeout(() => danmakuLayer.removeChild(span), 8000);
    }
</script>


</body>
</html>

結(jié)合 STOMP 協(xié)議與 SockJS 客戶端即可建立彈幕推送通道。

結(jié)語

通過本項(xiàng)目,我們以 Spring Boot 3 為核心技術(shù)棧,構(gòu)建了支持 WebSocket 實(shí)時(shí)通信的彈幕系統(tǒng)。該系統(tǒng)架構(gòu)清晰、可擴(kuò)展性強(qiáng),適用于視頻平臺(tái)、直播系統(tǒng)、虛擬課堂等多種場(chǎng)景。未來可進(jìn)一步擴(kuò)展彈幕審核、用戶等級(jí)體系、彈幕樣式個(gè)性化等高級(jí)功能,以構(gòu)建更加豐富的互動(dòng)體驗(yàn)。

責(zé)任編輯:武曉燕 來源: 路條編程
相關(guān)推薦

2022-07-26 14:53:10

WebSocket網(wǎng)絡(luò)通信協(xié)議

2011-12-15 11:11:51

JavaNIO

2023-02-10 08:16:48

WebSocket簡(jiǎn)易聊天室

2025-05-28 03:00:00

2011-06-09 15:44:29

Spring

2022-11-14 08:01:48

2015-01-19 17:44:02

Cocos引擎3D特效

2015-07-06 10:42:18

PHP聊天室應(yīng)用

2021-11-16 09:38:10

鴻蒙HarmonyOS應(yīng)用

2023-01-05 09:17:58

2023-01-13 00:02:41

2025-05-09 08:35:00

聊天室FastAPIWebSocket

2024-01-09 08:07:09

JSThreeJSCSS

2022-12-01 08:25:23

eTsTCP聊天室

2013-11-27 10:46:31

JavaEEWebsockets

2020-10-10 06:25:36

日志原理搜索

2021-10-14 18:46:29

Websocket瀏覽器API

2015-08-06 17:17:33

swoole聊天室

2022-12-22 08:57:29

Redis數(shù)據(jù)存儲(chǔ)

2019-07-23 11:20:16

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)