SpringBoot-WebSocket-STMOP简介与使用

简介:

简介

  • WebSocket:是一种网络通信协议,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息详情
  • sockjs-client:js库,如果浏览器不支持 WebSocket,该库可以模拟对 WebSocket 的支持github
  • STOMP:简单(流)文本定向消息协议 介绍
  • stomp-websocket:js库,提供一个基于STOMP客户端的WebSocket gihub

CODE

已下代码在demo中都有,但是有的为了博客效果没有简化。

Maven 增加依赖

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-websocket</artifactId>
      <exclusions>
        <exclusion>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
      </exclusions>
    </dependency>

SpringBoot 配置

注意事项

  • 重写DefaultHandshakeHandler的determineUser方法来自己实现生成用户频道名称,如使用的是spring Security则可忽略此条
  • enableSimpleBroker:设置客户端接收消息的前缀
  • setUserDestinationPrefix:指定用户频道的前缀,这个前缀必须在enableSimpleBroker中设置过
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
        //设置端点,前端通过 /ContextPath/端点 进行连接
        stompEndpointRegistry.addEndpoint("/any-socket").addInterceptors(new HandshakeInterceptor() {

            /**
             * 握手前拦截,往attributes存储用户信息,后续用户频道使用
             * @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 {
                boolean result = false;
                HttpSession session =getSession(request);
                if (session != null){
                    User user =(User)getSession(request).getAttribute("user");
                    if(user != null){
                        attributes.put("user",user);
                        result = true;
                    }
                }
                return result;
            }
            @Nullable
            private HttpSession getSession(ServerHttpRequest request) {
                if (request instanceof ServletServerHttpRequest) {
                    ServletServerHttpRequest serverRequest = (ServletServerHttpRequest) request;
                    return serverRequest.getServletRequest().getSession();
                }
                return null;
            }
            @Override
            public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {}
        }).setHandshakeHandler(new DefaultHandshakeHandler() {
            /**
             * 指定握手主体生成规则,后续接收用户消息时会使用,默认用户频道为/UserDestinationPrefix/{Principal.getName}/频道
             * @param request
             * @param wsHandler
             * @param attributes
             * @return
             */
            @Nullable
            @Override
            protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) {
                return new UserPrincipal((User) attributes.get("user"));
            }
        //支持SockJS
        }).withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry messageBrokerRegistry) {

        messageBrokerRegistry.setApplicationDestinationPrefixes("/app");
// 客户端订阅地址的前缀信息,也就是客户端接收服务端发送消息的前缀信息
 messageBrokerRegistry.enableSimpleBroker("/queue", "/topic");
        //指定用户频道前缀,默认为user可修改
        messageBrokerRegistry.setUserDestinationPrefix("/queue");
    }

    @Override
    public void configureWebSocketTransport(final WebSocketTransportRegistration registration) {
        registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {
            @Override
            public WebSocketHandler decorate(final WebSocketHandler handler) {
                return new WebSocketHandlerDecorator(handler) {
                    @Override
                    public void afterConnectionEstablished(final WebSocketSession session) throws Exception {
                        String username = session.getPrincipal().getName();
                        //上线相关操作
                        super.afterConnectionEstablished(session);
                    }

                    @Override
                    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus)
                            throws Exception {
                        String username = session.getPrincipal().getName();
                      //离线相关操作
                        super.afterConnectionClosed(session, closeStatus);
                    }
                };
            }
        });
    }
}

服务端代码

** 说明 **

  • @MessageMapping("/sendMsg"),对应前端发送消息时调用的路径,访问路径为/ApplicationDestinationPrefixes/sendMsg,此时已与ContextPath无关。
  • convertAndSendToUser:向指定用户发送消息,对应设置中的determineUser,和指定的用户频道前缀,最终发送的路径:/用户频道前缀/Principal.getName/后缀
  • convertAndSend:向指定频道发送消息,可以使用@SendTo代替
  • @SendToUser:向请求的用户对应的用户频道发送消息,与convertAndSendToUser不能互换
    @MessageMapping("/sendMsg")
    public void sendMsg(Principal principal, String message) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
        Message msg = JsonUtils.toObject(message, Message.class);
        try {
            msg.setSendTime(sdf.format(new Date()));
        } catch (Exception e) {
        }
        if (!"TO_ALL".equals(msg.getReceiver())) {
            template.convertAndSendToUser(msg.getReceiver(), "/chat", JsonUtils.toJson(msg));
        } else {
            template.convertAndSend("/notice", JsonUtils.toJson(msg));
        }
    }

