最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring Boot中使用Server-Sent Events (SSE) 實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)推送教程

 更新時(shí)間:2024年03月29日 09:12:21   作者:冬山兄  
Server-Sent Events (SSE) 是HTML5引入的一種輕量級(jí)的服務(wù)器向?yàn)g覽器客戶端單向推送實(shí)時(shí)數(shù)據(jù)的技術(shù),本文主要介紹了Spring Boot中使用Server-Sent Events (SSE) 實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)推送教程,具有一定的參考價(jià)值,感興趣的可以了解一下

一、簡(jiǎn)介

Server-Sent Events (SSE) 是HTML5引入的一種輕量級(jí)的服務(wù)器向?yàn)g覽器客戶端單向推送實(shí)時(shí)數(shù)據(jù)的技術(shù)。在Spring Boot框架中,我們可以很容易地集成并利用SSE來(lái)實(shí)現(xiàn)實(shí)時(shí)通信。

二、依賴(lài)添加

在Spring Boot項(xiàng)目中,無(wú)需額外引入特定的依賴(lài),因?yàn)镾pring Web MVC模塊已經(jīng)內(nèi)置了對(duì)SSE的支持。

輔助Maven

        <!-- 集成beetl -->
        <dependency>
            <groupId>com.ibeetl</groupId>
            <artifactId>beetl-framework-starter</artifactId>
            <version>1.2.30.RELEASE</version>
        </dependency>

        <!-- 集成hutool工具類(lèi)簡(jiǎn)便操作 -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.10</version>
        </dependency>

三、編寫(xiě)核心SSE Client

@Slf4j
@Component
public class SseClient {
    private static final Map<String, SseEmitter> sseEmitterMap = new ConcurrentHashMap<>();
    /**
     * 創(chuàng)建連接
     */
    public SseEmitter createSse(String uid) {
        //默認(rèn)30秒超時(shí),設(shè)置為0L則永不超時(shí)
        SseEmitter sseEmitter = new SseEmitter(0l);
        //完成后回調(diào)
        sseEmitter.onCompletion(() -> {
            log.info("[{}]結(jié)束連接...................", uid);
            sseEmitterMap.remove(uid);
        });
        //超時(shí)回調(diào)
        sseEmitter.onTimeout(() -> {
            log.info("[{}]連接超時(shí)...................", uid);
        });
        //異?;卣{(diào)
        sseEmitter.onError(
                throwable -> {
                    try {
                        log.info("[{}]連接異常,{}", uid, throwable.toString());
                        sseEmitter.send(SseEmitter.event()
                                .id(uid)
                                .name("發(fā)生異常!")
                                .data("發(fā)生異常請(qǐng)重試!")
                                .reconnectTime(3000));
                        sseEmitterMap.put(uid, sseEmitter);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
        );
        try {
            sseEmitter.send(SseEmitter.event().reconnectTime(5000));
        } catch (IOException e) {
            e.printStackTrace();
        }
        sseEmitterMap.put(uid, sseEmitter);
        log.info("[{}]創(chuàng)建sse連接成功!", uid);
        return sseEmitter;
    }

    /**
     * 給指定用戶發(fā)送消息
     *
     */
    public boolean sendMessage(String uid,String messageId, String message) {
        if (StrUtil.isBlank(message)) {
            log.info("參數(shù)異常,msg為null", uid);
            return false;
        }
        SseEmitter sseEmitter = sseEmitterMap.get(uid);
        if (sseEmitter == null) {
            log.info("消息推送失敗uid:[{}],沒(méi)有創(chuàng)建連接,請(qǐng)重試。", uid);
            return false;
        }
        try {
            sseEmitter.send(SseEmitter.event().id(messageId).reconnectTime(1*60*1000L).data(message));
            log.info("用戶{},消息id:{},推送成功:{}", uid,messageId, message);
            return true;
        }catch (Exception e) {
            sseEmitterMap.remove(uid);
            log.info("用戶{},消息id:{},推送異常:{}", uid,messageId, e.getMessage());
            sseEmitter.complete();
            return false;
        }
    }

    /**
     * 斷開(kāi)
     * @param uid
     */
    public void closeSse(String uid){
        if (sseEmitterMap.containsKey(uid)) {
            SseEmitter sseEmitter = sseEmitterMap.get(uid);
            sseEmitter.complete();
            sseEmitterMap.remove(uid);
        }else {
            log.info("用戶{} 連接已關(guān)閉",uid);
        }

    }

}
  • 創(chuàng)建SSE 端點(diǎn):創(chuàng)建一個(gè)SseEmitter,用uid進(jìn)行標(biāo)識(shí),uid可以是用戶標(biāo)識(shí)符,也可以是業(yè)務(wù)標(biāo)識(shí)符??梢岳斫鉃橥ㄐ判诺罉?biāo)識(shí)。
  • 通過(guò)端點(diǎn)發(fā)送事件:可以定時(shí)或在事件發(fā)生時(shí)調(diào)用sseEmitter.send()方法來(lái)發(fā)送事件。
  • 關(guān)閉端點(diǎn)連接

四、編寫(xiě)Controller

@Controller
public class IndexAction {
    @Autowired
    private SseClient sseClient;
    @GetMapping("/")
    public String index(ModelMap model) {
        String uid = IdUtil.fastUUID();
        model.put("uid",uid);
        return "index";
    }

