基于SpringMVC搭建WebSocker
SpringMVC的搭建请参考我以前的文章
1.添加pom依赖
本文使用最新的Spring6,一些依赖的问题需要自行解决
<!-- 添加socket支持 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>6.0.10</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>6.0.10</version>
</dependency>
2.添加Socket Handler,用于处理Socker消息的请求和发送。
package cn.coreqi.handler;
import org.springframework.web.socket.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* 创建WebSocketHandler的实现类
* Spring提供了AbstractWebSocketHandler类、TextWebSocketHandler类、BinaryWebSocketHandler类,看自己需求进行继承。
* 该类主要是用来处理消息的接收和发送
*/
public class MyWebSocketHandler implements WebSocketHandler {
//保存用户链接
private static ConcurrentHashMap<String, WebSocketSession> users = new ConcurrentHashMap<String, WebSocketSession>();
//连接就绪时
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
users.put(session.getId(), session);
}
//处理消息
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
System.err.println(session + "---->" + message + ":"+ message.getPayload().toString());
// message.getPayload().toString() 获取消息具体内容
String msg = message.getPayload().toString();
System.out.println("handleMessage......." + msg + "..........." + msg);
// 处理消息 msgContent消息内容
TextMessage textMessage = new TextMessage(msg, true);
//session.sendMessage(message);
// 调用方法(发送消息给所有人)
sendMsgToAllUsers(textMessage);
}
//处理传输时异常
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
if(session.isOpen()){
session.close();
}
System.err.println("websocket chat connection closed......");
users.remove(session.getId());
}
//关闭连接时
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
System.out.println("用户: " + session.getRemoteAddress() + " is leaving, because:" + closeStatus);
users.remove(session.getId());
}
//是否支持分包
@Override
public boolean supportsPartialMessages() {
return false;
}
//给所有用户发送消息
public void sendMsgToAllUsers(WebSocketMessage<?> message) throws Exception{
for (WebSocketSession user : users.values()) {
user.sendMessage(message);
}
}
}
3.添加Socket Interceptor,用于拦截握手前和握手后的一些操作
package cn.coreqi.interceptor;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
import java.util.Map;
/**
* 握手拦截器,继承HttpSessionHandshakeInterceptor类,也可以实现HandshakeInterceptor接口
* 这个的主要作用是可以在握手前做一些事,把所需要的东西放入到attributes里面,然后可以在WebSocketHandler的session中取到相应的值,具体可参考HttpSessionHandshakeInterceptor
*/
public class MyHandshakeInterceptor extends HttpSessionHandshakeInterceptor {
/**
* 在调用handler前处理方法。常用在注册用户信息,绑定WebSocketSession,在handler里根据用户信息获取WebSocketSession发送消息。
* @param request
* @param response
* @param wsHandler
* @param attributes
* @return
* @throws Exception
*/
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
System.out.println("++++++++++++++++ HandshakeInterceptor: beforeHandshake ++++++++++++++" + attributes);
return super.beforeHandshake(request, response, wsHandler, attributes);
}
//握手后
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) {
System.out.println("++++++++++++++++ HandshakeInterceptor: afterHandshake ++++++++++++++");
super.afterHandshake(request, response, wsHandler, ex);
}
}
4.添加WebSocker配置类,用于指定路由与处理类及拦截器的映射关系
package cn.coreqi.config;
import cn.coreqi.handler.MyWebSocketHandler;
import cn.coreqi.interceptor.MyHandshakeInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.server.HandshakeInterceptor;
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
/**
* 配置websocket入口,允许访问的域、注册Handler、SockJs支持和拦截器
* @param registry
*/
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
//允许连接的域,只能以http或https开头
String[] allowsOrigins = {"http://localhost:8080"};
//前台 可以使用websocket环境
//registry.addHandler注册和路由的功能,当客户端发起websocket连接,把/path交给对应的handler处理
registry.addHandler(myWebSocketHandler(),"/coreqi")
.addInterceptors(myInterceptor())
.setAllowedOrigins(allowsOrigins);
//前台 不可以使用websocket环境,则使用sockjs进行模拟连接
registry.addHandler(myWebSocketHandler(), "/sockjs/coreqi") //配置路径对应的处理类
.addInterceptors(myInterceptor()) //配置拦截器
.setAllowedOrigins(allowsOrigins) //允许连接的域
.withSockJS(); //提供SockJs支持
}
// websocket 拦截器
@Bean
public HandshakeInterceptor myInterceptor(){
return new MyHandshakeInterceptor();
}
// websocket 处理类
@Bean
public WebSocketHandler myWebSocketHandler(){
return new MyWebSocketHandler();
}
@Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
container.setMaxTextMessageBufferSize(8192);
container.setMaxBinaryMessageBufferSize(8192);
return container;
}
}