|
@@ -1,72 +1,114 @@
|
|
package org.springblade.websocket.service;
|
|
package org.springblade.websocket.service;
|
|
|
|
|
|
|
|
+import io.undertow.websockets.jsr.UndertowSession;
|
|
import lombok.Data;
|
|
import lombok.Data;
|
|
-import org.apache.commons.lang.StringUtils;
|
|
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
+import org.springblade.business.feign.BusinessWebSocketClient;
|
|
import org.springblade.common.constant.ClientIdConstant;
|
|
import org.springblade.common.constant.ClientIdConstant;
|
|
|
|
+import org.springblade.common.constant.WebsocketMsgConstant;
|
|
import org.springblade.core.tool.api.R;
|
|
import org.springblade.core.tool.api.R;
|
|
import org.springblade.core.tool.jackson.JsonUtil;
|
|
import org.springblade.core.tool.jackson.JsonUtil;
|
|
-import org.springblade.core.tool.utils.SpringUtil;
|
|
|
|
|
|
+import org.springblade.feign.ArchiveWebSocketClient;
|
|
|
|
+import org.springblade.manager.feign.ManagerWebSocketClient;
|
|
import org.springblade.meter.feign.MeterWebSocketClient;
|
|
import org.springblade.meter.feign.MeterWebSocketClient;
|
|
import org.springblade.websocket.entity.WebSocketClientInfo;
|
|
import org.springblade.websocket.entity.WebSocketClientInfo;
|
|
import org.springblade.websocket.vo.MsgVO;
|
|
import org.springblade.websocket.vo.MsgVO;
|
|
|
|
+import org.springblade.websocket.vo.SystMsgVO;
|
|
import org.springblade.websocket.vo.UserInfoVO;
|
|
import org.springblade.websocket.vo.UserInfoVO;
|
|
|
|
+import org.springframework.beans.BeansException;
|
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
+import org.springframework.beans.factory.annotation.Qualifier;
|
|
|
|
+import org.springframework.context.ApplicationContext;
|
|
|
|
+import org.springframework.context.ApplicationContextAware;
|
|
import org.springframework.stereotype.Component;
|
|
import org.springframework.stereotype.Component;
|
|
-
|
|
|
|
import javax.websocket.*;
|
|
import javax.websocket.*;
|
|
import javax.websocket.server.PathParam;
|
|
import javax.websocket.server.PathParam;
|
|
import javax.websocket.server.ServerEndpoint;
|
|
import javax.websocket.server.ServerEndpoint;
|
|
import java.io.IOException;
|
|
import java.io.IOException;
|
|
-import java.util.ArrayList;
|
|
|
|
-import java.util.HashMap;
|
|
|
|
-import java.util.List;
|
|
|
|
-import java.util.Map;
|
|
|
|
-import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
|
|
+import java.util.*;
|
|
|
|
+import java.util.concurrent.*;
|
|
import java.util.concurrent.locks.ReentrantLock;
|
|
import java.util.concurrent.locks.ReentrantLock;
|
|
|
|
|
|
@ServerEndpoint(value = "/websocket/{system}/{projectId}/{contractId}/{userId}")
|
|
@ServerEndpoint(value = "/websocket/{system}/{projectId}/{contractId}/{userId}")
|
|
@Component
|
|
@Component
|
|
@Data
|
|
@Data
|
|
-public class WebSocketService {
|
|
|
|
|
|
+public class WebSocketService implements ApplicationContextAware {
|
|
|
|
+
|
|
|
|
+ @Autowired
|
|
|
|
+ @Qualifier("WebsocketExecutor")
|
|
|
|
+ private Executor WebsocketExecutor;
|
|
|
|
|
|
- private static MeterWebSocketClient meterWebSocketClient = null;
|
|
|
|
|
|
+ /** 计量*/
|
|
|
|
+ private static MeterWebSocketClient meterWebSocketClient;
|
|
|
|
+ /** 质检*/
|
|
|
|
+ private static BusinessWebSocketClient businessWebSocketClient;
|
|
|
|
+ /** 档案*/
|
|
|
|
+ private static ArchiveWebSocketClient archiveWebSocketClient;
|
|
|
|
+ /** 后台*/
|
|
|
|
+ private static ManagerWebSocketClient managerWebSocketClient;
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
|
|
|
+ WebSocketService.meterWebSocketClient = applicationContext.getBean(MeterWebSocketClient.class);
|
|
|
|
+ WebSocketService.businessWebSocketClient = applicationContext.getBean(BusinessWebSocketClient.class);
|
|
|
|
+ WebSocketService.archiveWebSocketClient = applicationContext.getBean(ArchiveWebSocketClient.class);
|
|
|
|
+ WebSocketService.managerWebSocketClient = applicationContext.getBean(ManagerWebSocketClient.class);
|
|
|
|
+ }
|
|
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(WebSocketService.class);
|
|
private static final Logger log = LoggerFactory.getLogger(WebSocketService.class);
|
|
|
|
|
|
/**静态变量,用来记录当前在线用户数。应该把它设计成线程安全的。*/
|
|
/**静态变量,用来记录当前在线用户数。应该把它设计成线程安全的。*/
|
|
private static int onlineUserCount = 0;
|
|
private static int onlineUserCount = 0;
|
|
|
|
+
|
|
/**静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。*/
|
|
/**静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。*/
|
|
private static int onlineLinkCount = 0;
|
|
private static int onlineLinkCount = 0;
|
|
|
|
+
|
|
/**concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象*/
|
|
/**concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象*/
|
|
private static ConcurrentHashMap<Long, Map<String, WebSocketClientInfo>> webSocketMap = new ConcurrentHashMap<>();
|
|
private static ConcurrentHashMap<Long, Map<String, WebSocketClientInfo>> webSocketMap = new ConcurrentHashMap<>();
|
|
|
|
+
|
|
/**concurrent包的线程安全Set,用来存放每个用户所在合同对应的session对象*/
|
|
/**concurrent包的线程安全Set,用来存放每个用户所在合同对应的session对象*/
|
|
- private static ConcurrentHashMap<UserInfoVO, List<Session>> userInfoMap = new ConcurrentHashMap<>();
|
|
|
|
|
|
+ private static ConcurrentHashMap<UserInfoVO, CopyOnWriteArrayList<Session>> userInfoMap = new ConcurrentHashMap<>();
|
|
|
|
+
|
|
|
|
+ /** 计量系统session集合*/
|
|
|
|
+ private static Set<Session> measureSystemSessions = new CopyOnWriteArraySet<>();
|
|
|
|
+ /** 质检系统session集合*/
|
|
|
|
+ private static Set<Session> clientSystemSessions = new CopyOnWriteArraySet<>();
|
|
|
|
+ /** 档案系统session集合*/
|
|
|
|
+ private static Set<Session> archivesSystemSessions = new CopyOnWriteArraySet<>();
|
|
|
|
+
|
|
|
|
+// /** 更新公告推送记录*/
|
|
|
|
+// private static Set<UserSingleVO> updateMsgPushUsers = new HashSet<>();
|
|
|
|
+// /** 普通公告推送记录*/
|
|
|
|
+// private static Set<UserSingleVO> systemMsgPushUsers = new HashSet<>();
|
|
|
|
|
|
/**锁的映射表*/
|
|
/**锁的映射表*/
|
|
private static final ConcurrentHashMap<Long, ReentrantLock> locks = new ConcurrentHashMap<>();
|
|
private static final ConcurrentHashMap<Long, ReentrantLock> locks = new ConcurrentHashMap<>();
|
|
|
|
|
|
/**与某个客户端的连接会话,需要通过它来给客户端发送数据*/
|
|
/**与某个客户端的连接会话,需要通过它来给客户端发送数据*/
|
|
private Session session;
|
|
private Session session;
|
|
- /**接收userId*/
|
|
|
|
|
|
+ /**用户id*/
|
|
private Long userId;
|
|
private Long userId;
|
|
|
|
+ /**用户ip*/
|
|
|
|
+ private String userIp;
|
|
|
|
+ /**系统名称*/
|
|
|
|
+ private String system;
|
|
/**用户系统项目合同信息*/
|
|
/**用户系统项目合同信息*/
|
|
private UserInfoVO vo;
|
|
private UserInfoVO vo;
|
|
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* 连接建立成功调用的方法
|
|
* 连接建立成功调用的方法
|
|
*/
|
|
*/
|
|
@OnOpen
|
|
@OnOpen
|
|
public void onOpen(Session session, @PathParam("system") String system, @PathParam("projectId") Long projectId,
|
|
public void onOpen(Session session, @PathParam("system") String system, @PathParam("projectId") Long projectId,
|
|
@PathParam("contractId") Long contractId,@PathParam("userId") Long userId) {
|
|
@PathParam("contractId") Long contractId,@PathParam("userId") Long userId) {
|
|
- if (meterWebSocketClient == null){
|
|
|
|
- meterWebSocketClient = SpringUtil.getBean(MeterWebSocketClient.class);
|
|
|
|
- }
|
|
|
|
ReentrantLock lock = getLock(userId);
|
|
ReentrantLock lock = getLock(userId);
|
|
lock.lock();
|
|
lock.lock();
|
|
this.session = session;
|
|
this.session = session;
|
|
|
|
+ UndertowSession undertowSession = (UndertowSession) session;
|
|
|
|
+ this.userIp = undertowSession.getWebSocketChannel().getSourceAddress().getAddress().getHostAddress();
|
|
this.userId= userId;
|
|
this.userId= userId;
|
|
|
|
+ this.system = system;
|
|
//用户的连接信息
|
|
//用户的连接信息
|
|
WebSocketClientInfo client = new WebSocketClientInfo();
|
|
WebSocketClientInfo client = new WebSocketClientInfo();
|
|
client.setSession(session);
|
|
client.setSession(session);
|
|
@@ -83,25 +125,39 @@ public class WebSocketService {
|
|
userMap.put(session.getId(),client);
|
|
userMap.put(session.getId(),client);
|
|
webSocketMap.put(userId, userMap);
|
|
webSocketMap.put(userId, userMap);
|
|
addOnlineLinkCount();
|
|
addOnlineLinkCount();
|
|
- log.info("--------------------------------建立连接-----------------------------------------");
|
|
|
|
|
|
+ log.info("----------------------建立连接-------------------------------");
|
|
log.info("用户连接:"+userId+",当前用户总连接数:"+userMap.size());
|
|
log.info("用户连接:"+userId+",当前用户总连接数:"+userMap.size());
|
|
log.info("当前在线人数为:" + getOnlineUserCount()+",当前总连接数:"+getOnlineLinkCount());
|
|
log.info("当前在线人数为:" + getOnlineUserCount()+",当前总连接数:"+getOnlineLinkCount());
|
|
try {
|
|
try {
|
|
sendMessage(JsonUtil.toJson(R.data(new MsgVO("msgLink","来自后台的反馈:连接成功"))));
|
|
sendMessage(JsonUtil.toJson(R.data(new MsgVO("msgLink","来自后台的反馈:连接成功"))));
|
|
this.vo = new UserInfoVO(system,projectId,contractId,userId);
|
|
this.vo = new UserInfoVO(system,projectId,contractId,userId);
|
|
-// int randomNumber = (int)(Math.random() * 11);
|
|
|
|
-// Thread.sleep(randomNumber);
|
|
|
|
- List<Session> sessions = userInfoMap.get(vo);
|
|
|
|
|
|
+ CopyOnWriteArrayList<Session> sessions = userInfoMap.get(vo);
|
|
if (sessions == null){
|
|
if (sessions == null){
|
|
- sessions = new ArrayList<>();
|
|
|
|
|
|
+ sessions = new CopyOnWriteArrayList<>();
|
|
}
|
|
}
|
|
sessions.add(session);
|
|
sessions.add(session);
|
|
userInfoMap.put(vo,sessions);
|
|
userInfoMap.put(vo,sessions);
|
|
|
|
+ /** 获取倒计时,如果当前有倒计时则推送*/
|
|
|
|
+ this.vo.setMsgType("3");
|
|
|
|
+ try {
|
|
|
|
+ managerWebSocketClient.pushMsg(vo);
|
|
|
|
+ }catch (Exception e){
|
|
|
|
+ log.info("用户:"+userId+",网络异常:"+e.getMessage());
|
|
|
|
+ }
|
|
/** 向指定系统发送通知,如果当前用户有需要推送的消息则推送 */
|
|
/** 向指定系统发送通知,如果当前用户有需要推送的消息则推送 */
|
|
switch (system) {
|
|
switch (system) {
|
|
case ClientIdConstant.METER_ID:
|
|
case ClientIdConstant.METER_ID:
|
|
|
|
+ measureSystemSessions.add(session);
|
|
meterWebSocketClient.pushMsg(vo);
|
|
meterWebSocketClient.pushMsg(vo);
|
|
break;
|
|
break;
|
|
|
|
+ case ClientIdConstant.ARCHIVE_ID:
|
|
|
|
+ archivesSystemSessions.add(session);
|
|
|
|
+ break;
|
|
|
|
+ case ClientIdConstant.CLIENT_ID:
|
|
|
|
+ clientSystemSessions.add(session);
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ log.error("未知的系统登录:"+system);
|
|
}
|
|
}
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
log.error("用户:"+userId+",网络异常:"+e.getMessage());
|
|
log.error("用户:"+userId+",网络异常:"+e.getMessage());
|
|
@@ -115,18 +171,27 @@ public class WebSocketService {
|
|
*/
|
|
*/
|
|
@OnClose
|
|
@OnClose
|
|
public void onClose() {
|
|
public void onClose() {
|
|
- //同一个userId,只能有一个线程操作
|
|
|
|
-// try {
|
|
|
|
-// Thread.sleep(10);
|
|
|
|
-// } catch (InterruptedException e) {
|
|
|
|
-// throw new RuntimeException(e);
|
|
|
|
-// }
|
|
|
|
|
|
+ //同一个userId,只能有一个线程同时操作
|
|
ReentrantLock lock = getLock(userId);
|
|
ReentrantLock lock = getLock(userId);
|
|
lock.lock();
|
|
lock.lock();
|
|
try {
|
|
try {
|
|
|
|
+ //先删除系统中存储的session
|
|
|
|
+ switch (system) {
|
|
|
|
+ case ClientIdConstant.METER_ID:
|
|
|
|
+ measureSystemSessions.remove(session);
|
|
|
|
+ break;
|
|
|
|
+ case ClientIdConstant.CLIENT_ID:
|
|
|
|
+ clientSystemSessions.remove(session);
|
|
|
|
+ break;
|
|
|
|
+ case ClientIdConstant.ARCHIVE_ID:
|
|
|
|
+ archivesSystemSessions.remove(session);
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ log.error("未知的系统退出:"+system);
|
|
|
|
+ }
|
|
Map<String, WebSocketClientInfo> userMap = webSocketMap.get(userId);
|
|
Map<String, WebSocketClientInfo> userMap = webSocketMap.get(userId);
|
|
if (userMap != null && userMap.size() > 0) {
|
|
if (userMap != null && userMap.size() > 0) {
|
|
- log.info("--------------------------------断开连接---------------------------------------");
|
|
|
|
|
|
+ log.info("----------------------断开连接-----------------------------");
|
|
List<Session> sessions = userInfoMap.get(vo);
|
|
List<Session> sessions = userInfoMap.get(vo);
|
|
if (sessions != null && sessions.size() > 0){
|
|
if (sessions != null && sessions.size() > 0){
|
|
sessions.remove(session);
|
|
sessions.remove(session);
|
|
@@ -157,10 +222,15 @@ public class WebSocketService {
|
|
@OnMessage
|
|
@OnMessage
|
|
public void onMessage(String message, Session session) {
|
|
public void onMessage(String message, Session session) {
|
|
log.info("收到用户消息:"+userId+",报文:"+message);
|
|
log.info("收到用户消息:"+userId+",报文:"+message);
|
|
- //可以群发消息
|
|
|
|
//消息保存到数据库、redis
|
|
//消息保存到数据库、redis
|
|
- if(StringUtils.isNotBlank(message)){
|
|
|
|
-
|
|
|
|
|
|
+ if(WebsocketMsgConstant.GET_MSG.equals(message)){
|
|
|
|
+ /** 向系统公告发送通知,如果当前有公告则推送*/
|
|
|
|
+ try {
|
|
|
|
+ this.vo.setMsgType("12");
|
|
|
|
+ managerWebSocketClient.pushMsg(vo);
|
|
|
|
+ }catch (Exception e){
|
|
|
|
+ log.info("用户:"+userId+",网络异常:"+e.getMessage());
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -183,21 +253,29 @@ public class WebSocketService {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * 推送指定的系统的所有在线用户
|
|
|
|
+ */
|
|
|
|
+ public void sendMessage(String msg,String system) throws Exception {
|
|
|
|
+ synchronized (session){
|
|
|
|
+ this.session.getBasicRemote().sendText(msg);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* 向指定客户端推送指定用户消息
|
|
* 向指定客户端推送指定用户消息
|
|
*/
|
|
*/
|
|
public void sendMessage(UserInfoVO vo2){
|
|
public void sendMessage(UserInfoVO vo2){
|
|
List<Session> sessions = userInfoMap.get(vo2);
|
|
List<Session> sessions = userInfoMap.get(vo2);
|
|
if(sessions != null && sessions.size() > 0){
|
|
if(sessions != null && sessions.size() > 0){
|
|
- /** 此处不能使用迭代器,否则在推送消息时,当前用户又开启一个页面,集合发生变化迭代器会报错ConcurrentModificationException*/
|
|
|
|
- /** 如果数组越界,则复制一份出来循环发送*/
|
|
|
|
- for (int i = 0; i < sessions.size(); i++) {
|
|
|
|
- Session s = sessions.get(i);
|
|
|
|
|
|
+ /** 此处不能使用普通集合,否则在推送消息时,当前用户又开启一个页面,集合发生变化迭代器会报错ConcurrentModificationException*/
|
|
|
|
+ for (Session s : sessions) {
|
|
if (s == null){
|
|
if (s == null){
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
RemoteEndpoint.Basic basicRemote = s.getBasicRemote();
|
|
RemoteEndpoint.Basic basicRemote = s.getBasicRemote();
|
|
- /** 推送消息时可能因为nginx配置的连接时间导致通道关闭,此时跳过推送给这个窗口*/
|
|
|
|
|
|
+ /** 推送消息时可能因为nginx配置的连接时间,或者用户刚好断开连接,
|
|
|
|
+ * 导致通道关闭,但是数组中使用的是快照,还存在这个连接,此时跳过推送给这个窗口*/
|
|
if (basicRemote != null){
|
|
if (basicRemote != null){
|
|
try {
|
|
try {
|
|
basicRemote.sendText(vo2.getMsg());
|
|
basicRemote.sendText(vo2.getMsg());
|
|
@@ -209,6 +287,84 @@ public class WebSocketService {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * 推送系统公告
|
|
|
|
+ * @param vo
|
|
|
|
+ */
|
|
|
|
+ public void sendSystemMsg(SystMsgVO vo) {
|
|
|
|
+ log.info("------------------公告推送开始-------------------------");
|
|
|
|
+ Integer meterTotal = measureSystemSessions.size();
|
|
|
|
+ Integer clientTotal = clientSystemSessions.size();
|
|
|
|
+ Integer archivesTotal = archivesSystemSessions.size();
|
|
|
|
+ String pushSystem = vo.getPushSystem();
|
|
|
|
+ Integer msgType = vo.getMsgType();
|
|
|
|
+// if (msgType == 1){
|
|
|
|
+// updateMsgPushUsers.clear();
|
|
|
|
+// }else {
|
|
|
|
+// systemMsgPushUsers.clear();
|
|
|
|
+// }
|
|
|
|
+ //处理消息类型
|
|
|
|
+ String msgTypeValue;
|
|
|
|
+ if (msgType == 1){
|
|
|
|
+ msgTypeValue = WebsocketMsgConstant.MSG_UPDATE_MSG;
|
|
|
|
+ }else if (msgType == 2){
|
|
|
|
+ msgTypeValue = WebsocketMsgConstant.MSG_SYSTEM_MSG;
|
|
|
|
+ }else {
|
|
|
|
+ msgTypeValue = WebsocketMsgConstant.MSG_COUNT_DOWN;
|
|
|
|
+ }
|
|
|
|
+ //提前转换消息格式
|
|
|
|
+ String msg = JsonUtil.toJson(R.data(new MsgVO(msgTypeValue,vo.getMsgContent())));
|
|
|
|
+ //异步推送各个系统,最后汇总统计
|
|
|
|
+ CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(
|
|
|
|
+ () -> sendAssignSystemMsg(pushSystem.contains(ClientIdConstant.METER_ID) ? measureSystemSessions : new HashSet<>(),msg), WebsocketExecutor);
|
|
|
|
+ CompletableFuture<Integer> cf2 = CompletableFuture.supplyAsync(
|
|
|
|
+ () -> sendAssignSystemMsg(pushSystem.contains(ClientIdConstant.CLIENT_ID) ? clientSystemSessions : new HashSet<>(),msg), WebsocketExecutor);
|
|
|
|
+ CompletableFuture<Integer> cf3 = CompletableFuture.supplyAsync(
|
|
|
|
+ () -> sendAssignSystemMsg(pushSystem.contains(ClientIdConstant.ARCHIVE_ID) ? archivesSystemSessions : new HashSet<>(),msg), WebsocketExecutor);
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ CompletableFuture.allOf(cf1, cf2,cf3).get(10, TimeUnit.SECONDS);
|
|
|
|
+ String pushInfo = "推送系统{"+pushSystem+"}";
|
|
|
|
+ String pushResult = "推送结果"+"{计量在线"+meterTotal+"推送"+cf1.get()+",质检在线"+clientTotal+"推送"+cf2.get()+",档案在线"+archivesTotal+"推送"+cf3.get()+"}";
|
|
|
|
+ log.info(pushInfo);
|
|
|
|
+ log.info(pushResult);
|
|
|
|
+ log.info("------------------公告推送结束-------------------------");
|
|
|
|
+ } catch (TimeoutException e) {
|
|
|
|
+ log.error("推送公告超时,原因:"+e.getMessage());
|
|
|
|
+ } catch (Exception e){
|
|
|
|
+ log.error("推送公告报错,原因:"+e.getMessage());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 单个系统推送方法
|
|
|
|
+ */
|
|
|
|
+ public Integer sendAssignSystemMsg(Set<Session> sessions,String msg){
|
|
|
|
+ Integer total = 0;
|
|
|
|
+ if (sessions.size() > 0){
|
|
|
|
+ for (Session s : sessions) {
|
|
|
|
+ if (s == null){
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ RemoteEndpoint.Basic basicRemote = s.getBasicRemote();
|
|
|
|
+ /** 推送消息时可能因为nginx配置的连接时间,或者用户刚好断开连接,
|
|
|
|
+ * 导致通道关闭,但是数组中使用的是快照,还存在这个连接,此时跳过推送给这个窗口*/
|
|
|
|
+ if (basicRemote != null){
|
|
|
|
+ try {
|
|
|
|
+ basicRemote.sendText(msg);
|
|
|
|
+ total++;
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
+ log.error("推送公告失败,原因:"+e.getMessage());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return total;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* 获取锁的方法,如果锁不存在,则创建一个新的锁
|
|
* 获取锁的方法,如果锁不存在,则创建一个新的锁
|
|
*/
|
|
*/
|
|
@@ -245,6 +401,4 @@ public class WebSocketService {
|
|
WebSocketService.onlineLinkCount--;
|
|
WebSocketService.onlineLinkCount--;
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
-
|
|
|
|
}
|
|
}
|