当前位置: 首页 > news >正文

springBoot集成websocket实时消息推送

springBoot集成websocket实时消息推送

WebSocket是一种在Web应用程序中实现双向通信的协议。它允许在客户端和服务器之间建立持久性的连接,并支持双向数据传输,实现了实时、低延迟的通信。

📍常见的消息推送方法

  1. WebSocket:通过使用WebSocket协议,可以在Java后端实现双向通信,从而实现消息的实时推送。你可以使用Java中的WebSocket API或者使用开源库如Tomcat的WebSocket支持、Spring WebSocket等来实现。
  2. Server-Sent Events (SSE):SSE是一种基于HTTP的轻量级服务器推送技术,它允许服务器向客户端单向推送消息。在Java后端,你可以使用Servlet或者基于框架的实现来支持SSE。
  3. 消息队列:通过使用消息队列如RabbitMQ、ActiveMQ或者Kafka等,Java后端可以将消息发布到消息队列中,然后客户端通过订阅消息队列来获取实时消息推送。
  4. 短轮询(Long Polling):即浏览器定时向服务器发送请求,以此来更新数据的方法。如下图所示,原理就是客户端不断地向服务端发请求,如果服务端数据有更新,服务端就把数据发送回来,客户端就能接收到新数据了
  5. 长轮询(Long Polling):虽然不同于实时推送,但长轮询是一种模拟实时推送的技术。在Java后端,你可以实现长轮询机制来达到类似实时推送的效果。
    以上是一些常见的Java后端实现消息实时推送提醒的方法。每种方法都有其适用的场景和特点

📍引入依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

📍WebSocketConfig配置类

package com.yxsd.cnooc.data.wb;import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;@Component
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();}
}

📍WebSocketServer服务器类

package com.yxsd.cnooc.data.service;import org.springframework.stereotype.Component;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;/*** @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,* 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端*/
@Component
@ServerEndpoint("/websocket/{userId}")
public class WebSocketTest {private static ConcurrentHashMap<String, CopyOnWriteArraySet<WebSocketTest>> userwebSocketMap = new ConcurrentHashMap<String, CopyOnWriteArraySet<WebSocketTest>>();private static ConcurrentHashMap<String, Integer> count = new ConcurrentHashMap<String, Integer>();private String userId;/** 与某个客户端的连接会话,需要通过它来给客户端发送数据*/private Session session;/*** 连接建立成功调用的方法** @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据*/@OnOpenpublic void onOpen(Session session, @PathParam("userId") final String userId) {this.session = session;this.userId = userId;System.out.println("session:"+session);System.out.println("userId:"+userId);if (!exitUser(userId)) {initUserInfo(userId);} else {CopyOnWriteArraySet<WebSocketTest> webSocketTestSet = getUserSocketSet(userId);webSocketTestSet.add(this);userCountIncrease(userId);}System.out.println("有" + userId + "新连接加入!当前在线人数为" + getCurrUserCount(userId));}/*** 连接关闭调用的方法*/@OnClosepublic void onClose() {CopyOnWriteArraySet<WebSocketTest> webSocketTestSet = userwebSocketMap.get(userId);//从set中删除webSocketTestSet.remove(this);//在线数减1userCountDecrement(userId);System.out.println("有一连接关闭!当前在线人数为" + getCurrUserCount(userId));}/*** 收到客户端消息后调用的方法** @param message 客户端发送过来的消息* @param session 可选的参数*/@OnMessagepublic void onMessage(String message, Session session) {CopyOnWriteArraySet<WebSocketTest> webSocketSet = userwebSocketMap.get(userId);/* System.out.println("来自客户端" + userId + "的消息:" + message);//群发消息for (WebSocketTest item : webSocketSet) {try {item.sendMessage(message);} catch (IOException e) {e.printStackTrace();continue;}}*/}/*** 发生错误时调用** @param session* @param error*/@OnErrorpublic void onError(Session session, Throwable error) {System.out.println("发生错误");error.printStackTrace();}/*** 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。** @param message* @throws IOException*/public void sendMessage(String message) throws IOException {System.out.println("服务端推送" + userId + "的消息:" + message);this.session.getAsyncRemote().sendText(message);}/*** 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。   我是在有代办消息时 调用此接口 向指定用户发送消息 ** @param message* @throws IOException*/public void sendMessage(String userId,String message) throws IOException {System.out.println("服务端推送" + userId + "的消息:" + message);CopyOnWriteArraySet<WebSocketTest> webSocketSet = userwebSocketMap.get(userId);//群发消息for (WebSocketTest item : webSocketSet) {try {item.session.getBasicRemote().sendText(message);} catch (IOException e) {e.printStackTrace();continue;}}}public boolean exitUser(String userId) {return userwebSocketMap.containsKey(userId);}public CopyOnWriteArraySet<WebSocketTest> getUserSocketSet(String userId) {return userwebSocketMap.get(userId);}public void userCountIncrease(String userId) {if (count.containsKey(userId)) {count.put(userId, count.get(userId) + 1);}}public void userCountDecrement(String userId) {if (count.containsKey(userId)) {count.put(userId, count.get(userId) - 1);}}public void removeUserConunt(String userId) {count.remove(userId);}public Integer getCurrUserCount(String userId) {return count.get(userId);}private void initUserInfo(String userId) {CopyOnWriteArraySet<WebSocketTest> webSocketTestSet = new CopyOnWriteArraySet<WebSocketTest>();webSocketTestSet.add(this);userwebSocketMap.put(userId, webSocketTestSet);count.put(userId, 1);}}

📍前端实现代码

