参照:demo篇---同一个用户开启多个webSocket连接_浏览器同一域名创建多个个 websocket 连接-CSDN博客
之前springboot中websocket实现实时算送数据给前端-CSDN博客 方法只能单机使用,如果遇到一个用户打开多个浏览器时,消息只会推送给最新打开或刷新的浏览器,而其他浏览器则不能接收到后端推送的消息。
为了解决上述问题,除了采用redis或mysql方法外,还可以对一个用户进行广播的方式传送数据。
WebSocketServer
主要是修改WebSocketServer中的代码
/**
* @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
* 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
*/
@Component
@CrossOrigin
//@EnableScheduling// cron定时任务
@Data
@Slf4j
@ServerEndpoint("/ws/{userId}")
public class WebSocketServer {
private static ConcurrentHashMap<String, CopyOnWriteArraySet<WebSocketServer>> userwebSocketMap = new ConcurrentHashMap<String, CopyOnWriteArraySet<WebSocketServer>>();
private static ConcurrentHashMap<String, Integer> count = new ConcurrentHashMap<String, Integer>();
private String userId;
/*
* 与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
private Session session;
/**
* 连接建立成功调用的方法
*
* @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") final String userId) {
this.session = session;
this.userId = userId;
if (!exitUser(userId)) {
initUserInfo(userId);
} else {
CopyOnWriteArraySet<WebSocketServer> webSocketTestSet = getUserSocketSet(userId);
webSocketTestSet.add(this);
userCountIncrease(userId);
}
System.out.println("有" + userId + "新连接加入!当前在线人数为" + getCurrUserCount(userId));
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
CopyOnWriteArraySet<WebSocketServer> webSocketTestSet = userwebSocketMap.get(userId);
//从set中删除
webSocketTestSet.remove(this);
//在线数减1
userCountDecrement(userId);
System.out.println("有一连接关闭!当前在线人数为" + getCurrUserCount(userId));
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
* @param session 可选的参数
*/
@OnMessage
public void onMessage(String message, Session session) {
CopyOnWriteArraySet<WebSocketServer> webSocketSet = userwebSocketMap.get(userId);
System.out.println("来自客户端" + userId + "的消息:" + message);
//群发消息
for (WebSocketServer item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
continue;
}
}
}
/**
* 发生错误时调用
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
System.out.println("发生错误");
error.printStackTrace();
}
/**
* 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
*
* @param message
* @throws IOException
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
//this.session.getAsyncRemote().sendText(message);
}
/**
* 发送自定义消息
*/
public static void sendInfo1(JSON message, @PathParam("userId") String userId) throws IOException {
log.info("发送消息到:" + userId + ",报文:" + message);
// if (StringUtils.isNotBlank(userId) && userwebSocketMap.containsKey(userId)) {
// userwebSocketMap.get(userId).sendMessage(message.toString());
// } else {
// log.error("用户" + userId + ",不在线!");
// }
if (StringUtils.isNotBlank(userId)) {
if (userwebSocketMap.containsKey(userId)) {
// 获取 userId 对应的所有 WebSocketServer 实例
CopyOnWriteArraySet<WebSocketServer> servers = userwebSocketMap.get(userId);
for (WebSocketServer server : servers) {
server.sendMessage(message.toString());
}
} else {
log.error("用户" + userId + ",不在线!");
}
}
}
public boolean exitUser(String userId) {
return userwebSocketMap.containsKey(userId);
}
public CopyOnWriteArraySet<WebSocketServer> 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<WebSocketServer> webSocketTestSet = new CopyOnWriteArraySet<WebSocketServer>();
webSocketTestSet.add(this);
userwebSocketMap.put(userId, webSocketTestSet);
count.put(userId, 1);
}
}
这样打开多个浏览器,这几个浏览器的同一个用户都能收到后端推送的数据了。