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

springboot+vue實(shí)現(xiàn)SSE服務(wù)器發(fā)送事件的示例

 更新時(shí)間:2025年01月02日 09:06:02   作者:black^sugar  
本文介紹了使用Spring Boot和Vue實(shí)現(xiàn)服務(wù)器發(fā)送事件,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

思路

一個(gè)基于訂閱發(fā)布機(jī)制的SSE事件??蛻舳丝梢哉?qǐng)求訂閱api(攜帶客戶端id),與服務(wù)器建立SSE鏈接;后續(xù)服務(wù)器需要推送消息到客戶端時(shí),再根據(jù)客戶端id從已建立鏈接的會(huì)話中找到目標(biāo)客戶端,將消息推送出去。

后端

這個(gè)控制器類允許客戶端訂閱、接收消息和斷開連接,通過 pool 存儲(chǔ) SseEmitter 并對(duì)其進(jìn)行管理。

package com.example.q11e.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

@RestController
public class SseController {
    // 存儲(chǔ)已訂閱的客戶端的會(huì)話列表
    private final Map<String, SseEmitter> pool = new ConcurrentHashMap<>();

    // 向特定的 SseEmitter 發(fā)送消息
    public void publisher(String id_sid, int content) {
        // 根據(jù) id_sid 從映射中獲取 SseEmitter
        SseEmitter sseEmitter = pool.get(id_sid);
        if (Objects.isNull(sseEmitter)) {
            return;
        }
        try {
            sseEmitter.send(content); // 發(fā)送內(nèi)容
        } catch (IOException e) {
            System.out.println("null " + e);
        }
    }


    // 處理客戶端的訂閱請(qǐng)求
    @GetMapping("/subscribe/{id}")
    public SseEmitter subscribe(@PathVariable("id") String id_sid) {
        // 根據(jù) id_sid 從映射中獲取 SseEmitter
        SseEmitter sseEmitter = pool.get(id_sid);
        if (Objects.isNull(sseEmitter)) {
            // 如果不存在,則創(chuàng)建一個(gè)新的 SseEmitter,設(shè)置超時(shí)時(shí)間為 130000 毫秒
            sseEmitter = new SseEmitter(130000L);
            // 設(shè)置發(fā)送完成事件:從映射中移除該 SseEmitter
            sseEmitter.onCompletion(() -> pool.remove(id_sid)); 
            // 設(shè)置超時(shí)事件:從映射中移除該 SseEmitter
            sseEmitter.onTimeout((() -> pool.remove(id_sid))); 
            // 將新創(chuàng)建的 SseEmitter 放入映射中
            pool.put(id_sid, sseEmitter);
        }
        // System.out.println(pool);
        // 返回 SseEmitter 給客戶端
        return sseEmitter;
    }

    // 處理客戶端的斷開連接請(qǐng)求
    public void disconnect(String id_sid) {
        SseEmitter emitter = pool.remove(id_sid);
        if (emitter!= null) {
            emitter.complete();
        }
    }
}

發(fā)送消息

package com.example.q11e.service;

import com.example.q11e.controller.SseController;

@Service
public class BatchService {
    @Autowired
    public BatchService(SseController sseController) {
        this.sseController = sseController;
    }
    private final SseController sseController;

    @Async
    public void batchRequests(){
        // uid+"_"+sid 客戶端標(biāo)識(shí)符,sucCount為需要發(fā)送的信息
        sseController.publisher(uid + "_" + sid, sucCount);
        sseController.disconnect(uid + "_" + sid);
    }
}

前端

SSE狀態(tài)管理  store.ts

// sse前端
import { defineStore } from 'pinia';
import { getUserBalance } from '@/request/api.ts'

export const useESStore = defineStore('EventSource', {
  state: () => ({
    uid: localStorage.getItem('uid'),
    balance: 1,
    eventSourceInstance: null as EventSource | null, // 新增狀態(tài)屬性
    currentSid: null as string | null,
    currentCount: 0,
    currentTotal: 0,
    connect: false
  }),
  actions: {
    setUid(uid:string) {
      this.uid = uid;
    },
    setConnect(connect: boolean) {
      this.connect = connect
    },
    initEventSource(sid:string) {
      if (this.uid) {
        const sseURL = import.meta.env.VITE_SSE_URL
        const evtSrcInstance = new EventSource(sseURL + "/" + this.uid + "_" + sid);
        evtSrcInstance.onmessage = (e) => {
          this.setCurrentCount(e.data) //普通函數(shù)時(shí): this-->evtSrcInstance
        };
        evtSrcInstance.onopen = () => {
          this.setCurrentCount(0)
          this.setConnect(true)
        };
        evtSrcInstance.onerror = () => {
          this.setConnect(false)
          this.setCurrentTotal(0)
        };
        this.eventSourceInstance = evtSrcInstance; // 存儲(chǔ)實(shí)例到狀態(tài)
      }
    },
    closeEventSource() {
      if (this.eventSourceInstance) {
        this.eventSourceInstance.close();
        this.eventSourceInstance = null;
      }
    }
  }
});
<template>
  <span v-show="connect">
    <span class="sid">{{ sid }}</span>
    <span v-for="(char, index) in ['.', '.', '.']" :key="index" class="blink-effect sid"
      :style="{ animationDelay: `${index * 0.1}s` }">{{ char }}</span>
     <!----count是服務(wù)器推送的內(nèi)容----->
    <span class="process">{{ count }}/{{ total }}</span>
  </span>
</template>

<script lang="ts" setup>
import { computed } from 'vue'
import { useESStore } from '@/store/store.ts'
const SSE = useESStore()
let count = computed(() => SSE.currentCount)
let total = computed(() => SSE.currentTotal)
let sid = computed(() => SSE.currentSid)
let connect = computed(() => SSE.connect)
</script>

<style scoped>
.process {
  background: red;
  color: white;
  padding: 2px 4px;
}
.sid { color: #333; }
@keyframes blink {
  0%, 100% {
    transform: translateY(0); /* 開始和結(jié)束狀態(tài)位置無變化 */
  }
  50% {
    transform: translateY(-5px); /* 中間狀態(tài)位置向上移動(dòng)5px */
  }
}
.blink-effect {
  display: inline-block;
  animation: blink 1s infinite;
}
</style>

效果

后端執(zhí)行某耗時(shí)任務(wù)時(shí),需要實(shí)時(shí)推送進(jìn)度到客戶端,每完成一個(gè)階段,就向客戶端推送一個(gè)單位進(jìn)度,做到客戶端實(shí)時(shí)顯示進(jìn)度的效果。

到此這篇關(guān)于springboot+vue實(shí)現(xiàn)SSE服務(wù)器發(fā)送事件的示例的文章就介紹到這了,更多相關(guān)springboot vue SSE發(fā)送事件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

巴彦淖尔市| 全州县| 同德县| 资阳市| 德清县| 洛南县| 正宁县| 鄂托克前旗| 施秉县| 潜江市| 天台县| 伽师县| 三亚市| 汽车| 明水县| 南安市| 曲水县| 内乡县| 金川县| 同心县| 桃园县| 东光县| 金沙县| 那坡县| 凤庆县| 赣州市| 喀喇沁旗| 莱州市| 和政县| 奈曼旗| 通河县| 汉沽区| 商水县| 启东市| 新竹县| 郧西县| 乌拉特后旗| 遵义县| 武夷山市| 宁南县| 出国|