61c77211796f75024d626262d177762907119a73.svn-base 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. package org.jeecg.modules.demo.mock.vxe.websocket;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import lombok.extern.slf4j.Slf4j;
  5. import org.jeecg.common.constant.VXESocketConst;
  6. import org.springframework.stereotype.Component;
  7. import javax.websocket.OnClose;
  8. import javax.websocket.OnMessage;
  9. import javax.websocket.OnOpen;
  10. import javax.websocket.Session;
  11. import javax.websocket.server.PathParam;
  12. import javax.websocket.server.ServerEndpoint;
  13. import java.util.Collection;
  14. import java.util.HashMap;
  15. import java.util.Map;
  16. /**
  17. * vxe WebSocket,用于实现实时无痕刷新的功能
  18. */
  19. @Slf4j
  20. @Component
  21. @ServerEndpoint("/vxeSocket/{userId}/{pageId}")
  22. public class VXESocket {
  23. /**
  24. * 当前 session
  25. */
  26. private Session session;
  27. /**
  28. * 当前用户id
  29. */
  30. private String userId;
  31. /**
  32. * 页面id,用于标识同一用户,不同页面的数据
  33. */
  34. private String pageId;
  35. /**
  36. * 当前socket唯一id
  37. */
  38. private String socketId;
  39. /**
  40. * 用户连接池,包含单个用户的所有socket连接;
  41. * 因为一个用户可能打开多个页面,多个页面就会有多个连接;
  42. * key是userId,value是Map对象;子Map的key是pageId,value是VXESocket对象
  43. */
  44. private static Map<String, Map<String, VXESocket>> userPool = new HashMap<>();
  45. /**
  46. * 连接池,包含所有WebSocket连接;
  47. * key是socketId,value是VXESocket对象
  48. */
  49. private static Map<String, VXESocket> socketPool = new HashMap<>();
  50. /**
  51. * 获取某个用户所有的页面
  52. */
  53. public static Map<String, VXESocket> getUserPool(String userId) {
  54. return userPool.computeIfAbsent(userId, k -> new HashMap<>());
  55. }
  56. /**
  57. * 向当前用户发送消息
  58. *
  59. * @param message 消息内容
  60. */
  61. public void sendMessage(String message) {
  62. try {
  63. this.session.getAsyncRemote().sendText(message);
  64. } catch (Exception e) {
  65. log.error("【vxeSocket】消息发送失败:" + e.getMessage());
  66. }
  67. }
  68. /**
  69. * 封装消息json
  70. *
  71. * @param data 消息内容
  72. */
  73. public static String packageMessage(String type, Object data) {
  74. JSONObject message = new JSONObject();
  75. message.put(VXESocketConst.TYPE, type);
  76. message.put(VXESocketConst.DATA, data);
  77. return message.toJSONString();
  78. }
  79. /**
  80. * 向指定用户的所有页面发送消息
  81. *
  82. * @param userId 接收消息的用户ID
  83. * @param message 消息内容
  84. */
  85. public static void sendMessageTo(String userId, String message) {
  86. Collection<VXESocket> values = getUserPool(userId).values();
  87. if (values.size() > 0) {
  88. for (VXESocket socketItem : values) {
  89. socketItem.sendMessage(message);
  90. }
  91. } else {
  92. log.warn("【vxeSocket】消息发送失败:userId\"" + userId + "\"不存在或未在线!");
  93. }
  94. }
  95. /**
  96. * 向指定用户的指定页面发送消息
  97. *
  98. * @param userId 接收消息的用户ID
  99. * @param message 消息内容
  100. */
  101. public static void sendMessageTo(String userId, String pageId, String message) {
  102. VXESocket socketItem = getUserPool(userId).get(pageId);
  103. if (socketItem != null) {
  104. socketItem.sendMessage(message);
  105. } else {
  106. log.warn("【vxeSocket】消息发送失败:userId\"" + userId + "\"的pageId\"" + pageId + "\"不存在或未在线!");
  107. }
  108. }
  109. /**
  110. * 向多个用户的所有页面发送消息
  111. *
  112. * @param userIds 接收消息的用户ID数组
  113. * @param message 消息内容
  114. */
  115. public static void sendMessageTo(String[] userIds, String message) {
  116. for (String userId : userIds) {
  117. VXESocket.sendMessageTo(userId, message);
  118. }
  119. }
  120. /**
  121. * 向所有用户的所有页面发送消息
  122. *
  123. * @param message 消息内容
  124. */
  125. public static void sendMessageToAll(String message) {
  126. for (VXESocket socketItem : socketPool.values()) {
  127. socketItem.sendMessage(message);
  128. }
  129. }
  130. /**
  131. * websocket 开启连接
  132. */
  133. @OnOpen
  134. public void onOpen(Session session, @PathParam("userId") String userId, @PathParam("pageId") String pageId) {
  135. try {
  136. this.userId = userId;
  137. this.pageId = pageId;
  138. this.socketId = userId + pageId;
  139. this.session = session;
  140. socketPool.put(this.socketId, this);
  141. getUserPool(userId).put(this.pageId, this);
  142. log.info("【vxeSocket】有新的连接,总数为:" + socketPool.size());
  143. } catch (Exception ignored) {
  144. }
  145. }
  146. /**
  147. * websocket 断开连接
  148. */
  149. @OnClose
  150. public void onClose() {
  151. try {
  152. socketPool.remove(this.socketId);
  153. getUserPool(this.userId).remove(this.pageId);
  154. log.info("【vxeSocket】连接断开,总数为:" + socketPool.size());
  155. } catch (Exception ignored) {
  156. }
  157. }
  158. /**
  159. * websocket 收到消息
  160. */
  161. @OnMessage
  162. public void onMessage(String message) {
  163. // log.info("【vxeSocket】onMessage:" + message);
  164. JSONObject json;
  165. try {
  166. json = JSON.parseObject(message);
  167. } catch (Exception e) {
  168. log.warn("【vxeSocket】收到不合法的消息:" + message);
  169. return;
  170. }
  171. String type = json.getString(VXESocketConst.TYPE);
  172. switch (type) {
  173. // 心跳检测
  174. case VXESocketConst.TYPE_HB:
  175. this.sendMessage(VXESocket.packageMessage(type, true));
  176. break;
  177. // 更新form数据
  178. case VXESocketConst.TYPE_UVT:
  179. this.handleUpdateForm(json);
  180. break;
  181. default:
  182. log.warn("【vxeSocket】收到不识别的消息类型:" + type);
  183. break;
  184. }
  185. }
  186. /**
  187. * 处理 UpdateForm 事件
  188. */
  189. private void handleUpdateForm(JSONObject json) {
  190. // 将事件转发给所有人
  191. JSONObject data = json.getJSONObject(VXESocketConst.DATA);
  192. VXESocket.sendMessageToAll(VXESocket.packageMessage(VXESocketConst.TYPE_UVT, data));
  193. }
  194. }