导包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
创建MyWebSocketHandler
@Component
public class MyWebSocketHandler implements WebSocketHandler {
private static final List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
sessions.add(session);
// System.out.println(String.format("用户%s已加入,当前%s个用户在线", session.getId(),sessions.size()));
System.out.println(String.format("用户%s已加入,当前%s个用户在线", session.getAttributes().get("token"),sessions.size()));
}
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
System.out.println(String.format("收到用户%s消息:%s", session.getId(), message.getPayload()));
for (WebSocketSession s : sessions) {
if (!session.equals(s)) {
s.sendMessage(new TextMessage((CharSequence) message.getPayload()));
}
}
}
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
System.out.println("连接出错");
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
sessions.remove(session);
System.out.println(String.format("用户%s已断开,当前%s个用户在线", session.getId(),sessions.size()));
}
@Override
public boolean supportsPartialMessages() {
return false;
}
}
开启配置
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
private static final String PROTOCOL_KEY = "Sec-WebSocket-Protocol";
@Resource
private MyWebSocketHandler myWebSocketHandler;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myWebSocketHandler, "/default")
.setAllowedOrigins("*")
.addInterceptors(new HandshakeInterceptor() {
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
//参数获取方式一
UriComponents uriComponents = UriComponentsBuilder.fromUri(request.getURI()).build();
String queryToken = uriComponents.getQueryParams().getFirst("token");
if (!StringUtils.hasLength(queryToken)) {
attributes.put("token", queryToken);
}
//参数获取方式二
List<String> payload = request.getHeaders().get(PROTOCOL_KEY);
if (!ObjectUtils.isEmpty(payload)) {
attributes.put("token", payload.get(0));
}
return true;
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
List<String> payload = request.getHeaders().get(PROTOCOL_KEY);
if (!ObjectUtils.isEmpty(payload)) {
response.getHeaders().put(PROTOCOL_KEY, payload);
}
}
});
}
}
说明:上面两种参数获取方式对应客户端如下
const ws = new WebSocket("ws://localhost:8090/myHandler?token=465", ["test-token"]);
let timer = null
const pingStep = 20000
const stateArr = [
{ key: 0, value: '正在连接中' },
{ key: 1, value: '已经连接并且可以通讯' },
{ key: 2, value: '连接正在关闭' },
{ key: 3, value: '连接已关闭或者没有连接成功' },
]
const closeWs = () => {
ws.close()
clearInterval(timer)
}
ws.onopen = function(event) {
timer = window.setInterval(() => {
Logger.log(`每隔${pingStep / 1000}秒钟发送一次心跳`)
const ping = { type: 'ping' }
sendMsg(JSON.stringify(ping))
}, pingStep)
window.onbeforeunload = function () {
closeWs()
}
console.log("WebSocket连接已建立");
};
ws.onmessage = function(event) {
console.log("收到消息:" + event.data);
};
ws.onerror = function(event) {
console.log("WebSocket出错:" + event);
};
ws.onclose = function(event) {
console.log("WebSocket连接已关闭:" + event.code + " - " + event.reason);
};