    @CrossOrigin
    @GetMapping("/createSse")
    public SseEmitter createConnect(String uid) {
        return sseClient.createSse(uid);
    }
    @CrossOrigin
    @GetMapping("/sendMsg")
    @ResponseBody
    public String sseChat(String uid) {
        for (int i = 0; i < 10; i++) {
            sseClient.sendMessage(uid, "no"+i,IdUtil.fastUUID());
        }
        return "ok";
    }

    /**
     * 關(guān)閉連接
     */
    @CrossOrigin
    @GetMapping("/closeSse")
    public void closeConnect(String uid ){

        sseClient.closeSse(uid);
    }
}

1,打開(kāi)頁(yè)面默認(rèn)頁(yè)面,傳遞端點(diǎn)標(biāo)識(shí)。

2,連接端點(diǎn)(/createSse),頁(yè)面需要使用

3,通過(guò)ajax(/sendMsg),觸發(fā)后端業(yè)務(wù)(循環(huán)十條數(shù)據(jù)發(fā)往頁(yè)面),向頁(yè)面發(fā)送消息。

4,主動(dòng)關(guān)閉連接(/closeSse)

五、前端接收與處理

HTML & JavaScript

在前端頁(yè)面,使用EventSource API訂閱SSE endpoint:

Html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="con"></div>
<script>
    let chat = document.getElementById("con");
    if (window.EventSource) {
        //創(chuàng)建sse
         eventSource = new EventSource(`/createSse?uid=${uid}`);
        eventSource.onopen = function (event) {
            console.log('SSE鏈接成功');
        }
        eventSource.onmessage = function (event) {
            if(event.data){
                chat.innerHTML += event.data + '<br/>';
                //console.log('后端返回的數(shù)據(jù):', data.value);
            }
        }
        eventSource.onerror = (error) => {
            console.log('SSE鏈接失敗');
        };
    } else {
        alert("你的瀏覽器不支持SSE");
    }
</script>
</body>
</html>

在這個(gè)例子中,前端每接收到一次SSE推送的事件,就會(huì)在id為"con"的元素中追加數(shù)據(jù)。

六、注意事項(xiàng)

  • 當(dāng)客戶端斷開(kāi)連接時(shí),SseEmitter會(huì)拋出IOException,所以務(wù)必捕獲并處理這種異常,通常情況下我們會(huì)調(diào)用emitter.complete()emitter.completeWithError()來(lái)關(guān)閉SseEmitter。
  • SSE連接是持久性的,長(zhǎng)時(shí)間保持連接可能需要處理超時(shí)和重連問(wèn)題。
  • 考慮到資源消耗,對(duì)于大量的并發(fā)客戶端,可能需要采用連接池或者其他優(yōu)化策略。

總結(jié),Spring Boot中利用SSE實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)推送既簡(jiǎn)單又實(shí)用,特別適合實(shí)時(shí)更新頻率不高、實(shí)時(shí)性要求不嚴(yán)苛的場(chǎng)景。同時(shí),在高并發(fā)場(chǎng)景下需要注意資源管理和優(yōu)化策略的選擇。

