赞
踩
引用
SSE(Server-Sent Events)是 HTML5 遵循 W3C 标准提出的客户端和服务端之间进行实时通信的协议。
SSE 客户端可以接收来自服务器的“流”数据,而不需要进行轮询
。由于**不浪费请求
**,因此 SSE 对于减轻服务器的压力非常有用。
SSE 使用**纯 JavaScript
** 实现简单,不需要额外的插件或库来处理消息(简单方便
)。
SSE 天生具有自适应性,由于 SSE 是基于 HTTP 响应使用 EventStream 传递消息,因此它利用了 HTTP 的开销和互联网上的结构。
SSE 可以与任何服务器语言和平台一起使用,因为 SSE 是一种规定了消息传递方式的技术,不依赖于具体的服务器语言和平台。
SSE 是**单向通信**,只能从服务器推送到客户端。如果应用程序需要双向通信,就需要使用 Websocket。
SSE无法发送二进制数据,只能发送 UTF-8 编码的文本。如果应用程序需要发送二进制数据,就需要使用 Websocket。
SSE 不是所有浏览器都支持。虽然 SSE 是 HTML5 的一部分,但具体的浏览器支持性可能会有差异。
养生店PC端操作单端通信告知房间小屏数据发生变更做出页面刷新。
当前台PC端 安排了 技师到某个房间,或者上钟,确认项目,设置空房等等. 进行消息通知 .房间小屏进行数据的相应变更
前后端通信断网情况处理。断开连接后,每隔一定睡眠时间,再次自调用确保重建连接。
let source = null //查看 if (!!window.EventSource) { createSource() } else { console.log("不支持"); } window.onbeforeunload = function () { close(); }; // 关闭 为避免占用服务器资源. 调用后台提供出来的清除通信链接API function close() { source.close(); const httpRequest = new XMLHttpRequest(); httpRequest.open('GET', 'http://192.168.10.83:8080/api/sse/communication/closePadClient?shopId=1&roomId=1', true); httpRequest.send(); console.log("close"); } function createSource(){ source = new EventSource('http://192.168.10.83:8080/api/sse/communication/createPadClient?shopId=1&roomId=1'); //建立连接 source.onopen = function (event) { console.log("建立连接" + event); } //接收数据 source.onmessage = function (event) { console.log(event.data); } //错误监听 source.onerror = async function (event) { if (event.currentTarget.readyState === EventSource.CLOSED) { console.log("连接关闭"); await sleep(3000) close() createSource() } else { console.log(event); } } } //js 睡眠解决方案 const sleep = async (count) => { return new Promise((resolve) => { setTimeout(() => { resolve() }, count) }) }
Spring MVC代码
@Controller @RequestMapping("/api/sse/communication") public class SSECommunicationServiceApi { @RequestMapping("/createPadClient") public SseEmitter createPadClient(HttpServletRequest request) { String shopId = request.getParameter("shopId"); String roomId = request.getParameter("roomId"); if (!StringUtils.hasText(shopId)) { throw new BusinessException("连接错误!店铺id为空"); } if (!StringUtils.hasText(roomId)) { throw new BusinessException("连接错误!房间id为空"); } // 设置超时时间,0表示不过期。默认30000毫秒 //可以在客户端一直断网、直接关闭页面但未提醒后端的情况下,服务端在一定时间等待后自动关闭网络连接 SseEmitter sseEmitter = new SseEmitter(0L); String roomKey = shopId+":"+roomId; SSECommunicationUtil.putSSEEmitter(roomKey,sseEmitter); System.out.println("sse连接,当前客户端:"+roomKey); return sseEmitter; } @ResponseBody @RequestMapping("/closePadClient") public BaseRespVO closePadClient(HttpServletRequest request) { String shopId = request.getParameter("shopId"); String roomId = request.getParameter("roomId"); if (!StringUtils.hasText(shopId)) { throw new BusinessException("关闭连接错误!店铺id为空"); } if (!StringUtils.hasText(roomId)) { throw new BusinessException("关闭连接错误!房间id为空"); } String roomKey = shopId+":"+roomId; SSECommunicationUtil.removeSSEEmitter(roomKey); System.out.println("sse连接,当前客户端:"+roomKey); return new BaseRespVO("关闭成功!"); } @ResponseBody @RequestMapping( "/testNotify") public BaseRespVO testNotify(HttpServletRequest request) { String shopId = request.getParameter("shopId"); String roomId = request.getParameter("roomId"); SSECommunicationUtil.updateRegNotificationPad(shopId,roomId, RegChangeNotificationEnum.ARRANGE_DOCTOR); return new BaseRespVO("发送完成!"); } }
SSE管理连接工具类。
public class SSECommunicationUtil { private static Map<String, SseEmitter> cache = new ConcurrentHashMap<>(); public static void updateRegNotificationPad(String shopId, String roomId, RegChangeNotificationEnum notify) { try { SseEmitter sseEmitter = cache.get(shopId+":"+roomId); Random random = new Random(); int sseId = random.nextInt(100000); sseEmitter.send( SseEmitter .event() .data(notify) .id("" + sseId) .reconnectTime(3000) ); } catch (Exception e) { System.out.println(e.getMessage()); } } public static void putSSEEmitter(String key,SseEmitter emitter) { SSECommunicationUtil.cache.put(key,emitter); } public static void removeSSEEmitter(String key) { SSECommunicationUtil.cache.remove(key); } }
通知消息枚举类
public enum RegChangeNotificationEnum { ARRANGE_DOCTOR("ARRANGE_DOCTOR","对已预约记录安排医生"), CLOCK_UP("CLOCK_UP","医生已进行调理(已上钟)"), CLOCK_DOWN("CLOCK_DOWN","医生已结束调理(已下钟)"), CONFIM_ITEM("CONFIM_ITEM","已确认调理项目"), VACATED_ROOM("VACATED_ROOM","已打扫,置空房"), ; private String code; private String title; public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } RegChangeNotificationEnum(String code, String title) { this.code = code; this.title = title; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。