三、WebSocket相关的拦截器和监听器

拦截器:

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方法】
  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是在Spring Boot项目中整合WebSocket的步骤,包括拦截器、消息处理器和WebSocket实现类的编写: 1. 添加依赖 在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` 2. 编写WebSocket配置类 创建一个WebSocketConfig类,用于配置WebSocket相关的内容,包括注册WebSocket处理器、拦截器等。 ```java @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Autowired private MyWebSocketHandler myWebSocketHandler; @Autowired private MyHandshakeInterceptor myHandshakeInterceptor; @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(myWebSocketHandler, "/websocket") .addInterceptors(myHandshakeInterceptor); } } ``` 在这个配置类中,我们注册了一个WebSocket处理器和一个握手拦截器WebSocket处理器用于处理WebSocket连接和消息,握手拦截器用于拦截WebSocket连接请求并进行一些处理。 3. 编写WebSocket处理器 创建一个WebSocket处理器类,用于处理WebSocket连接和消息。 ```java @Component public class MyWebSocketHandler extends TextWebSocketHandler { private static final Logger logger = LoggerFactory.getLogger(MyWebSocketHandler.class); private static final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>(); @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { logger.info("WebSocket连接建立成功:{}", session.getId()); sessions.put(session.getId(), session); } @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { logger.info("收到消息:{}", message.getPayload()); // 处理消息 } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { logger.info("WebSocket连接关闭:{},状态:{}", session.getId(), status); sessions.remove(session.getId()); } public static void sendMessage(String sessionId, String message) throws IOException { WebSocketSession session = sessions.get(sessionId); if (session != null && session.isOpen()) { session.sendMessage(new TextMessage(message)); } } } ``` 在这个处理器类中,我们重写了WebSocket处理器的个方法:afterConnectionEstablished、handleTextMessage和afterConnectionClosed。afterConnectionEstablished方法在WebSocket连接建立成功后被调用,handleTextMessage方法用于处理收到的消息,afterConnectionClosed方法在WebSocket连接关闭后被调用。 4. 编写握手拦截器 创建一个握手拦截器类,用于拦截WebSocket连接请求并进行一些处理。 ```java @Component public class MyHandshakeInterceptor implements HandshakeInterceptor { private static final Logger logger = LoggerFactory.getLogger(MyHandshakeInterceptor.class); @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { logger.info("WebSocket握手拦截器:beforeHandshake"); // 进行一些处理 return true; } @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) { logger.info("WebSocket握手拦截器:afterHandshake"); } } ``` 在这个握手拦截器类中,我们重写了握手拦截器的两个方法:beforeHandshake和afterHandshake。beforeHandshake方法在WebSocket连接请求到达服务器端时被调用,afterHandshake方法在WebSocket连接握手成功后被调用。 5. 编写WebSocket实现类 创建一个WebSocket实现类,用于实现WebSocket的具体业务逻辑。 ```java @Controller public class MyWebSocketController { @MessageMapping("/hello") @SendTo("/topic/greetings") public String greeting(String message) throws Exception { Thread.sleep(1000); // 模拟处理时间 return "Hello, " + message + "!"; } } ``` 在这个WebSocket实现类中,我们使用了@MessageMapping注解来指定处理消息的路径,使用@SendTo注解来指定返回消息的路径。 6. 测试WebSocket连接 在客户端中,可以使用JavaScript代码来测试WebSocket连接: ```javascript var socket = new WebSocket("ws://localhost:8080/websocket"); socket.onopen = function(event) { console.log("WebSocket连接已建立"); socket.send("Hello, WebSocket!"); }; socket.onmessage = function(event) { console.log("收到消息:" + event.data); }; socket.onclose = function(event) { console.log("WebSocket连接已关闭"); }; ``` 以上就是在Spring Boot项目中整合WebSocket的步骤,包括拦截器、消息处理器和WebSocket实现类的编写。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值