WebSocketServer.java 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. package top.haijunit.train.websocket;
  2. import com.fasterxml.jackson.core.type.TypeReference;
  3. import com.fasterxml.jackson.databind.ObjectMapper;
  4. import jakarta.websocket.*;
  5. import jakarta.websocket.server.PathParam;
  6. import jakarta.websocket.server.ServerEndpoint;
  7. import lombok.extern.slf4j.Slf4j;
  8. import org.apache.commons.lang3.StringUtils;
  9. import org.springframework.stereotype.Component;
  10. import java.io.IOException;
  11. import java.util.Map;
  12. import java.util.concurrent.ConcurrentHashMap;
  13. /**
  14. * @author zhanghaijun
  15. * @date 2023/11/3 16:36
  16. * @description websocket服务接口
  17. */
  18. @Component
  19. @ServerEndpoint("/socket/{uid}")
  20. @Slf4j
  21. public class WebSocketServer {
  22. /**
  23. * 记录当前在线连接数
  24. */
  25. private static int onlineCount = 0;
  26. /**
  27. * 使用线程安全的ConcurrentHashMap来存放每个客户端对应的WebSocket对象
  28. */
  29. private static final ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
  30. /**
  31. * 与某个客户端的连接会话,需要通过它来给客户端发送数据
  32. */
  33. private Session session;
  34. /**
  35. * 接收客户端消息的uid
  36. */
  37. private String uid = "";
  38. /**
  39. * 连接建立成功调用的方法
  40. * @param session
  41. * @param uid
  42. */
  43. @OnOpen
  44. public void onOpen(Session session, @PathParam("uid") String uid) {
  45. this.session = session;
  46. this.uid = uid;
  47. if (webSocketMap.containsKey(uid)) {
  48. webSocketMap.remove(uid);
  49. //加入到set中
  50. webSocketMap.put(uid, this);
  51. } else {
  52. //加入set中
  53. webSocketMap.put(uid, this);
  54. //在线数加1
  55. addOnlineCount();
  56. }
  57. log.info("用户【" + uid + "】连接成功,当前在线人数为:" + getOnlineCount());
  58. try {
  59. sendMsg("连接成功");
  60. } catch (IOException e) {
  61. log.error("用户【" + uid + "】网络异常!", e);
  62. }
  63. }
  64. /**
  65. * 连接关闭调用的方法
  66. */
  67. @OnClose
  68. public void onClose() {
  69. if (webSocketMap.containsKey(uid)) {
  70. webSocketMap.remove(uid);
  71. //从set中删除
  72. subOnlineCount();
  73. }
  74. log.info("用户【" + uid + "】退出,当前在线人数为:" + getOnlineCount());
  75. }
  76. /**
  77. * 收到客户端消息后调用的方法
  78. * @param message 客户端发送过来的消息
  79. * @param session 会话
  80. */
  81. @OnMessage
  82. public void onMessage(String message, Session session) {
  83. log.info("用户【" + uid + "】发送报文:" + message);
  84. //群发消息
  85. //消息保存到数据库或者redis
  86. if (StringUtils.isNotBlank(message)) {
  87. try {
  88. //解析发送的报文
  89. ObjectMapper objectMapper = new ObjectMapper();
  90. Map<String, String> map = objectMapper.readValue(message, new TypeReference<Map<String, String>>(){});
  91. //追加发送人(防止串改)
  92. map.put("fromUID", this.uid);
  93. String toUID = map.get("toUID");
  94. //传送给对应的toUserId用户的WebSocket
  95. if (StringUtils.isNotBlank(toUID) && webSocketMap.containsKey(toUID)) {
  96. webSocketMap.get(toUID).sendMsg(objectMapper.writeValueAsString(map));
  97. } else {
  98. //若果不在这个服务器上,可以考虑发送到mysql或者redis
  99. log.error("请求目标用户【" + toUID + "】不在该服务器上");
  100. }
  101. } catch (Exception e) {
  102. log.error("用户【" + uid + "】发送消息异常!", e);
  103. }
  104. }
  105. }
  106. /**
  107. * 处理错误
  108. * @param session
  109. * @param error
  110. */
  111. @OnError
  112. public void onError(Session session, Throwable error) {
  113. log.error("用户【" + this.uid + "】处理消息错误,原因:" + error.getMessage());
  114. error.printStackTrace();
  115. }
  116. /**
  117. * 实现服务器主动推送
  118. * @param msg
  119. * @throws IOException
  120. */
  121. private void sendMsg(String msg) throws IOException {
  122. this.session.getBasicRemote().sendText(msg);
  123. }
  124. /**
  125. * 发送自定义消息
  126. * @param message
  127. * @param uid
  128. * @throws IOException
  129. */
  130. public static void sendInfo(String message, @PathParam("uid") String uid) throws IOException {
  131. log.info("发送消息到用户【" + uid + "】发送的报文:" + message);
  132. if (!StringUtils.isEmpty(uid) && webSocketMap.containsKey(uid)) {
  133. webSocketMap.get(uid).sendMsg(message);
  134. } else {
  135. log.error("用户【" + uid + "】不在线!");
  136. }
  137. }
  138. private static synchronized int getOnlineCount() {
  139. return onlineCount;
  140. }
  141. private static synchronized void addOnlineCount() {
  142. WebSocketServer.onlineCount++;
  143. }
  144. private static synchronized void subOnlineCount() {
  145. WebSocketServer.onlineCount--;
  146. }
  147. }