前端


```html
//这是去获取未读消息的条数(这个函数是自定义的)
function getNotifyInfo() {$.ajax({cache: true,type: "get",url: ctx + "tbs/notice/unreadMessage",async: false,success: function (result) {if (result.code == 0) {if(result.data > 0){//设置在小铃铛上面$("#noticeNum").text(result.data);$("#noticeNum").show();$("#noticeDetail").text([[#{tbs.meaasge.notice.unread}]].format(result.data));}else{$("#noticeNum").text("");$("#noticeNum").hide();$("#noticeDetail").text([[#{tbs.meaasge.notice.read}]]);}}},error: function (error) {}});}var websocket;//避免重复连接var lockReconnect = false, tt;/*** websocket启动*/function createWebSocket() {try {var userId = $("#userId").val();var url = $("#url").val() + "/websocket/message/" + userId;if ('WebSocket' in window) {websocket = new WebSocket(url);init();} else if ('MozWebSocket' in window) {websocket = new MozWebSocket(url);init();} else {//websocket = new SockJS(url);}} catch (e) {console.log('catch' + e);reconnect();}}function init() {//连接成功建立的回调方法websocket.onopen = function (event) {//console.log("WebSocket:onopen");//心跳检测重置heartCheck.reset().start();};//接收到消息的回调方法websocket.onmessage = function (event) {//console.log("WebSocket:onmessage,", event.data);heartCheck.reset().start();if(event.data != "ok"){getNotifyInfo();}};//连接发生错误的回调方法websocket.onerror = function (event) {//console.log("WebSocket:error");reconnect();};//连接关闭的回调方法websocket.onclose = function (event) {//console.log("WebSocket:closed");heartCheck.reset();//心跳检测reconnect();};//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。window.onbeforeunload = function () {websocket.close();};//关闭连接function closeWebSocket() {websocket.close();}//发送消息function send(message) {websocket.send(message);}}/*** websocket重连*/function reconnect() {if (lockReconnect) {return;}lockReconnect = true;tt && clearTimeout(tt);tt = setTimeout(function () {//console.log('reconnect...');lockReconnect = false;createWebSocket();}, 10000);}/*** websocket心跳检测*/var heartCheck = {timeout: 60000,timeoutObj: null,serverTimeoutObj: null,reset: function () {clearTimeout(this.timeoutObj);clearTimeout(this.serverTimeoutObj);return this;},start: function () {var self = this;this.timeoutObj && clearTimeout(this.timeoutObj);this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);this.timeoutObj = setTimeout(function () {//这里发送一个心跳,后端收到后,返回一个心跳消息,//onmessage拿到返回的心跳就说明连接正常websocket.send("ping");//console.log('ping');self.serverTimeoutObj = setTimeout(function () { // 如果超过一定时间还没重置,说明后端主动断开了websocket.close();//如果onclose会执行reconnect,我们执行 websocket.close()就行了.如果直接执行 reconnect 会触发onclose导致重连两次}, self.timeout)}, this.timeout)}};

java

controller

import java.util.concurrent.Semaphore;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;import com.dcdzsoft.tbs.utils.SemaphoreUtils;
import com.dcdzsoft.tbs.utils.WebSocketUsers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;/*** websocket 消息处理*/
@Component
@ServerEndpoint("/websocket/message/{uid}")
public class WebSocketServer {/*** WebSocketServer 日志控制器*/private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketServer.class);/*** 默认最多允许同时在线人数100000*/public static int socketMaxOnlineCount = 100000;private static Semaphore socketSemaphore = new Semaphore(socketMaxOnlineCount);/*** 连接建立成功调用的方法*/@OnOpenpublic void onOpen(Session session, @PathParam("uid") String uid) throws Exception {boolean semaphoreFlag = false;// 尝试获取信号量semaphoreFlag = SemaphoreUtils.tryAcquire(socketSemaphore);if (!semaphoreFlag) {// 未获取到信号量WebSocketUsers.sendMessageToUserByText(session, "Online Limit:" + socketMaxOnlineCount);session.close();} else {// 添加用户WebSocketUsers.put(uid, session);LOGGER.info("\n online number - {}", WebSocketUsers.getUsers().size());WebSocketUsers.sendMessageToUserByText(session, "success");}}/*** 连接关闭时处理*/@OnClosepublic void onClose(Session session) {LOGGER.info("\n close connect - {}", session);// 移除用户WebSocketUsers.remove(session);// 获取到信号量则需释放SemaphoreUtils.release(socketSemaphore);}/*** 抛出异常时处理*/@OnErrorpublic void onError(Session session, Throwable exception) throws Exception {if (session.isOpen()) {// 关闭连接session.close();}LOGGER.info("\n connect error - {}", exception);// 移出用户WebSocketUsers.remove(session);// 获取到信号量则需释放SemaphoreUtils.release(socketSemaphore);}/*** 服务器接收到客户端消息时调用的方法*/@OnMessagepublic void onMessage(String message, Session session) {WebSocketUsers.sendMessageToUserByText(session, "ok");}
}

WebSocketConfig

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** websocket 配置* @author ruoyi*/
@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

WebSocketUsers

import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.websocket.Session;
import com.dcdzsoft.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** websocket 客户端用户集* @author ruoyi*/
public class WebSocketUsers {/*** WebSocketUsers 日志控制器*/private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketUsers.class);/*** 用户集*/private static Map<String, Session> USERS = new ConcurrentHashMap<String, Session>();/*** 存储用户* @param key     唯一键* @param session 用户信息*/public static void put(String key, Session session) {USERS.put(key, session);}/*** 移除用户* @param session 用户信息* @return 移除结果*/public static boolean remove(Session session) {String key = null;boolean flag = USERS.containsValue(session);if (flag) {Set<Map.Entry<String, Session>> entries = USERS.entrySet();for (Map.Entry<String, Session> entry : entries) {Session value = entry.getValue();if (value.equals(session)) {key = entry.getKey();break;}}} else {return true;}return remove(key);}/*** 移出用户** @param key 键*/public static boolean remove(String key) {Session remove = USERS.remove(key);if (remove != null) {boolean containsValue = USERS.containsValue(remove);return containsValue;} else {return true;}}/*** 获取在线用户列表** @return 返回用户集合*/public static Map<String, Session> getUsers() {return USERS;}/*** 获取在线用户列表* @return 返回用户集合*/public static Session getUserSession(String uid) {return USERS.get(uid);}/*** 群发消息文本消息* @param message 消息内容*/public static void sendMessageToUsersByText(String message) {Collection<Session> values = USERS.values();for (Session value : values) {sendMessageToUserByText(value, message);}}/*** 发送文本消息** @param message 消息内容*/public static void sendMessageToUserByText(Session session, String message) {if (session != null) {try {session.getBasicRemote().sendText(message);} catch (IOException e) {LOGGER.error("\n[msg error]", e);}} else {LOGGER.info("\n[already offline]");}}/*** 发送文本消息* @param message 消息内容*/public static void sendMessageToUserByText(String uid, String message) {try {Session session = getUserSession(uid);if(session == null){LOGGER.info("\n[already offline]");}else{session.getBasicRemote().sendText(message);}} catch (IOException e) {LOGGER.error("\n[msg error]", e);}}
}

SemaphoreUtils

import java.util.concurrent.Semaphore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*** 信号量相关处理** @author ruoyi*/
public class SemaphoreUtils {/*** SemaphoreUtils 日志控制器*/private static final Logger LOGGER = LoggerFactory.getLogger(SemaphoreUtils.class);/*** 获取信号量* @param semaphore* @return*/public static boolean tryAcquire(Semaphore semaphore) {boolean flag = false;try {flag = semaphore.tryAcquire();} catch (Exception e) {LOGGER.error("获取信号量异常", e);}return flag;}/*** 释放信号量* @param semaphore*/public static void release(Semaphore semaphore) {try {semaphore.release();} catch (Exception e) {LOGGER.error("释放信号量异常", e);}}
}

哪里需要,哪里调 WebSocketUsers.sendMessageToUserByText(userId.toString(), “internalMessage”);这个方法来告诉前端,你执行一下获取数量的函数

websocket实现消息实时更新(亲测,2021/11/9)相关推荐

  1. 最新微信8.0.1抢红包神器-亲测2021年2月11日可用-安卓IOS

    最新微信8.0.1抢红包神器-亲测2021年2月11日可用-安卓&IOS 文章目录 概述 效果图 使用指南 获取方式 概述 今晚就过年了,相信很多朋友在微信群能收到很多红包,但是过年可能吃的更 ...

  2. Axure 8.1.0.3381 激活码 10月20号更新 亲测可用

    Axure 8.1.0.3381  激活码  10月20号更新 亲测可用,立马激活,更新之后不后悔. 激活码查看地址:https://download.csdn.net/download/qq_207 ...

  3. win10必须禁用的服务_【亲测】Win10系统如何彻底禁止自动更新 亲测有效的Win10关闭自动更新方法...

    昨天有人称Win10系统更新依然无法彻底关闭,今天再来补充一下,肯定可以! 不少用户反映自己的Win10系统更新无法彻底关闭,网上提供的关闭Win10更新的教程,关闭之后还是会自动更新Win10系统, ...

  4. FC金手指代码大全·持续更新-亲测可用-FC 经典游戏完整可用的金手指大全---持续更新,偶尔玩玩经典回味无穷,小时候不能通关的现在通通通关一遍

    FC 经典游戏完整可用的金手指大全-持续更新,偶尔玩玩经典回味无穷,小时候不能通关的现在通通通关一遍 2021年5月11日更新: 每次翻金手指一些垃圾小网站标题党吸引进去吓一大堆木马什么也没有,什么x ...

  5. 禁止Chrome浏览器自动更新 亲测可用

    说明:仅供学习使用,请勿用于非法用途,若有侵权,请联系博主删除 作者:zhu6201976 博客:zhu6201976的博客_CSDN博客 一.需求场景 Chrome浏览器安装后会默认自动更新升级,对 ...

  6. 微信公众号自定义菜单栏添加历史消息方法(亲测有效)

    1.在浏览器中打开自己公众号的一篇推送,Ctrl+U查看网页源代码. 2.Ctrl+F搜索var biz,复制对应的代码 3.前面加上https://mp.weixin.qq.com/mp/profi ...

  7. 微信通知设置全开仍然需要打开界面才有消息提醒?亲测神奇偏方,还原所有设置前必须试一试的方法

    背景 过年回家,老人说手机微信有消息不提醒了.试过了很多方法,不管是设置通知开启,提高微信权限,打开网上一系列方法中的设置,包括比较偏方的电池优化中的允许后台运行都没有效果. 线索(症状) 发现有时进 ...

  8. springboot心跳检测_springboot websocket 实时刷新 添加心跳机制(亲测可用版)

    思路 在我之前的一篇文章当中写到了websocket的实时刷新,但是有个问题没有解决,就是长时间没有数据的时候,这个连接就会自动断开,然后再次进行连接的话,需要再次进行连接.如果加入心跳机制的话,10 ...

  9. Windows 10如何连接和使用局域网内的打印机(非网络打印机)亲测有效、绝对管用,不定时更新!!!(更新日期2021.09.14,如有不会的可以直接私我)

    (请先看置顶博文)本博打开方式!!!请详读!!!请详读!!!请详读!!!_Cat-CSDN博客 要完成这个Case,步骤很简单,以下是详细过程,慢慢看完就一定可以实现:(一定要保证涉及共享打印机的计算 ...

最新文章

  1. 给PHPSTORM添加XDEBUG调试功能
  2. java多线程之wait_(三)java多线程之wait notify notifyAll
  3. 别再搜集面经啦!小夕教你斩下NLP算法岗offer!
  4. Android中ListView数据使用sAdapter.notifyDataSetChanged();方法不刷新的问题
  5. memcpy-avx-unaligned/strcpy_sse2_unaligned崩溃记录
  6. Android中的App网络传输协议
  7. 自制冰箱,冰柜蒸发器和毛细管的速算
  8. python PyAutoGUI 模拟鼠标键盘操作和截屏
  9. 如何实现简单粗暴靠谱的直播抓娃娃方案
  10. C#获取企业微信打卡数据
  11. 四面阿里,因为最后一个问题与offer失之交臂
  12. 计算机毕设(附源码)JAVA-SSM基于云服务器网上论坛设计
  13. 使用 Fastai 构建食物图像分类器
  14. Java-Util之ArrayList
  15. 服务器渲染技术jsp
  16. 案例:SOA成就最佳电子政务平台
  17. 河海大学软件工程学硕考研复试经验贴
  18. Be accepted for inclusion in the IEEE INFOCOM 2018 technical program
  19. VS2012 开发SharePoint 2013 声明式workflow action(activity)之 HelloWorld
  20. 三星数码相机照片恢复,相机格式化后恢复

热门文章

  1. [译]如何理解你的肠道微生物检测报告和数据
  2. 基于php的个人理财系统,基于PHP个人理财管理系统设计
  3. 如何将多段16:9的视频同时裁切为1:1的视频
  4. Vue3渲染函数开发混合插件之函数调用组件
  5. linux桌面版远程控制软件,ubuntu64位ARM版本飞腾可用
  6. 下一页分节符和连续分节符
  7. GNN-CS224W: 16 Position-aware and Identity-aware GNNs and Robustness of GNN
  8. 发现了问题解决不了--转:【win XP SP3 不能安装HD声卡驱动的解决办法】
  9. 联想Thinkbook Ubuntu18.04 安装nvidia显卡驱动
  10. 2023年最新自动化/控制保研夏令营预推免经验贴(清华/自动化所/浙大/上交)