1 先创建 http握手 拦截器 HttpHandShakeIntecepter,因为一般会从握手拦截器里取值(个人理解)
package cn.huawei.intecepter;
import java.util.Map;
import javax.servlet.http.HttpSession;
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;
/**
*
* 功能描述:http握手拦截器,可以通过这个类的方法获取resuest,和response
*
* 将 httprequest中的sessionId 保存起来
*
*/
public class HttpHandShakeIntecepter implements HandshakeInterceptor{
@Override
public boolean beforeHandshake(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception {
if(request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest)request;
HttpSession session = servletRequest.getServletRequest().getSession();
String huihuaId = session.getId();
System.out.println("【握手拦截器】beforeHandshake 会话id="+huihuaId);
attributes.put("huihuaId", huihuaId);
}
return true;
}
@Override
public void afterHandshake(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler wsHandler,
Exception exception) {
if(request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest)request;
HttpSession session = servletRequest.getServletRequest().getSession();
String huihuaId = session.getId();
System.out.println("【握手拦截器】afterHandshake 会话id="+huihuaId);
}
}
}
2 创建频道拦截器 SocketChannelIntecepter,可以从握手拦截器里面取值
package cn.huawei.intecepter;
import cn.huawei.controller.v6.UserChatController;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptorAdapter;
/**
* 功能描述:频道拦截器 ,类似管道,可以获取消息的一些meta数据
*
* 取得 http握手拦截器 中 存储的sessionid
*/
public class SocketChannelIntecepter extends ChannelInterceptorAdapter{
/**
* 在完成发送之后进行调用,不管是否有异常发生,一般用于资源清理
*/
@Override
public void afterSendCompletion(Message<?> message, MessageChannel channel,
boolean sent, Exception ex) {
System.out.println("频道拦截器->afterSendCompletion");
super.afterSendCompletion(message, channel, sent, ex);
}
/**
* 在消息被实际发送到频道之前调用
*/
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
System.out.println("频道拦截器->preSend");
return super.preSend(message, channel);
}
/**
* 发送消息调用后立即调用
*/
@Override
public void postSend(Message<?> message, MessageChannel channel,
boolean sent) {
System.out.println("频道拦截器->postSend");
//消息头访问器
StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(message);
// 避免非stomp消息类型,例如心跳检测
if (headerAccessor.getCommand() == null ) return ;
String huihuaId = headerAccessor.getSessionAttributes().get("huihuaId").toString();
System.out.println("频道拦截器 -> 会话id = "+huihuaId);
switch (headerAccessor.getCommand()) {
case CONNECT:
connect(huihuaId);
break;
case DISCONNECT:
disconnect(huihuaId);
break;
case SUBSCRIBE:
break;
case UNSUBSCRIBE:
break;
default:
break;
}
}
//连接成功
private void connect(String huihuaId){
}
//断开连接
private void disconnect(String huihuaId){
//用户下线操作
UserChatController.onlineUser.remove(huihuaId);
}
}
3 在websocket配置中配置拦截器
package cn.huawei.config;
import cn.huawei.intecepter.HttpHandShakeIntecepter;
import cn.huawei.intecepter.SocketChannelIntecepter;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/endpoint-websocket")
//配置握手拦截器
.addInterceptors(new HttpHandShakeIntecepter())
.setAllowedOrigins("*")
.withSockJS();
}
/**
* 配置消息代理(中介)
* enableSimpleBroker 服务端推送给客户端的路径前缀
* setApplicationDestinationPrefixes 客户端发送数据给服务器端的一个前缀
*/
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic", "/chat");
registry.setApplicationDestinationPrefixes("/app");
}
/**
* 配置 频道拦截器
*/
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new SocketChannelIntecepter());
}
@Override
public void configureClientOutboundChannel(ChannelRegistration registration) {
registration.interceptors(new SocketChannelIntecepter());
}
}
4 测试,顺带可以看看拦截器加载的顺序,有得于理解
【握手拦截器】beforeHandshake 会话id=F3367AD9F1849BE6AB03178989DC1C3B
【握手拦截器】afterHandshake 会话id=F3367AD9F1849BE6AB03178989DC1C3B
频道拦截器->preSend
频道拦截器->postSend
频道拦截器 -> 会话id = F3367AD9F1849BE6AB03178989DC1C3B
频道拦截器->afterSendCompletion