前端代码

    function connect() {
        //连接端点,此时需加上项目路径
        var socket = new SockJS(_baseUrl+'any-socket');
        stompClient = Stomp.over(socket);
        stompClient.connect({}, function (frame) {
            //监听/topic/notice这个频道的消息
            stompClient.subscribe('/topic/notice', function (message) {
                showMessage(JSON.parse(message.body));
            });
            //监听当前登录用户这个频道的消息,对应服务端convertAndSendToUser
            stompClient.subscribe("/queue/"+_username+"/chat", function (message) {
                showMessage(JSON.parse(message.body));
            });
        });
    }

        $("#send").click(function () {
            debugger;
            var msg = {
                "username":_username
                ,"avatar":_avatar
                ,"content":$("#message").val()
                ,"receiver":target
            };;
            //向MessageMapping对应路径发送消息
            stompClient.send("/app/sendMsg", {}, JSON.stringify(msg));
            $("#message").val("");
        });

Demo

demo参考了这个博客,去掉了Spring Security的部分,修改了一对一消息发送的规则,写的比较简陋,第一个用户登录的时候会报错大家将就看看就行。第二个用户登录后刷新第一个登陆用户的页面会加载用户,就可以点对点的聊天了。 
https://gitee.com/MeiJM/stompDemo

参考资料

https://www.jianshu.com/p/4ef5004a1c81 
https://www.jianshu.com/p/0f498adb3820 
https://spring.io/guides/gs/messaging-stomp-websocket/ 
https://www.callicoder.com/spring-boot-websocket-chat-example/ 
http://www.ruanyifeng.com/blog/2017/05/websocket.html 
https://github.com/spring-guides/gs-messaging-stomp-websocket



目录
相关文章
|
移动开发 前端开发 网络协议
WebSocket协议简介
WebSocket协议简介
1795 0
|
5月前
|
前端开发 网络协议 JavaScript
在Spring Boot中实现基于WebSocket的实时通信
在Spring Boot中实现基于WebSocket的实时通信
|
2月前
|
开发框架 前端开发 网络协议
Spring Boot结合Netty和WebSocket,实现后台向前端实时推送信息
【10月更文挑战第18天】 在现代互联网应用中,实时通信变得越来越重要。WebSocket作为一种在单个TCP连接上进行全双工通信的协议,为客户端和服务器之间的实时数据传输提供了一种高效的解决方案。Netty作为一个高性能、事件驱动的NIO框架,它基于Java NIO实现了异步和事件驱动的网络应用程序。Spring Boot是一个基于Spring框架的微服务开发框架,它提供了许多开箱即用的功能和简化配置的机制。本文将详细介绍如何使用Spring Boot集成Netty和WebSocket,实现后台向前端推送信息的功能。
324 1
|
2月前
|
前端开发 Java C++
RSocket vs WebSocket:Spring Boot 3.3 中的两大实时通信利器
本文介绍了在 Spring Boot 3.3 中使用 RSocket 和 WebSocket 实现实时通信的方法。RSocket 是一种高效的网络通信协议,支持多种通信模式,适用于微服务和流式数据传输。WebSocket 则是一种标准协议,支持全双工通信,适合实时数据更新场景。文章通过一个完整的示例,展示了如何配置项目、实现前后端交互和消息传递,并提供了详细的代码示例。通过这些技术,可以大幅提升系统的响应速度和处理效率。
|
4月前
|
开发框架 网络协议 Java
SpringBoot WebSocket大揭秘:实时通信、高效协作,一文让你彻底解锁!
【8月更文挑战第25天】本文介绍如何在SpringBoot项目中集成WebSocket以实现客户端与服务端的实时通信。首先概述了WebSocket的基本原理及其优势,接着详细阐述了集成步骤:添加依赖、配置WebSocket、定义WebSocket接口及进行测试。通过示例代码展示了整个过程,旨在帮助开发者更好地理解和应用这一技术。
315 1
|
4月前
|
小程序 Java API
springboot 微信小程序整合websocket,实现发送提醒消息
springboot 微信小程序整合websocket,实现发送提醒消息
|
4月前
|
JavaScript 前端开发 网络协议
WebSocket在Java Spring Boot+Vue框架中实现消息推送功能
在现代Web应用中,实时消息提醒是一项非常重要的功能,能够极大地提升用户体验。WebSocket作为一种在单个TCP连接上进行全双工通信的协议,为实现实时消息提醒提供了高效且低延迟的解决方案。本文将详细介绍如何在Java Spring Boot后端和Vue前端框架中利用WebSocket实现消息提醒功能。
178 0
|
6月前
|
前端开发 JavaScript 安全
集成WebSocket在Spring Boot中可以用于实现实时的双向通信
集成WebSocket在Spring Boot中可以用于实现实时的双向通信
91 4
下一篇
无影云桌面