到此這篇關(guān)于Spring Boot中使用Server-Sent Events (SSE) 實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)推送教程的文章就介紹到這了,更多相關(guān)SpringBoot 實(shí)時(shí)數(shù)據(jù)推送內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Mybatis使用concat函數(shù)問(wèn)題

    Mybatis使用concat函數(shù)問(wèn)題

    這篇文章主要介紹了Mybatis使用concat函數(shù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • POI導(dǎo)出Excel報(bào)錯(cuò)No such file or directory的解決方法

    POI導(dǎo)出Excel報(bào)錯(cuò)No such file or directory的解決方法

    這篇文章主要為大家詳細(xì)介紹了POI導(dǎo)出Excel報(bào)錯(cuò)No such file or directory的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • 如何查看Linux上正在運(yùn)行的所有Java程序列表

    如何查看Linux上正在運(yùn)行的所有Java程序列表

    在linux操作時(shí),經(jīng)常要查看運(yùn)行的項(xiàng)目的進(jìn)程和端口,下面這篇文章主要給大家介紹了關(guān)于如何查看Linux上正在運(yùn)行的所有Java程序列表的相關(guān)資料,需要的朋友可以參考下
    2023-10-10
  • Java利用openoffice將doc、docx轉(zhuǎn)為pdf實(shí)例代碼

    Java利用openoffice將doc、docx轉(zhuǎn)為pdf實(shí)例代碼

    這篇文章主要介紹了Java利用openoffice將doc、docx轉(zhuǎn)為pdf實(shí)例代碼,分享了相關(guān)代碼示例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01
  • 原理分析Java?Mybatis中的Mapper

    原理分析Java?Mybatis中的Mapper

    這篇文章主要為大家介紹了Java?Mybatis中的Mapper,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-01-01
  • 基于Java實(shí)現(xiàn)對(duì)文件進(jìn)行MD5加密

    基于Java實(shí)現(xiàn)對(duì)文件進(jìn)行MD5加密

    MD5(Message-Digest?Algorithm?5)是一種廣泛使用的哈希函數(shù),可以生成一個(gè)128位(16字節(jié))的哈希值,本文將介紹如何使用Java語(yǔ)言實(shí)現(xiàn)對(duì)文件的MD5加密,幫助開(kāi)發(fā)者理解和應(yīng)用這一技術(shù)
    2025-06-06
  • Java行為型設(shè)計(jì)模式之策略模式詳解

    Java行為型設(shè)計(jì)模式之策略模式詳解

    策略模式屬于Java-設(shè)計(jì)模式中行為模式之一,該模式定義了一系列算法,并將每個(gè)算法封裝起來(lái),使它們可以相互替換。本文將通過(guò)示例詳細(xì)講解這一模式,需要的可以參考一下
    2022-11-11
  • idea不自動(dòng)生成target問(wèn)題及解決

    idea不自動(dòng)生成target問(wèn)題及解決

    文章講述了在使用IDEA開(kāi)發(fā)Maven項(xiàng)目時(shí)遇到的常見(jiàn)問(wèn)題及其解決方法,主要包括項(xiàng)目導(dǎo)入問(wèn)題、資源文件未打包問(wèn)題以及清理緩存的技巧
    2026-03-03
  • SpringBoot中創(chuàng)建的AOP不生效的原因及解決

    SpringBoot中創(chuàng)建的AOP不生效的原因及解決

    這篇文章主要介紹了SpringBoot中創(chuàng)建的AOP不生效的原因及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • JDK版本修改不生效的解決方法

    JDK版本修改不生效的解決方法

    本文主要介紹了在配置新電腦環(huán)境時(shí)遇到JDK版本切換失敗的問(wèn)題,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2025-03-03

最新評(píng)論

巴彦淖尔市| 昌图县| 华容县| 体育| 镇坪县| 文安县| 株洲县| 博白县| 孟村| 江北区| 织金县| 喀什市| 鄯善县| 瓦房店市| 潮安县| 琼海市| 诏安县| 怀仁县| 湟源县| 弥渡县| 常德市| 嘉祥县| 芮城县| 噶尔县| 榆林市| 宜兴市| 金秀| 宜章县| 南开区| 武胜县| 淄博市| 苗栗市| 柳江县| 治多县| 海盐县| 汶川县| 铁力市| 龙州县| 会宁县| 华容县| 水城县|