欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

springboot實(shí)現(xiàn)SSE(Server?Sent?Event)的示例代碼

 更新時間:2024年04月22日 10:26:49   作者:愛碼少年?00fly.online  
SSE?全稱Server?Sent?Event,直譯一下就是服務(wù)器發(fā)送事件,本文主要為大家詳細(xì)介紹了springboot實(shí)現(xiàn)SSE的相關(guān)知識,需要的可以參考一下

一、概述

1.SSE是何方神圣

SSE 全稱Server Sent Event,直譯一下就是服務(wù)器發(fā)送事件。

其最大的特點(diǎn),可以簡單概括為兩個

  • 長連接
  • 服務(wù)端可以向客戶端推送信息

2.sse與websocket區(qū)別

sse 是單通道,只能服務(wù)端向客戶端發(fā)消息;而 websocket 是雙通道

那么為什么有了 websocket 還要搞出一個 sse 呢?既然存在,必然有著它的優(yōu)越之處

ssewebsocket
http 協(xié)議獨(dú)立的 websocket 協(xié)議
輕量,使用簡單相對復(fù)雜
默認(rèn)支持?jǐn)嗑€重連需要自己實(shí)現(xiàn)斷線重連
文本傳輸二進(jìn)制傳輸
支持自定義發(fā)送的消息類型-

二、實(shí)現(xiàn)過程

下面我們以springboot工程為例,實(shí)現(xiàn)服務(wù)器端不間斷向客戶端推送數(shù)據(jù)

1.效果展示

http://124.71.129.204:8080/index

2. 簡要流程

3. 源碼放送

SSE工具類

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;

import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import lombok.extern.slf4j.Slf4j;

/**
 * Server-Sent Events <BR>
 * https://blog.csdn.net/hhl18730252820/article/details/126244274
 */
@Slf4j
public class SSEServer
{
    /**
     * 當(dāng)前連接數(shù)
     */
    private static AtomicInteger count = new AtomicInteger(0);
    
    private static Map<String, SseEmitter> sseEmitterMap = new ConcurrentHashMap<>();
    
    public static SseEmitter connect()
    {
        String userId = RandomStringUtils.randomAlphanumeric(10);
        SseEmitter sseEmitter = new SseEmitter(0L); // 設(shè)置超時時間,0表示不過期,默認(rèn)是30秒,超過時間未完成會拋出異常
        
        // 注冊回調(diào)
        sseEmitter.onCompletion(completionCallBack(userId));
        sseEmitter.onError(errorCallBack(userId));
        sseEmitter.onTimeout(timeOutCallBack(userId));
        sseEmitterMap.put(userId, sseEmitter);
        log.info("create new sse connect ,current user:{}, count: {}", userId, count.incrementAndGet());
        return sseEmitter;
    }
    
    public static void batchSendMessage(String message)
    {
        sseEmitterMap.forEach((k, v) -> {
            try
            {
                v.send(message, MediaType.APPLICATION_JSON);
            }
            catch (IOException e)
            {
                log.error("user id:{}, send message error:{}", k, e.getMessage());
                removeUser(k);
            }
        });
    }
    
    public static void removeUser(String userId)
    {
        sseEmitterMap.remove(userId);
        log.info("remove user id:{}, count: {}", userId, count.decrementAndGet());
    }
    
    public static int getUserCount()
    {
        return count.intValue();
    }
    
    private static Runnable completionCallBack(String userId)
    {
        return () -> {
            log.info("結(jié)束連接,{}", userId);
            removeUser(userId);
        };
    }
    
    private static Runnable timeOutCallBack(String userId)
    {
        return () -> {
            log.info("連接超時,{}", userId);
            removeUser(userId);
        };
    }
    
    private static Consumer<Throwable> errorCallBack(String userId)
    {
        return throwable -> {
            log.error("連接異常,{}", userId);
            removeUser(userId);
        };
    }
}

sse接口

import java.util.concurrent.TimeUnit;

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

import com.fly.hello.service.SSEServer;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Api(tags = "sse接口")
@RestController
@RequestMapping("/sse")
public class SSEController
{
    long i = -1;
    
    @ApiOperation("初始化")
    @GetMapping("/connect/{userId}")
    public SseEmitter connect(@PathVariable String userId)
    {
        SseEmitter sseEmitter = SSEServer.connect();
        if (i < 0)
        {
            new Thread(() -> sendMessage()).start();
        }
        return sseEmitter;
    }
    
    private void sendMessage()
    {
        if (i < 0) // 保證僅觸發(fā)一次
        {
            log.info("Server-Sent Events start");
            while (true)
            {
                try
                {
                    TimeUnit.MILLISECONDS.sleep(1000);
                }
                catch (InterruptedException e)
                {
                }
                i = ++i % 101;
                SSEServer.batchSendMessage(String.valueOf(i));
            }
        }
    }
}

頁面引用sse

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>

<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<link href="css/bootstrap.min.css" rel="external nofollow"  rel="stylesheet" type="text/css" />
<style>
body {
	margin: 10;
	font-size: 62.5%;
	line-height: 1.5;
}

.blue-button {
	background: #25A6E1;
	padding: 3px 20px;
	color: #fff;
	font-size: 10px;
	border-radius: 2px;
	-moz-border-radius: 2px;
	-webkit-border-radius: 4px;
	border: 1px solid #1A87B9
}

