客户端测试工具:coolaf.com/tool/chattest。
可以打开两个窗口,模拟用户1
与用户2
聊天,并以userId
来区分不同的用户(客户端的唯一标识
)。
localhost:8080/webSocket?userId=1
localhost:8080/webSocket?userId=2
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
创建websocket服务端:
/socket/DemoWebSocketHandler.java
@Component
public class DemoWebSocketHandler implements WebSocketHandler{
// key 用户(客户端标识)value 会话,用来存放每个客户端对应的WebSocketSession对象
private final Map<Integer, WebSocketSession> webSocketSeesionMap = new HashMap<>();
// websocket连接成功时触发
@Override
public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
// 当我们和客户端建立连接之后,我们可以得到一个会话ID webSocketSession.getId()
// 获取用户ID(在这里是不能获取url参数,要通过拦截器去获取url参数)
Map<Striing, Object> attributes = webSocketSession.getAttributes();// 取得拦截器里的那个map
Integer userId = attributes.get("userId");
// 接下来把这个userId当成一个key,然后把webSocketSession当成一个value,存到本类的成员变量map集合里
webSocketSeesionMap.put(userId, webSocketSession);
}
// 收到客户端消息时触发
@Override
public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) throws Exception {
// 获取来自客户端的消息
String message = String.valueOf(webSocketMessage.getPayload());
// 获取当前url的用户ID
Map<String, Object> attributes = webSocketSession.getAttributes();// 取得拦截器里的那个map
Integer urlUserId = attributes.get("userId");
// 接下来可以让用户1给用户2发送一条消息
// 遍历webSocketSeesionMap
webSocketSeesionMap.forEach((userId,value) => {
// 判断当前用户ID是不是传递突来的用户ID
if (userId.equals(urlUserId)) {
// 如果当前用户ID是他自己(url也是他)的话
// 那就直接跳过
}else {
// 如果不是,把客户端传递过来的Message干到参数里面
value.sendMessage(new TextMessage(message));
}
});
// 向客户端发送消息
//webSocketSession.sendMessage(new TextMessage("你好"));
}
// websocket连接发生错误时触发
@Override
public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {
// 这里可以拿到异常对象throwable
}
// websocket连接关闭时触发
@Override
public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
// 一般在连接关闭时,就需要把这个会话从缓存里面移除掉
// 获取当前url的用户ID
Map<String, Object> attributes = webSocketSession.getAttributes();// 取得拦截器里的那个map
Integer urlUserId = attributes.get("userId");
webSocketSessionMap.remove(urlUserId);// 移除当前会话
}
@Override
public boolean supportsPartialMessages() {
return false;
}
}
接着对websocket服务端做配置:
/websocket/WebSocketConfig.java
@Configuration
@EnableWebSocket // 表示开启服务端websocket
public class WebSocketConfig imlements WebSocketConfigurer{
@Resocure
private DemoWebSocketHandler demoWebSocketHandler;
@Resource
private WebSocketInterceptor webSocketInterceptor;// 拦截器
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
// 在这里对websocket做一些配置
webSocketHandlerRegistry.addHandler(demoWebSocketHandler, "/websocket")// 添加一个websocket处理器,websocket链接地址。
.addInterceptors(webSocketInterceptor)// 可以传递若干个拦截器
.setAllowedOrigins("*");// 允许跨域访问
}
}
/webSocket/WebSocketInterceptor.java
@Component
public class WebSocketInterceptor extends HttpSessionHandShackInterceptor {
// 在webSocket连接之前调用
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> atributes) throws Exception {
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletServerHttpRequest = (ServletServerHttpRequest)request;
ServletRequest servletRequest = servletServerHttpRequest.getServletRequest();
Integer userId = Integer.valueOf(servletRequest.getParameter("userId"));
// 把获取的参数放到map里面
attributes.put("userId", userId);
}
return super.beforeHandShake(request, response, wsHandler, attributes);
}
}
以上内容源于网络