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

springboot整合SSE的項目實踐

 更新時間:2023年09月15日 15:29:51   作者:普通還不自信的程序員  
SSE是一種可以主動從服務(wù)端推送消息的技術(shù),本文主要介紹了springboot整合SSE的項目實踐,具有一定的參考價值,感興趣的可以了解一下

SSE簡介

SSE(Server Sent Event),是一種可以主動從服務(wù)端推送消息的技術(shù)。SSE的本質(zhì)其實就是一個HTTP的長連接,只不過它給客戶端發(fā)送的不是一次性的數(shù)據(jù)包,而是一個stream流,格式為text/event-stream。所以客戶端不會關(guān)閉連接,會一直等著服務(wù)器發(fā)過來的新的數(shù)據(jù)流。

SSE服務(wù)端代碼

springboot中封裝了sse代碼,不需要額外的依賴

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
public class SseEmitterServer {
    private static final Logger LOGGER = LoggerFactory.getLogger(SseEmitterServer.class);
    /**
     * 當前連接數(shù)
     */
    private static AtomicInteger count = new AtomicInteger(0);
    private static Map<Integer, SseEmitter> sseEmitterMap = new ConcurrentHashMap<>();
    public static SseEmitter connect(Integer userId){
        // 設(shè)置超時日期,0表示不過期
        SseEmitter sseEmitter = new SseEmitter(0L);
        // 注冊回調(diào)
        sseEmitter.onCompletion(completionCallBack(userId));
        sseEmitter.onError(errorCallBack(userId));
        sseEmitter.onTimeout(timeoutCallBack(userId));
        sseEmitterMap.put(userId,sseEmitter);
        count.getAndIncrement();
        LOGGER.info("創(chuàng)建新SSE連接,連接用戶編號:{}",userId);
        LOGGER.info("現(xiàn)有連接用戶:"+sseEmitterMap.keySet());
        return sseEmitter;
    }
    /**
     * 給指定用戶發(fā)信息
     */
    public static void sendMessage(Integer userId,String message){
        if (!sseEmitterMap.containsKey(userId)) {
            connect(userId);
        }
        try {
            sseEmitterMap.get(userId).send(message);
            LOGGER.info("給" + userId + "號發(fā)送消息:" + message);
        } catch (IOException e) {
            LOGGER.error("userId:{},發(fā)送信息出錯:{}", userId, e.getMessage());
            e.printStackTrace();
        }
    }
    /**
     * 群發(fā)消息
     */
    public static void batchSendMessage(String message){
        if (sseEmitterMap != null&&!sseEmitterMap.isEmpty()) {
            sseEmitterMap.forEach((k,v)->{
                try {
                    v.send(message, MediaType.APPLICATION_JSON);
                } catch (IOException e) {
                    LOGGER.error("userId:{},發(fā)送信息出錯:{}",k,e.getMessage());
                    e.printStackTrace();
                }
            });
        }
    }
    public static void batchSendMessage(Set<Integer> userIds,String message){
        userIds.forEach(userId->sendMessage(userId,message));
    }
    /**
     * 移出用戶
     */
    public static void removeUser(Integer userId){
        sseEmitterMap.remove(userId);
        count.getAndDecrement();
        LOGGER.info("remove user id:{}",userId);
        LOGGER.info("remain user id:"+sseEmitterMap.keySet());
    }
    public static List<Integer> getIds(){
        return new ArrayList<>(sseEmitterMap.keySet());
    }
    public static int getUserCount(){
        return count.intValue();
    }
    private static Runnable completionCallBack(Integer userId){
        return ()->{
          LOGGER.info("結(jié)束連接,{}",userId);
          removeUser(userId);
        };
    }
    private static Runnable timeoutCallBack(Integer userId){
        return ()->{
            LOGGER.info("連接超時,{}",userId);
            removeUser(userId);
        };
    }
    private static Consumer<Throwable> errorCallBack(Integer userId){
        return throwable -> {
            LOGGER.error("連接異常,{}",userId);
            removeUser(userId);
        };
    }
}
@RestController
@CrossOrigin(maxAge = 3600)
public class SseController {
    @RequestMapping(value = "/sse/connect/{id}",method = RequestMethod.GET)
    public SseEmitter connect(@PathVariable Integer id){
        SseEmitter sseEmitter = SseEmitterServer.connect(id);
        return sseEmitter;
    }
    /**
     * 向指定用戶發(fā)送消息
     */
    @RequestMapping(value = "/sse/send/{id}", method = RequestMethod.GET)
    public EiInfo sendMsg(@PathVariable Integer id,@RequestParam("message") String message) {
        EiInfo eiInfo = new EiInfo();
        SseEmitterServer.sendMessage(id,message);
        eiInfo.sysSetMsg("向"+id+"號用戶發(fā)送信息,"+message+",消息發(fā)送成功");
        return eiInfo;
    }
    /**
     * 向所有用戶發(fā)送消息
     */
    @RequestMapping(value = "/sse/send/all", method = RequestMethod.GET)
    public EiInfo sendMsg2AllUser(@RequestParam("message") String message) {
        EiInfo eiInfo = new EiInfo();
        SseEmitterServer.batchSendMessage(message);
        eiInfo.sysSetMsg("向所有用戶發(fā)送信息,"+message+",消息發(fā)送成功");
        return eiInfo;
    }
    /**
     * 關(guān)閉用戶連接
     */
    @RequestMapping(value = "/sse/close/{id}", method = RequestMethod.GET)
    public EiInfo closeSse(@PathVariable Integer id) {
        EiInfo eiInfo = new EiInfo();
        SseEmitterServer.removeUser(id);
        eiInfo.sysSetMsg("關(guān)閉"+id+"號連接。當前連接用戶有:"+SseEmitterServer.getIds());
        return eiInfo;
    }
}