table {
	width: 60%;
}

th {
	background: SteelBlue;
	color: white;
}

td, th {
	border: 1px solid gray;
	font-size: 12px;
	text-align: left;
	padding: 5px 10px;
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
	max-width: 200px;
	white-space: nowrap;
	text-overflow: ellipsis;
	text-overflow: ellipsis;
}
</style>
</head>
<title>Hello World!</title>
<script>
	let data = new EventSource("/sse/connect/001")
	data.onmessage = function(event) {
		document.getElementById("result").innerText = event.data + '%';
		document.getElementById("my-progress").value = event.data;
	}
</script>
<body>
	<div class="wrapper-page">
		<table align="center">
			<tr>
				<th colspan="4">Navigate</th>
			</tr>
			<tr>
				<td><a href="/index" rel="external nofollow"  target="_self">index</a></td>
				<td><a href="/404" rel="external nofollow"  target="_self">出錯頁面</a></td>
				<td><a href="/doc.html" rel="external nofollow"  target="_blank">doc.html</a></td>
				<td><a href="/h2-console" rel="external nofollow"  target="_blank">h2-console</a></td>
			</tr>
		</table>
		<div class="ex-page-content text-center">
			<h2 align="center">
				<a href="index" rel="external nofollow" >reload</a>
				<div><progress style="width: 60%" id="my-progress" value="0" max="100"></progress></div>
				<div id="result"></div>
			</h2>
			<img src="show/girl" width="600" height="600" />
			<img src="show/pic" width="600" height="600" />
		</div>
	</div>
</body>

</html>

4.完整項(xiàng)目

https://gitcode.com/00fly/springboot-hello

git clone https://gitcode.com/00fly/springboot-hello.git

到此這篇關(guān)于springboot實(shí)現(xiàn)SSE(Server Sent Event)的示例代碼的文章就介紹到這了,更多相關(guān)springboot實(shí)現(xiàn)SSE內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java編程Reference核心原理示例源碼分析

    java編程Reference核心原理示例源碼分析

    這篇文章主要為大家介紹了java編程Reference的核心原理以及示例源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-01-01
  • 利用java實(shí)現(xiàn)單詞倒序排列

    利用java實(shí)現(xiàn)單詞倒序排列

    這篇文章就是利用java實(shí)現(xiàn)單詞倒序排列,感覺像是在變魔術(shù),感興趣的小伙伴來見證一下
    2015-07-07
  • java中最大的整數(shù)用法分析

    java中最大的整數(shù)用法分析

    這篇文章主要介紹了java中最大的整數(shù)用法,結(jié)合具體實(shí)例形式分析了java計算類java.math.BigInteger具體使用技巧,需要的朋友可以參考下
    2017-06-06
  • Java jvm中Code Cache案例詳解

    Java jvm中Code Cache案例詳解

    這篇文章主要介紹了Java jvm中Code Cache案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Java 仿天貓服裝商城系統(tǒng)的實(shí)現(xiàn)流程

    Java 仿天貓服裝商城系統(tǒng)的實(shí)現(xiàn)流程

    讀萬卷書不如行萬里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+SSM+jsp+mysql+maven實(shí)現(xiàn)一個仿天貓服裝商城系統(tǒng),大家可以在過程中查缺補(bǔ)漏,提升水平
    2021-11-11
  • window下安裝和配置maven環(huán)境

    window下安裝和配置maven環(huán)境

    這篇文章主要為大家詳細(xì)介紹了window下安裝和配置maven環(huán)境的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • Java使用fill()數(shù)組填充的實(shí)現(xiàn)

    Java使用fill()數(shù)組填充的實(shí)現(xiàn)

    這篇文章主要介紹了Java使用fill()數(shù)組填充的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • 全網(wǎng)最精細(xì)詳解二叉樹,2萬字帶你進(jìn)入算法領(lǐng)域

    全網(wǎng)最精細(xì)詳解二叉樹,2萬字帶你進(jìn)入算法領(lǐng)域

    大家好,我是哪吒,一個熱愛編碼的Java工程師,本著"欲速則不達(dá),欲達(dá)則欲速"的學(xué)習(xí)態(tài)度,在程序猿這條不歸路上不斷成長,所謂成長,不過是用時間慢慢擦亮你的眼睛,少時看重的,年長后卻視若鴻毛,少時看輕的,年長后卻視若泰山,成長之路,亦是漸漸放下執(zhí)念,內(nèi)心歸于平靜的旅程
    2021-08-08
  • SpringBoot 中常用注解及各種注解作用

    SpringBoot 中常用注解及各種注解作用

    本篇文章將介紹幾種SpringBoot 中常用注解及各個注解的作用,感興趣的朋友跟隨腳本之家小編一起學(xué)習(xí)吧
    2018-03-03
  • Java請求調(diào)用參數(shù)格式為form-data類型的接口代碼示例

    Java請求調(diào)用參數(shù)格式為form-data類型的接口代碼示例

    這篇文章主要給大家介紹了關(guān)于Java請求調(diào)用參數(shù)格式為form-data類型的接口的相關(guān)資料,文中給出了詳細(xì)的代碼示例,對大家的學(xué)習(xí)或者工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-08-08

最新評論