拦截器:
package com.liaoxiang.websocket_demo.intercepter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* @auther Mr.Liao
* @date 2019/3/22 18:20
*/
public class HttpHandShakeInterceptor implements HandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
System.out.println("【HttpHandShakeInterceptor-beforeHandshake方法】");
ServletServerHttpRequest httpRequest = (ServletServerHttpRequest) request;
HttpServletRequest servletRequest = httpRequest.getServletRequest();
String sessionID = servletRequest.getSession().getId();
System.out.println("【SessionId】------>"+sessionID);
attributes.put("sessionID", sessionID);
return true;
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler wsHandler, Exception exception) {
System.out.println("【HttpHandShakeInterceptor-afterHandshake方法】");
}
}
package com.liaoxiang.websocket_demo.intercepter;
import com.liaoxiang.websocket_demo.controller.ChatRoomController;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptor;
/**
* @auther Mr.Liao
* @date 2019/3/22 19:43
*/
public class SocketChannelInterceptor implements ChannelInterceptor {
/**
* 在消息被实际发送到频道之前调用
*/
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
System.out.println("【SocketChannelInterceptor-preSend方法】");
return message;
}
/**
* 在消息被实际发送之后,立即调用
*/
@Override
public void postSend(Message<?> message, MessageChannel channel, boolean sent) {
System.out.println("【SocketChannelInterceptor-postSend方法】");
// 消息头访问器
StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(message);
if (headerAccessor.getCommand() == null) return;
String sessionID = headerAccessor.getSessionAttributes().get("sessionID").toString();
switch (headerAccessor.getCommand()){
case CONNECT:
// 连接成功的处理
connect(sessionID);
break;
case DISCONNECT:
// 断开连接后的处理
disconnect(sessionID);
break;
case SUBSCRIBE:
break;
case UNSUBSCRIBE:
break;
}
}
/**
* 连接成功
*/
private void connect(String sessionID){
System.out.println("【SocketChannelInterceptor-连接成功】");
}
/**
* 断开连接
*/
private void disconnect(String sessionID){
System.out.println("【SocketChannelInterceptor-断开连接】");
ChatRoomController.onlineUser.remove(sessionID);
}
/**
* 总会执行,不管是否有异常发生,一般用于资源清理
*/
@Override
public void afterSendCompletion(Message<?> message, MessageChannel channel, boolean sent, Exception ex) {
System.out.println("【SocketChannelInterceptor-afterSendCompletion方法】");
}
}
注册拦截器:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
/**
* 注册端点,发送或者订阅消息前,需要连接此端点
* @param registry
*/
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/endpoint-websocket") //端点名称
.addInterceptors(new HttpHandShakeInterceptor()) //注册Http拦截器
.setAllowedOrigins("*") // 跨域访问
.withSockJS(); // 使用sockJS协议
}
/**
* 配置消息代理
* enableSimpleBroker: 服务端推送消息给客户端的一个前缀
* SendTo("/topic/game_chat")
* setApplicationDestinationPrefixes: 客户端发送消息给服务端的前缀
* this.stompClient.send('/app/v1/chat',{},JSON.stringify({'content':msg}))
*/
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/game", "/chat", "/monitor","/topic");
registry.setApplicationDestinationPrefixes("/app");
}
/**
* 注册Channel拦截器
*/
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new SocketChannelInterceptor());
}
@Override
public void configureClientOutboundChannel(ChannelRegistration registration) {
registration.interceptors(new SocketChannelInterceptor());
}
}
监听器:
package com.liaoxiang.websocket_demo.listener;
import org.springframework.context.ApplicationListener;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.messaging.SessionConnectEvent;
/**
* @auther Mr.Liao
* @date 2019/3/22 15:41
*/
@Component
public class ConnectEventListener implements ApplicationListener<SessionConnectEvent> {
@Override
public void onApplicationEvent(SessionConnectEvent sessionConnectEvent) {
StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(sessionConnectEvent.getMessage());
System.out.println("【ConnectEventListener事件类型监听器】---->"+headerAccessor.getMessageType());
}
}
package com.liaoxiang.websocket_demo.listener;
import org.springframework.context.ApplicationListener;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.messaging.SessionSubscribeEvent;
import java.util.Objects;
/**
* @auther Mr.Liao
* @date 2019/3/22 15:41
*/
@Component
public class SubscribeEventListener implements ApplicationListener<SessionSubscribeEvent> {
/**
* 订阅消息触发事件,调用这个方法
* StompHeaderAccessor:简单消息传递协议中处理消息头的基类
* 通过这个类,可以获取消息类型(例如:发布订阅,建立连接断开连接), 会话id等
*/
@Override
public void onApplicationEvent(SessionSubscribeEvent sessionSubscribeEvent) {
StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(sessionSubscribeEvent.getMessage());
System.out.println("【SubscribeEventListener订阅事件监听器】---->"+headerAccessor.getMessageType());
System.out.println("【SubscribeEventListener订阅事件监听器: SessionID】---->"+ Objects.requireNonNull(headerAccessor.
getSessionAttributes()).get("sessionID"));
}
}
建立连接:
【HttpHandShakeInterceptor-beforeHandshake方法】
【SessionId】------>FD19B9E5900BB3FAAB1E9FDDE70397AB
【HttpHandShakeInterceptor-afterHandshake方法】
【SocketChannelInterceptor-preSend方法】
【SocketChannelInterceptor-postSend方法】
【SocketChannelInterceptor-连接成功】
【SocketChannelInterceptor-afterSendCompletion方法】
【SocketChannelInterceptor-preSend方法】
【ConnectEventListener事件类型监听器】---->CONNECT
【SocketChannelInterceptor-postSend方法】
【SocketChannelInterceptor-afterSendCompletion方法】
【SocketChannelInterceptor-preSend方法】
【SocketChannelInterceptor-postSend方法】
【SocketChannelInterceptor-afterSendCompletion方法】
【SubscribeEventListener订阅事件监听器】---->SUBSCRIBE
【SubscribeEventListener订阅事件监听器: SessionID】---->FD19B9E5900BB3FAAB1E9FDDE70397AB
断开连接:
【SocketChannelInterceptor-preSend方法】
【SocketChannelInterceptor-postSend方法】
【SocketChannelInterceptor-断开连接】
【SocketChannelInterceptor-afterSendCompletion方法】
【SocketChannelInterceptor-preSend方法】
【SocketChannelInterceptor-preSend方法】
【SocketChannelInterceptor-postSend方法】
【SocketChannelInterceptor-afterSendCompletion方法】
【SocketChannelInterceptor-postSend方法】
【SocketChannelInterceptor-断开连接】
【SocketChannelInterceptor-afterSendCompletion方法】
【SocketChannelInterceptor-preSend方法】
【SocketChannelInterceptor-postSend方法】
【SocketChannelInterceptor-afterSendCompletion方法】