SSE測試

連接服務(wù)端

創(chuàng)建三個用戶,分別連接服務(wù)端

給指定用戶發(fā)送消息

使用接口測試工具,只給1號用戶發(fā)送消息

瀏覽器中,1號用戶接收到消息,2號3號未接收到消息

群發(fā)消息

關(guān)閉連接

當SSE客戶端連接后,如果長時間不斷開,它會保持連接狀態(tài)。SSE(Server-Sent Events)是一種基于HTTP的推送技術(shù),允許服務(wù)器實時向客戶端發(fā)送數(shù)據(jù)。當客戶端連接到服務(wù)器的SSE端點時,它會創(chuàng)建一個EventSource對象,該對象將與服務(wù)器進行長期連接,并接收服務(wù)器發(fā)送的事件。只有在客戶端手動關(guān)閉連接或連接發(fā)生錯誤時,才會斷開SSE連接。

請注意,由于SSE是基于HTTP的技術(shù),因此它可能受到瀏覽器或服務(wù)器的超時設(shè)置的影響。如果在長時間沒有收到服務(wù)器的數(shù)據(jù)時,連接可能會斷開。如果您希望在長時間不斷開連接的情況下保持SSE連接,請確保服務(wù)器發(fā)送數(shù)據(jù)以保持連接活躍,或者調(diào)整相關(guān)超時設(shè)置。

在使用SSE的客戶端連接中,如果長時間不斷開連接,可能會出現(xiàn)以下情況:

  • 連接超時。如果服務(wù)器端沒有發(fā)送新的事件數(shù)據(jù),而客戶端也沒有重新建立連接,可能會超過服務(wù)器的連接超時時間。這可能導(dǎo)致服務(wù)器關(guān)閉連接,客戶端需要重新建立連接才能接收新的事件數(shù)據(jù)。
  • 網(wǎng)絡(luò)異常。長時間不斷開連接可能會導(dǎo)致網(wǎng)絡(luò)異常,例如連接中斷、丟包等問題。在這種情況下,客戶端可能需要重新建立連接,以恢復(fù)和服務(wù)器的通信。為了避免長時間不斷開連接的問題,建議在合適的時機關(guān)閉連接。

