WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端
创建Spring boot项目,添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
WebSocketConfig,启用websocket支持
package com.example.websocket.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* WebSocketConfig
*
* @author hcf
* @date 2022/1/6 17:59
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
WebSocketServer
websocket 和 socket 类似,有客户端和服务端,客户端就是pc、app等,服务端就是后端。因为 WebSocket 是类似客户端服务端的形式(采用ws协议)
所以 WebSocketServer 其实就相当于一个 ws 协议的 Controller,直接使用注解@ServerEndpoint 和 @Component启用即可
package com.example.websocket.server;
import com.example.websocket.util.WebSocketUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Date;
import java.util.Objects;
/**
* WebSocketServer
*
* @author hcf
* @date 2022/1/6 17:57
*/
@Component
@ServerEndpoint(value = "/websocket/{appNo}")
public class WebSocketServer {
private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketServer.class);
@OnOpen
public void onOpen(@PathParam("appNo") String appNo, Session session) {
LOGGER.info("用户【{}】于 {} 时间,与服务器建立 websocket 连接!", appNo, new Date());
WebSocketUtil.addSession(appNo, session);
}
@OnClose
public void onClose(@PathParam("appNo") String appNo) {
LOGGER.info("用户【{}】于 {} 时间,与服务器断开 websocket 连接!", appNo, new Date());
WebSocketUtil.remoteSession(appNo);
}
@OnMessage
public void onMessage(@PathParam("appNo") String appNo, String message) {
LOGGER.info("服务器于 {} 时间,对用户【{}】发送消息,消息内容:{}", new Date(), appNo, message);
Session session = WebSocketUtil.ONLINE_SESSION.get(appNo);
if (Objects.isNull(session)) {
LOGGER.info("服务器和用户【{}】之间的链接已断开", appNo);
return;
}
Boolean success = WebSocketUtil.sendMessage(appNo, session, message);
LOGGER.info("客户端向服务端发送消息结果:{}", success);
}
@OnError
public void onError(Session session, Throwable throwable) {
LOGGER.error("服务器和用户之间的链接产生异常,异常原因:{}", throwable.getMessage(), throwable);
try {
session.close();
} catch (IOException e) {
LOGGER.error("断开服务器和用户之间的链接产生异常,异常原因:{}", e.getMessage(), e);
}
}
}
package com.example.websocket.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.websocket.Session;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
/**
* WebSocketUtil
*
* @author hcf
* @date 2022/1/6 18:01
*/
public class WebSocketUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketUtil.class);
public static final Map<String, Session> ONLINE_SESSION = new ConcurrentHashMap<>();
public static void addSession(String userKey, Session session) {
ONLINE_SESSION.put(userKey, session);
}
public static void remoteSession(String userKey) {
ONLINE_SESSION.remove(userKey);
}
public static Boolean sendMessage(String appNo, Session session, String message) {
// getAsyncRemote() 和 getBasicRemote() 异步与同步
Future<Void> future = session.getAsyncRemote().sendText(message);
try {
future.get(3, TimeUnit.SECONDS);
} catch (Exception e) {
LOGGER.error("服务器发送消息给客户端 【{}】 下的用户【{}】,传输失败。消息内容为:{},", session.getId(), appNo, message);
return false;
}
LOGGER.info("服务器发送消息给客户端 【{}】 下的用户【{}】,传输结果为:{}。消息内容为:{}", session.getId(), appNo, message, future.isDone());
return future.isDone();
}
}
启动项目进行测试
可以使用 http://www.websocket-test.com/ 测试网址