springboot使用SSE

1、pom文件

XML 复制代码
 <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
 </dependency>

2、前端代码

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title> Springboot集成SSE </title>
</head>
<script>
    let source = null;
    const clientId = new Date().getTime();
    if (!!window.EventSource) {

        source = new EventSource('http://127.0.0.1:8080/sse/subscribe?id=' + clientId);

    	//建立连接
        source.onopen = function (event) {
            setMessageInnerHTML("建立连接" + event);
        }
        //接收数据
        source.onmessage = function (event) {
            setMessageInnerHTML(event.data);
        }
        //错误监听
        source.onerror = function (event) {
            if (event.readyState === EventSource.CLOSED) {
                setMessageInnerHTML("连接关闭");
            } else {
                console.log(event);
            }
        }
    } else {
        setMessageInnerHTML("浏览器不支持SSE");
    }

    window.onbeforeunload = function () {
        close();
    };

    // 关闭
    function close() {
        source.close();
        const httpRequest = new XMLHttpRequest();
        httpRequest.open('GET', '/sse/over/?clientId=' + clientId, true);
        httpRequest.send();
        console.log("close");
    }

    // 显示消息
    function setMessageInnerHTML(innerHTML) {
        document.getElementById('text').innerHTML += innerHTML + '<br/>';
    }
</script>
<body>
<button onclick="close()">关闭连接</button>
<div id="text"></div>
</body>
</html>

3、后端代码

1、订阅
java 复制代码
private static Map<String, SseEmitter> cache = new ConcurrentHashMap<>();
	@GetMapping(path = "subscribe", produces = {MediaType.TEXT_EVENT_STREAM_VALUE})
	public SseEmitter subscribe(@RequestParam(name = "id", required = false) String id) throws IOException {
		// 超时时间设置
		SseEmitter sseEmitter = new SseEmitter(0L);
		
		cache.put(id, sseEmitter);
		//结束连接
		sseEmitter.onCompletion(() -> {
			log.info("结束连接:{}", id);
			cache.remove(id);
		});
		//连接异常
		sseEmitter.onError(throwable -> {
			log.info("连接异常:{}", id);
			cache.remove(id);
		});
		//连接超时
		sseEmitter.onTimeout(() -> {
			log.info("连接超时:{}", id);
			cache.remove(id);
		});
		return sseEmitter;
	}
2、推送
java 复制代码
@GetMapping(path = "push/{userId}")
	public String push(@PathVariable String userId,@RequestBody Map<String,Object> param) throws IOException {
		try {
			SseEmitter sseEmitter = cache.get("123");
			if (sseEmitter != null) {
				sseEmitter.send(SseEmitter.event().name("msg").data("后端发送消息:" + param));
			}
		} catch (IOException e) {
			log.error("用户[{}]推送异常:{}", userId, e.getMessage());
			cache.remove(userId);
		}
		return "over";
	}
3、关闭
java 复制代码
@GetMapping(path = "over")
	public String over(@RequestParam(name = "id", required = false) String id) {
		SseEmitter sseEmitter = cache.get(id);
		if (sseEmitter != null) {
			sseEmitter.complete();
			cache.remove(id);
		}
		return "over";
	}
相关推荐
波波0071 小时前
ASP.NET Core 健康检查实战:不只是一个 /health 接口
后端·asp.net
小码哥_常1 小时前
Spring Boot 搭建邮件发送系统:开启你的邮件自动化之旅
后端
石榴树下的七彩鱼2 小时前
图片修复 API 接入实战:网站如何自动去除图片水印(Python / PHP / C# 示例)
图像处理·后端·python·c#·php·api·图片去水印
我叫黑大帅2 小时前
为什么TCP是三次握手?
后端·网络协议·面试
我叫黑大帅2 小时前
如何排查 MySQL 慢查询
后端·sql·面试
techdashen2 小时前
Rust项目公开征测:Cargo 构建目录新布局方案
开发语言·后端·rust
一 乐2 小时前
电影院|基于springboot + vue电影院购票管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·电影院购票管理管理系统
恼书:-(空寄2 小时前
JVM GC 日志分析 + 常见 GC 场景 + 实战参数调优
java·jvm
消失的旧时光-19432 小时前
Spring Boot 实战(五):接口工程化升级(统一返回 + 异常处理 + 错误码体系 + 异常流转机制)
java·spring boot·后端·解耦
Rust研习社2 小时前
Rust 智能指针 Cell 与 RefCell 的内部可变性
开发语言·后端·rust