到此這篇關(guān)于springboot整合SSE的項目實踐的文章就介紹到這了,更多相關(guān)springboot整合SSE內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Springboot Druid 自定義加密數(shù)據(jù)庫密碼的幾種方案

    Springboot Druid 自定義加密數(shù)據(jù)庫密碼的幾種方案

    這篇文章主要介紹了Springboot Druid 自定義加密數(shù)據(jù)庫密碼的步驟,幫助大家更好的理解和使用springboot,感興趣的朋友可以了解下
    2020-12-12
  • java中的AWT事件處理問題

    java中的AWT事件處理問題

    這篇文章主要介紹了java中的AWT事件處理問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • SpringBoot框架整合Mybatis簡單攻略

    SpringBoot框架整合Mybatis簡單攻略

    這篇文章主要介紹了SpringBoot框架整合Mybatis的簡單攻略,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2021-10-10
  • java實現(xiàn)修改并替換jar包中靜態(tài)文件過程

    java實現(xiàn)修改并替換jar包中靜態(tài)文件過程

    文章介紹了如何在場景前后端不分離的項目中,通過環(huán)境變量動態(tài)修改jar包中的靜態(tài)資源文件,如`main.js`,具體步驟包括查詢jar包中的js文件目錄,解壓并替換文件,然后將修改后的文件重新打包到j(luò)ar中,文章提供了一種個人經(jīng)驗分享,希望能幫助到其他開發(fā)者
    2025-12-12
  • WebSocket整合SSM(Spring,Struts2,Maven)的實現(xiàn)示例

    WebSocket整合SSM(Spring,Struts2,Maven)的實現(xiàn)示例

    這篇文章主要介紹了WebSocket整合SSM(Spring,Struts2,Maven)的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧
    2019-01-01
  • Java中的類加載器_動力節(jié)點Java學(xué)院整理

    Java中的類加載器_動力節(jié)點Java學(xué)院整理

    這篇文章主要為大家詳細介紹了Java中類加載器的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • idea使用帶provide修飾依賴導(dǎo)致ClassNotFound

    idea使用帶provide修飾依賴導(dǎo)致ClassNotFound

    程序打包到Linux上運行時,若Linux上也有這些依賴,為了在Linux上運行時避免依賴沖突,可以使用provide修飾,本文主要介紹了idea使用帶provide修飾依賴導(dǎo)致ClassNotFound,下面就來介紹一下解決方法,感興趣的可以了解一下
    2024-01-01
  • SpringBoot中的三種應(yīng)用事件處理機制詳解

    SpringBoot中的三種應(yīng)用事件處理機制詳解

    在項目開發(fā)中,組件間的松耦合設(shè)計至關(guān)重要,應(yīng)用事件處理機制作為觀察者模式的一種實現(xiàn),允許系統(tǒng)在保持模塊獨立性的同時實現(xiàn)組件間的通信,SpringBoot延續(xù)并增強了Spring框架的事件機制,提供了多種靈活的事件處理方式,本文給大家介紹了SpringBoot中的三種應(yīng)用事件處理機制
    2025-04-04
  • JDK都出到14了,你有什么理由不會函數(shù)式編程(推薦)

    JDK都出到14了,你有什么理由不會函數(shù)式編程(推薦)

    這篇文章主要介紹了JDK都出到14了,你有什么理由不會函數(shù)式編程,本文給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05
  • java統(tǒng)計字符串中指定元素出現(xiàn)次數(shù)方法

    java統(tǒng)計字符串中指定元素出現(xiàn)次數(shù)方法

    這篇文章主要介紹了java統(tǒng)計字符串中指定元素出現(xiàn)次數(shù)方法,需要的朋友可以參考下
    2015-12-12

最新評論

图木舒克市| 汉川市| 府谷县| 巴彦淖尔市| 班戈县| 深泽县| 高安市| 灌南县| 通榆县| 万盛区| 信丰县| 新绛县| 综艺| 宣武区| 贵阳市| 子洲县| 福泉市| 普定县| 常州市| 石台县| 策勒县| 巴林左旗| 八宿县| 镇赉县| 攀枝花市| 逊克县| 萨嘎县| 汨罗市| 霸州市| 丰都县| 乌拉特中旗| 噶尔县| 凌源市| 枣庄市| 布拖县| 大埔区| 桦南县| 获嘉县| 垫江县| 白朗县| 长武县|