一、定义websocket请求拦截器( 主要是这一步 )
@Component
@Slf4j
public class BootWebSocketInterceptor extends HttpSessionHandshakeInterceptor {
private static String socketUrl = "/ws";
private static String tokenHeader = "socketToken";
//集成 HttpSessionHandshakeInterceptor ,重写它的握手前和握手后两个方法
//握手前
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest();
//获取请求路径,这个请求路径我们可以自己定义吗(即,请求哪个路径表示要进行websocket请求连接)
String contextPath = servletRequest.getRequestURI();
//判断这个请求路径是不是我们定义的建立websocket请求的路径
if (Objects.equals(contextPath, socketUrl)) {
//相等,表示这个请求是需要建立websocket连接的
String token = servletRequest.getParameter(tokenHeader);//获取请求token
//进行token相关的校验
//token是否为空
if (StrUtil.isBlank(token)) {
return false; //返回false,表示握手不成功
}
// 验证令牌有效性
boolean tokenExpired = *****;//自己项目的校验方法
if (tokenExpired) {
return false;
}
//有需要的业务可以在这里加
Integer uid = *****;//调用自己业务的解析token的方法拿到用户id
log.info("握手成功:" + uid);
//将参数放到attributes,供后面使用
attributes.put(SocketConstants.USER_ID, uid);
return super.beforeHandshake(request, response, wsHandler, attributes);
}
return false;
}
// 握手后
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler wsHandler, Exception ex) {
super.afterHandshake(request, response, wsHandler, ex);
}
二、定义websocket处理器
/**
* 聊天消息的 socket 处理
*/
@Slf4j
@Component
public class ChatWebSocketHandler extends TextWebSocketHandler {
//定理一个map来缓存websocket的Session
private static final ConcurrentHashMap<Integer, List<WebSocketSession>> POOL_SESSION = new ConcurrentHashMap<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) {
//获取第一步中解析的uid
Object uid = session.getAttributes().get(SocketConstants.USER_ID);
if (uid != null && lId != null) {
Integer liveId = Integer.valueOf((String) lId);
log.info("连接成功:" + uid + ",当前总用户数:" + POOL_SESSION.size());
//这里写建立成功之后需要的业务
}
}
/**
* 接收消息事件
*/
@SneakyThrows
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) {
// 获得客户端传来的消息
String payload = message.getPayload();
log.info("server 接收到客户端消息 {}", payload);
session.sendMessage(new TextMessage("ok"));
}
/**
* socket 断开连接时
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
//断开连接的业务代码
}
public PushResultVo sendMsg(Integer uid, Dict transmission) {
//定义发送消息的方法
//提供相关参数,找到需要接收信息的WebSocketSession
session.sendMessage(new TextMessage(JSONUtil.toJsonStr(transmission)));//发送消息
}
}
三、定位websocket配置类
@Configuration
@EnableWebSocket
@RequiredArgsConstructor
public class WebSocketConfig implements WebSocketConfigurer {
private final ChatWebSocketHandler chatWebSocketHandler;
private final BootWebSocketInterceptor bootWebSocketInterceptor;
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
//注册请求拦截器、处理器
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
webSocketHandlerRegistry
.addHandler(chatWebSocketHandler, "/ws") //对这个路径(即我们定义的websocket的请求路径)进行拦截处理
.addInterceptors(bootWebSocketInterceptor)
.setAllowedOrigins("*");
}
}