本文最后更新于:2023年8月24日 晚上
导入依赖
1 2 3 4
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
|
最简结构
建立websocket服务类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| package com.fsan.socket;
import com.alibaba.fastjson.JSON; import com.fsan.entity.RespResult; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.AbstractWebSocketHandler;
@Slf4j @Component public class WsService extends AbstractWebSocketHandler {
@Override public void afterConnectionEstablished(WebSocketSession session) { log.info(session.getId() + "建立ws连接"); }
@Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) { log.info(session.getId() + "关闭ws连接"); }
@Override protected void handleTextMessage(WebSocketSession session, TextMessage message) { String payload = message.getPayload(); log.info("收到消息:" + payload); } }
|
websocket配置开启服务
创建 config > SocketConfig.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| package com.fsan.config;
import com.fsan.socket.WsService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration @EnableWebSocket public class SocketConfig implements WebSocketConfigurer {
@Autowired private WsService wsService;
@Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry .addHandler(wsService, "/ws/user") .setAllowedOrigins("*");
} }
|
这里 “/ws/user” 就是连接路径,如 “ws://localhost:8081/ws/user”
html页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button onclick="createConn()">建立连接</button> <input type="text" id="inputVal" placeholder="发送消息"> <button onclick="sendMsg()">发送</button> </body>
<script> let socket; const sendMsg = () => { socket.send(document.getElementById("inputVal").value) } const createConn = () => { socket = new WebSocket(`ws://localhost:8081/ws/user`) socket.onopen = () => { document.getElementById("state").innerText = '已连接!' } } </script> </html>
|
存储每个socket连接
建立websocket管理类
socket > WsSocketManage.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
| package com.fsan.socket;
import com.alibaba.fastjson.JSON; import com.fsan.entity.WsRespResult; import com.fsan.myEnum.WsRespResultEnum; import lombok.extern.slf4j.Slf4j; import org.springframework.util.StringUtils; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession;
import java.io.IOException; import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap;
@Slf4j public class WsSocketManage { private static ConcurrentHashMap<String, WebSocketSession> wsSession = new ConcurrentHashMap<>();
static void add(String key, WebSocketSession session) { wsSession.put(key, session); }
static WebSocketSession remove(String key) { return wsSession.remove(key); }
static void removeAndClose(String key) { WebSocketSession remove = wsSession.remove(key); if (!StringUtils.isEmpty(remove)) { try { remove.close(); } catch (IOException e) { e.printStackTrace(); } }
}
static WebSocketSession get(String key) { return wsSession.get(key); }
public static Integer getUserNum() { return wsSession.size(); }
static HashMap<String, String> getQueryToMap(WebSocketSession session) { String query = session.getUri().getQuery(); HashMap<String, String> map = new HashMap<>(); for (String s : query.split("&")) { String[] s1 = s.split("="); map.put(s1[0], s1[1]); } return map; } }
|
关于ConcurrentHashMap:
ConcurrentHashMap是HashMap的升级版,HashMap是线程不安全的,而ConcurrentHashMap是线程安全。
session中参数 在前端中就是类似get的params传递 :ws://localhost:8081/msg/user?name=FSAN
建立连接时以用户名存储
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| package com.fsan.socket;
import com.fsan.stateEnum.WsRespResultEnum; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.AbstractWebSocketHandler;
import java.util.HashMap;
@Slf4j @Component public class WsService extends AbstractWebSocketHandler {
@Override public void afterConnectionEstablished(WebSocketSession session) { HashMap<String, String> queryToMap = WsSocketManage.getQueryToMap(session); String name = queryToMap.get("name"); WsSocketManage.add(name, session); log.info(name + "建立ws连接"); log.info("当前在线人数:" + WsSocketManage.getUserNum()); }
@Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) { String name = WsSocketManage.getQueryToMap(session).get("name"); WsSocketManage.removeAndClose(name); log.info(name + "关闭ws连接"); log.info("当前在线人数:" + WsSocketManage.getUserNum()); }
@Override protected void handleTextMessage(WebSocketSession session, TextMessage message) { String payload = message.getPayload(); log.info("收到消息:" + payload); } }
|
html页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>当前状态:<span id="state">未连接</span></p> <p>当前在线人数:<span id="userNum"></span></p> <button onclick="createConn()">建立连接</button> <input type="text" id="name" placeholder="登录名"> <input type="text" id="inputVal" placeholder="发送消息"> <button onclick="sendMsg()">发送</button> </body>
<script> let socket;
const valid = (name) => { if (!name) { alert("登录名不可为空!") return false; } return true; }
const sendMsg = () => { const name = document.getElementById("name").value if (!valid(name)) return socket.send(document.getElementById("inputVal").value) } const createConn = () => { const name = document.getElementById("name").value if (!valid(name)) return socket = new WebSocket(`ws: } </script> </html>
|
这样对已连接的session对象进行存储之后,就可以进行进一步的通知操作了
封装websocket的返回消息
因为socket消息的发送并不是向axios一样,axios前端可以接收指定业务的返回情况,而socket接收返回时不知道是什么业务,所以包装类根据参数数量划分,枚举类根据业务种类划分(越细越好)
包装类
创建 entity > WsRespResult.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| package com.fsan.entity;
import com.alibaba.fastjson.JSON; import com.fsan.stateEnum.WsRespResultEnum; import com.fsan.socket.WsSocketManage; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.web.socket.TextMessage;
@Data @AllArgsConstructor @NoArgsConstructor public class WsRespResult { private Integer code; private Object content; private Integer userNum; private String formName;
public static TextMessage send(WsRespResultEnum respResultEnum) { WsRespResult respResult = new WsRespResult(); respResult.setCode(respResultEnum.getCode()); respResult.setContent(respResultEnum.getContent()); respResult.setUserNum(WsSocketManage.getUserNum()); return new TextMessage(JSON.toJSONString(respResult)); }
public static TextMessage send(WsRespResultEnum respResultEnum, String formName) { WsRespResult respResult = new WsRespResult(); respResult.setCode(respResultEnum.getCode()); respResult.setContent(respResultEnum.getContent()); respResult.setFormName(formName); respResult.setUserNum(WsSocketManage.getUserNum()); return new TextMessage(JSON.toJSONString(respResult)); }
public static TextMessage send(WsRespResultEnum respResultEnum, String formName, String content) { WsRespResult respResult = new WsRespResult(); respResult.setCode(respResultEnum.getCode()); respResult.setContent(content); respResult.setFormName(formName); respResult.setUserNum(WsSocketManage.getUserNum()); return new TextMessage(JSON.toJSONString(respResult)); } }
|
发送给自己和发送给对方的区别就是要不要带上发送者的用户名
枚举类
创建 stateEnum > WsRespResultEnum.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package com.fsan.stateEnum;
public enum WsRespResultEnum { CONN_SUCCESS(2000, "连接成功"), SENDMSG_SUCCESS(2001, "发送消息成功"), USERNUM_UPDATE(2002, "广播所有更新在线人数"), ACCEPT_FORMTOALL(2003, "接收到广播消息"), ACCEPT_FORMTOUSER(2004, "接收到个人消息");
private Integer code; private Object content;
WsRespResultEnum(Integer code, Object content) { this.code = code; this.content = content; }
public Integer getCode() { return code; }
public Object getContent() { return content; } }
|
使用广播实现实时在线人数
更改自己连接状态和实时在线人数
管理类新增方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| package com.fsan.socket;
import com.alibaba.fastjson.JSON; import com.fsan.entity.WsRespResult; import com.fsan.stateEnum.WsRespResultEnum; import lombok.extern.slf4j.Slf4j; import org.springframework.util.StringUtils; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession;
import java.io.IOException; import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap;
@Slf4j public class WsSocketManage { private static ConcurrentHashMap<String, WebSocketSession> wsSession = new ConcurrentHashMap<>();
static void sendMsg(WebSocketSession session, WsRespResultEnum wsRespResultEnum) { try { session.sendMessage(WsRespResult.send(wsRespResultEnum)); } catch (IOException e) { e.printStackTrace(); } }
static void sendMsg(WebSocketSession sessionTo, WebSocketSession sessionForm, WsRespResultEnum wsRespResultEnum) { try { HashMap<String, String> queryToMap = getQueryToMap(sessionForm); String formName = queryToMap.get("name"); sessionTo.sendMessage(WsRespResult.send(wsRespResultEnum, formName)); } catch (IOException e) { e.printStackTrace(); } }
static void updateUserNum(WebSocketSession webSocketSession) { wsSession.forEach((s, session) -> sendMsg(session, webSocketSession, WsRespResultEnum.USERNUM_UPDATE)); } }
|
服务类在建立连接之后更新状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
@Override public void afterConnectionEstablished(WebSocketSession session) { HashMap<String, String> queryToMap = WsSocketManage.getQueryToMap(session); String name = queryToMap.get("name"); WsSocketManage.add(name, session); log.info(name + "建立ws连接"); log.info("当前在线人数:" + WsSocketManage.getUserNum()); WsSocketManage.sendMsg(session, WsRespResultEnum.CONN_SUCCESS); WsSocketManage.updateUserNum(session); }
|
服务类在断开连接后更新人数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
@Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) { String name = WsSocketManage.getQueryToMap(session).get("name"); WsSocketManage.removeAndClose(name); WsSocketManage.updateUserNum(session); log.info(name + "关闭ws连接"); log.info("当前在线人数:" + WsSocketManage.getUserNum()); }
|
html页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>当前状态:<span id="state">未连接</span></p> <p>当前在线人数:<span id="userNum"></span></p> <button onclick="createConn()">建立连接</button> <input type="text" id="name" placeholder="登录名"> <input type="text" id="inputVal" placeholder="发送消息"> <button onclick="sendMsg()">发送</button> </body>
<script> let socket;
const valid = (name) => { if (!name) { alert("登录名不可为空!") return false; } return true; }
const sendMsg = () => { const name = document.getElementById("name").value if (!valid(name)) return socket.send(document.getElementById("inputVal").value) } const createConn = () => { const name = document.getElementById("name").value if (!valid(name)) return socket = new WebSocket(`ws://localhost:8081/ws/user?name=${name}`) socket.onmessage = (data) => { const {userNum, code} = JSON.parse(data.data) switch (code) { case 2000: document.getElementById("state").innerText = '已连接!' break; case 2001: alert('消息已发送!') break; case 2002: document.getElementById("userNum").innerText = userNum break; } } } </script> </html>
|
群体广播和指定人发送
管理类增加方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
|
static void sendMsg(WebSocketSession sessionTo, WebSocketSession sessionForm, WsRespResultEnum wsRespResultEnum, String content) { try { HashMap<String, String> queryToMap = getQueryToMap(sessionForm); String formName = queryToMap.get("name"); sessionTo.sendMessage(WsRespResult.send(wsRespResultEnum, formName, content));
sessionForm.sendMessage(WsRespResult.send(WsRespResultEnum.SENDMSG_SUCCESS)); } catch (IOException e) { e.printStackTrace(); } }
static void sendToAll(WebSocketSession webSocketSession, String content) { wsSession.forEach((s, session) -> { String name = getQueryToMap(webSocketSession).get("name"); if (!s.equals(name)) { sendMsg(session, webSocketSession, WsRespResultEnum.ACCEPT_FORMTOALL, content); } }); }
static void sendToUser(WebSocketSession webSocketSession, String name, String content) { WebSocketSession toSession = get(name); sendMsg(toSession, webSocketSession, WsRespResultEnum.ACCEPT_FORMTOUSER, content); }
|
服务类接收消息时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
@Override protected void handleTextMessage(WebSocketSession session, TextMessage message) { String payload = message.getPayload(); Map parse = (Map) JSON.parse(payload); log.info("收到消息:" + parse); String state = (String) parse.get("state"); String content = (String) parse.get("content"); switch (state) { case "1": String toName = (String) parse.get("toName"); WsSocketManage.sendToUser(session, toName, content); break; case "2": WsSocketManage.sendToAll(session, content); break; } }
|
前端传递格式:
1 2 3 4 5 6 7 8
| { state: '', content: '', toName: '' }
|
html页面
增加指定发送人输入框,增加接收广播消息和指定消息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> <p>当前状态:<span id="state">未连接</span></p> <button onclick="createConn()">建立连接</button> </div> <p>当前在线人数:<span id="userNum"></span></p> <div> <input type="text" id="name" placeholder="用户名"> </div> <input type="text" id="inputVal" placeholder="发送消息"> <button onclick="sendMsgToAll()">发送广播</button> <input type="text" id="sendToName" placeholder="发送给"> <button onclick="sendMsg()">发送给个人</button> <div id="sendContent"></div> </body>
<script> let socket;
const valid = (name) => { if (!name) { alert("登录名不可为空!") return false; } return true; }
const sendMsgToAll = () => { const name = document.getElementById("name").value if (!valid(name)) return socket.send(JSON.stringify({ state: '2', content: document.getElementById("inputVal").value })) }
const sendMsg = () => { const name = document.getElementById("name").value if (!valid(name)) return socket.send(JSON.stringify({ state: '1', content: document.getElementById("inputVal").value, toName: document.getElementById("sendToName").value })) } const createConn = () => { let p let jsonContent const name = document.getElementById("name").value if (!valid(name)) return socket = new WebSocket(`ws://localhost:8081/ws/user?name=${name}`) socket.onmessage = (data) => { const jsonData = JSON.parse(data.data) switch (jsonData.code) { case 2000: document.getElementById("state").innerText = '已连接!' break; case 2001: alert('消息已发送!') break; case 2002: document.getElementById("userNum").innerText = jsonData.userNum break; case 2003: p = document.createElement("p") jsonContent = JSON.parse(jsonData.content) p.innerText = `收到来自${jsonData.formName}广播:${jsonContent}` document.getElementById("sendContent").appendChild(p) break; case 2004: p = document.createElement("p") jsonContent = JSON.parse(jsonData.content) p.innerText = `收到来自${jsonData.formName}私信:${jsonContent}` document.getElementById("sendContent").appendChild(p) break; } } } </script> </html>
|
后端发送广播和消息数据格式:
1 2 3 4 5 6 7 8 9 10
| { code: '', content: '', formName: '', userNum: '' }
|
完整代码
服务类
socket > WsService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| package com.fsan.socket;
import com.alibaba.fastjson.JSON; import com.fsan.stateEnum.WsRespResultEnum; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.AbstractWebSocketHandler;
import java.util.HashMap; import java.util.Map;
@Slf4j @Component public class WsService extends AbstractWebSocketHandler {
@Override public void afterConnectionEstablished(WebSocketSession session) { HashMap<String, String> queryToMap = WsSocketManage.getQueryToMap(session); String name = queryToMap.get("name"); WsSocketManage.add(name, session); log.info(name + "建立ws连接"); log.info("当前在线人数:" + WsSocketManage.getUserNum()); WsSocketManage.sendMsg(session, WsRespResultEnum.CONN_SUCCESS); WsSocketManage.updateUserNum(session); }
@Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) { String name = WsSocketManage.getQueryToMap(session).get("name"); WsSocketManage.removeAndClose(name); WsSocketManage.updateUserNum(session); log.info(name + "关闭ws连接"); log.info("当前在线人数:" + WsSocketManage.getUserNum()); }
@Override protected void handleTextMessage(WebSocketSession session, TextMessage message) { String payload = message.getPayload(); Map parse = (Map) JSON.parse(payload); log.info("收到消息:" + parse); String state = (String) parse.get("state"); String content = (String) parse.get("content"); switch (state) { case "1": String toName = (String) parse.get("toName"); WsSocketManage.sendToUser(session, toName, content); break; case "2": WsSocketManage.sendToAll(session, content); break; } } }
|
管理类
scoket > WsSocketManage.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
| package com.fsan.socket;
import com.alibaba.fastjson.JSON; import com.fsan.entity.WsRespResult; import com.fsan.stateEnum.WsRespResultEnum; import lombok.extern.slf4j.Slf4j; import org.springframework.util.StringUtils; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession;
import java.io.IOException; import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap;
@Slf4j public class WsSocketManage { private static ConcurrentHashMap<String, WebSocketSession> wsSession = new ConcurrentHashMap<>();
static void add(String key, WebSocketSession session) { wsSession.put(key, session); }
static WebSocketSession remove(String key) { return wsSession.remove(key); }
static void removeAndClose(String key) { WebSocketSession remove = wsSession.remove(key); if (!StringUtils.isEmpty(remove)) { try { remove.close(); } catch (IOException e) { e.printStackTrace(); } }
}
static WebSocketSession get(String key) { return wsSession.get(key); }
static void sendMsg(WebSocketSession session, WsRespResultEnum wsRespResultEnum) { try { session.sendMessage(WsRespResult.send(wsRespResultEnum)); } catch (IOException e) { e.printStackTrace(); } }
static void sendMsg(WebSocketSession sessionTo, WebSocketSession sessionForm, WsRespResultEnum wsRespResultEnum) { try { HashMap<String, String> queryToMap = getQueryToMap(sessionForm); String formName = queryToMap.get("name"); sessionTo.sendMessage(WsRespResult.send(wsRespResultEnum, formName)); } catch (IOException e) { e.printStackTrace(); } }
static void sendMsg(WebSocketSession sessionTo, WebSocketSession sessionForm, WsRespResultEnum wsRespResultEnum, String content) { try { HashMap<String, String> queryToMap = getQueryToMap(sessionForm); String formName = queryToMap.get("name"); sessionTo.sendMessage(WsRespResult.send(wsRespResultEnum, formName, content));
sessionForm.sendMessage(WsRespResult.send(WsRespResultEnum.SENDMSG_SUCCESS)); } catch (IOException e) { e.printStackTrace(); } }
public static Integer getUserNum() { return wsSession.size(); }
static HashMap<String, String> getQueryToMap(WebSocketSession session) { String query = session.getUri().getQuery(); HashMap<String, String> map = new HashMap<>(); for (String s : query.split("&")) { String[] s1 = s.split("="); map.put(s1[0], s1[1]); } return map; }
static void updateUserNum(WebSocketSession webSocketSession) { wsSession.forEach((s, session) -> sendMsg(session, webSocketSession, WsRespResultEnum.USERNUM_UPDATE)); }
static void sendToAll(WebSocketSession webSocketSession, String content) { wsSession.forEach((s, session) -> { String name = getQueryToMap(webSocketSession).get("name"); if (!s.equals(name)) { sendMsg(session, webSocketSession, WsRespResultEnum.ACCEPT_FORMTOALL, content); } }); }
static void sendToUser(WebSocketSession webSocketSession, String name, String content) { WebSocketSession toSession = get(name); sendMsg(toSession, webSocketSession, WsRespResultEnum.ACCEPT_FORMTOUSER, content); } }
|
返回包装类
entity > WsRespResult.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| package com.fsan.entity;
import com.alibaba.fastjson.JSON; import com.fsan.stateEnum.WsRespResultEnum; import com.fsan.socket.WsSocketManage; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.web.socket.TextMessage;
@Data @AllArgsConstructor @NoArgsConstructor public class WsRespResult { private Integer code; private Object content; private Integer userNum; private String formName;
public static TextMessage send(WsRespResultEnum respResultEnum) { WsRespResult respResult = new WsRespResult(); respResult.setCode(respResultEnum.getCode()); respResult.setContent(respResultEnum.getContent()); respResult.setUserNum(WsSocketManage.getUserNum()); return new TextMessage(JSON.toJSONString(respResult)); }
public static TextMessage send(WsRespResultEnum respResultEnum, String formName) { WsRespResult respResult = new WsRespResult(); respResult.setCode(respResultEnum.getCode()); respResult.setContent(respResultEnum.getContent()); respResult.setFormName(formName); respResult.setUserNum(WsSocketManage.getUserNum()); return new TextMessage(JSON.toJSONString(respResult)); }
public static TextMessage send(WsRespResultEnum respResultEnum, String formName, String content) { WsRespResult respResult = new WsRespResult(); respResult.setCode(respResultEnum.getCode()); respResult.setContent(content); respResult.setFormName(formName); respResult.setUserNum(WsSocketManage.getUserNum()); return new TextMessage(JSON.toJSONString(respResult)); } }
|
状态枚举类
stateEnum > WsRespResultEnum.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package com.fsan.stateEnum;
public enum WsRespResultEnum { CONN_SUCCESS(2000, "连接成功"), SENDMSG_SUCCESS(2001, "发送消息成功"), USERNUM_UPDATE(2002, "广播所有更新在线人数"), ACCEPT_FORMTOALL(2003, "接收到广播消息"), ACCEPT_FORMTOUSER(2004, "接收到个人消息");
private Integer code; private Object content;
WsRespResultEnum(Integer code, Object content) { this.code = code; this.content = content; }
public Integer getCode() { return code; }
public Object getContent() { return content; } }
|
socket配置类
config > SocketConfig.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| package com.fsan.config;
import com.fsan.socket.WsService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration @EnableWebSocket public class SocketConfig implements WebSocketConfigurer {
@Autowired private WsService wsService;
@Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry .addHandler(wsService, "/ws/user") .setAllowedOrigins("*");
} }
|
html页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> <p>当前状态:<span id="state">未连接</span></p> <button onclick="createConn()">建立连接</button> </div> <p>当前在线人数:<span id="userNum"></span></p> <div> <input type="text" id="name" placeholder="用户名"> </div> <input type="text" id="inputVal" placeholder="发送消息"> <button onclick="sendMsgToAll()">发送广播</button> <input type="text" id="sendToName" placeholder="发送给"> <button onclick="sendMsg()">发送给个人</button> <div id="sendContent"></div> </body>
<script> let socket;
const valid = (name) => { if (!name) { alert("登录名不可为空!") return false; } return true; }
const sendMsgToAll = () => { const name = document.getElementById("name").value if (!valid(name)) return socket.send(JSON.stringify({ state: '2', content: document.getElementById("inputVal").value })) }
const sendMsg = () => { const name = document.getElementById("name").value if (!valid(name)) return socket.send(JSON.stringify({ state: '1', content: document.getElementById("inputVal").value, toName: document.getElementById("sendToName").value })) } const createConn = () => { let p let jsonContent const name = document.getElementById("name").value if (!valid(name)) return socket = new WebSocket(`ws://localhost:8081/ws/user?name=${name}`) socket.onmessage = (data) => { const jsonData = JSON.parse(data.data) console.log(jsonData); switch (jsonData.code) { case 2000: document.getElementById("state").innerText = '已连接!' break; case 2001: alert('消息已发送!') break; case 2002: document.getElementById("userNum").innerText = jsonData.userNum break; case 2003: p = document.createElement("p") jsonContent = JSON.parse(jsonData.content) p.innerText = `收到来自${jsonData.formName}广播:${jsonContent}` document.getElementById("sendContent").appendChild(p) break; case 2004: p = document.createElement("p") jsonContent = JSON.parse(jsonData.content) p.innerText = `收到来自${jsonData.formName}私信:${jsonContent}` document.getElementById("sendContent").appendChild(p) break; } } } </script> </html>
|
最后说明
封装的比较烂,轻喷