  • 方法一:使用在线websocket客户端

    客户端页面使用 http://www.jsons.cn/websocket/ 与项目建立连接,充当web客户端

  • 方法二:自己编写客户端

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body></body>
<script>let webSocket = null;   // 创建一个变量if ('WebSocket' in window){  // 判断当前的浏览器是否支持WebSocket// 如果支持则创建一个WebSocket赋值给刚才创建的变量// 后面的路径实际上就是一次请求,但是这里用的是WebSocket协议// 记住这个地方后面详细讲到怎么写webSocket = new WebSocket('ws://localhost:8080/webSocket');}else{  // 如果不兼容则弹框,该浏览器不支持alert('该浏览器不支持')}/** * 当WebSocket创建连接(初始化)会触发该方法*/webSocket.onopen = function (event){console.log('建立连接') // 这个代表在浏览器打印日志,跟Java的System.out.println()意思一致}/** * 当WebSocket关闭时候会触发该方法*/webSocket.onclose = function (event){console.log('关闭连接') // 同上}/** * 当WebSocket接受消息会触发该方法*/webSocket.onmessage = function (event){console.log('收到消息:'+event.data)}/** * 当WebSocket连接出错触发该方法*/webSocket.onerror = function (event){console.log('websocket发生错误');}/** * 页面关闭,WebSocket关闭*/window.onbeforeunload = function (){webSocket.close();}
</script>
</html>

相关文章:

  • 【uniapp】 video视频层级、遮挡其他弹窗或顶部导航 使用nvue覆盖
  • 《Fine-Grained Image Analysis with Deep Learning: A Survey》阅读笔记
  • 【最新Tomcat】IntelliJ IDEA通用配置Tomcat教程(超详细)
  • 【计算机网络笔记】网络地址转换(NAT)
  • ClickHouse数据一致性
  • LangChain 2模块化prompt template并用streamlit生成网站 实现给动物取名字
  • 代码随想录算法训练营第二十八天| 78 子集 90 子集|| 93 复原IP地址
  • 基于SSM的北海旅游网站设计与实现
  • Windows安装Vmware 虚拟机
  • Axios传值的几种方式
  • 左支座零件的机械加工工艺规程及工艺装备设计【计算机辅助设计与制造CAD】
  • YOLOv8 加持 MobileNetv3,目标检测新篇章
  • docker的基本使用以及使用Docker 运行D435i
  • Notepad+正则表达式使用方法
  • SpringCloud 微服务全栈体系(十四)
  • ----------
  • Angular 响应式表单 基础例子
  • Eureka 2.0 开源流产,真的对你影响很大吗?
  • JS数组方法汇总
  • Odoo domain写法及运用
  • oschina
  • PaddlePaddle-GitHub的正确打开姿势
  • Python打包系统简单入门
  • Redash本地开发环境搭建
  • Vue学习第二天
  • 面试题:给你个id,去拿到name,多叉树遍历
  • 原生Ajax
  • 自制字幕遮挡器
  • 关于Android全面屏虚拟导航栏的适配总结
  • # Apache SeaTunnel 究竟是什么?
  • # 再次尝试 连接失败_无线WiFi无法连接到网络怎么办【解决方法】
  • ###C语言程序设计-----C语言学习(6)#
  • #pragam once 和 #ifndef 预编译头
  • (1)Android开发优化---------UI优化
  • (3)选择元素——(17)练习(Exercises)
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (八)Spring源码解析:Spring MVC
  • (附源码)ssm航空客运订票系统 毕业设计 141612
  • (力扣题库)跳跃游戏II(c++)
  • (区间dp) (经典例题) 石子合并
  • (三)docker:Dockerfile构建容器运行jar包
  • (三)Hyperledger Fabric 1.1安装部署-chaincode测试
  • (原)Matlab的svmtrain和svmclassify
  • (原+转)Ubuntu16.04软件中心闪退及wifi消失
  • (转)scrum常见工具列表
  • . Flume面试题
  • ./和../以及/和~之间的区别
  • .NET 4.0中的泛型协变和反变
  • .NET C# 使用 SetWindowsHookEx 监听鼠标或键盘消息以及此方法的坑
  • @Bean有哪些属性
  • @RequestBody与@ModelAttribute
  • @staticmethod和@classmethod的作用与区别
  • @transaction 提交事务_【读源码】剖析TCCTransaction事务提交实现细节
  • [1127]图形打印 sdutOJ
  • [android] 切换界面的通用处理