Spring Boot 2.x实战95 - 事件驱动4 - Websocket之STOMP Websocket

4.Websocket

在HTTP协议下,我们可以通过Websocket进行服务端和客户端进行全工通讯,即客户端和服务端都可通过通道直接向彼此发送数据。当我们使用STOMP的时候,应用作为所有连接客户端的消息代理,当然我们使用支持STOMP协议的第三方消息代理如RabbitMQ来负责。

4.1 STOMP Websocket

我们可以在Websockets之上使用STOMP(Simple/Streaming Text Oriented Message Protocol)协议进行交互。

4.1.1 新建应用

新建应用,信息如下:

Group:top.wisely

Artifact:learning-websocket

Dependencies:WebsocketSpring SecurityLombok

build.gradle文件中的依赖如下:

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-websocket'
	implementation 'org.springframework.boot:spring-boot-starter-security'
	compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'
  //...
}
4.1.2 示例
  • 配置STOMP Websocket

    @Configuration
    @EnableWebSocketMessageBroker //1
    public class WebsocketConfig implements WebSocketMessageBrokerConfigurer { //2
        @Override
        public void configureMessageBroker(MessageBrokerRegistry registry) { //3
            registry.enableSimpleBroker("/topic"); //4
            registry.setApplicationDestinationPrefixes("/app"); //5
        }
    
        @Override
        public void registerStompEndpoints(StompEndpointRegistry registry) { 
            registry.addEndpoint("/endpoint").withSockJS(); //6
        }
    
    }
    
    1. @EnableWebSocketMessageBroker开启Websocket消息代理的支持,包含给我们配置了消息发送模板SimpMessagingTemplate的Bean;
    2. 通过实现WebSocketMessageBrokerConfigurer接口并重载其方法配置Websocket消息代理;
    3. 通过configureMessageBroker方法配置Websocket消息代理;
    4. 配置消息代理的终点,客户端可订阅监听终点获取信息;
    5. 配置消息处理器(@MessageMapping注解的 方法)的前缀;
    6. WebSocket的端点地址,提供SockJS后备支持;
  • 配置安全

    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Bean
        PasswordEncoder passwordEncoder(){
            return new BCryptPasswordEncoder();
        }
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {//1
            auth.inMemoryAuthentication()
                        .withUser("wyf")
                        .password(passwordEncoder().encode("111111"))
                        .roles("USER")
                    .and()
                        .withUser("admin")
                        .password(passwordEncoder().encode("admin"))
                        .roles("ADMIN"); 
        }
    
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {//2
            http.authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                .formLogin();
        }
    }
    
    
    1. 配置内存中的用户wyfadmin
    2. 配置页面登录;
  • 消息处理

    @Controller
    public class ChatController {
    
        SimpMessagingTemplate simpMessagingTemplate; //1
    
        public ChatController(SimpMessagingTemplate simpMessagingTemplate) {
            this.simpMessagingTemplate = simpMessagingTemplate;
        }
    
        @MessageMapping("/chat/{to}") //2
        @SendTo("/topic/status") //3
        public String chat(Principal principal,
                           @RequestBody String msg,
                           @DestinationVariable  String to){ //4
            simpMessagingTemplate.convertAndSendToUser(to,"/topic/response", msg); //5
            return principal.getName() + " 发送的 " + msg + " 消息已送达给" + to;
        }
    
        @RequestMapping("/user")
        @ResponseBody
        public String user(Principal principal){ //6
            return principal.getName();
        }
    }
    
    1. 注入发送消息的simpMessagingTemplate的Bean;
    2. Spring Messaging的注解,用来映射终点和处理方法类似于@RequestMapping,客户端可以向此路径发送消息;
    3. 这里通过@SendTo发送到终点/topic/status,所有监听该终点的客户端都可订阅接收;和前面一样,发送的消息内容为方法返回值;
    4. 通过@DestinationVariable获取路径变量;
    5. 通过convertAndSendToUser向指定用户指定终点发送消息,被发送用户订阅/user/topic/response即可获得消息;若不指定用户可使用convertAndSend方法进行发送;
    6. 可通过注入Principal对象获得用户信息。
  • 客户端页面

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>聊天室</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
        <script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
        <script src="https://cdn.bootcss.com/sockjs-client/1.3.0/sockjs.min.js"></script>
    </head>
    <body>
    <div id="connect">
        <button onclick="connect()">连接</button>
        <button onclick="disconnect()">关闭</button>
    </div>
    <div id="input">
        <input id="msg" type="text"/>
        <button onclick="send()">发送</button>
    </div>
    <div id="response"></div> 
    <div id="status"></div>
    
    </body>
    
    <script>
        var stompClient = null;
        var from = null;
        var to = null;
        getUser();
        function getUser(){ //获取当前用户和聊天对象
            $.get('/user',function (data) {
                from = data;
                if (data == 'wyf'){
                    to = 'admin';
                } else {
                    to = 'wyf'
                }
                alert('当前用户为:' + from + ',' +"聊天对象为:" + to);
            })
        }
    
        function connect() { //连接
            var socket = new SockJS('/endpoint'); //1
            stompClient = Stomp.over(socket);
            stompClient.connect({}, function(frame) {
                alert("连接成功");
                stompClient.subscribe('/user/topic/response', function(messageOutput) { //2
                    $("#response").append(messageOutput.body + '<br>');
                });
    
                stompClient.subscribe('/topic/status', function(messageOutput) { //3
                   $("#status").html(messageOutput.body);
                });
    
    
            });
        }
    
        function send() {
            msg = $("#msg").val()
            stompClient.send("/app/chat/" + to,{},msg); //4
        }
        function disconnect() {
            stompClient.disconnect();
            alert("关闭成功");
        }
    </script>
    </html>
    
    1. 此处的填写的地址是服务端的设置:

      registry.addEndpoint("/endpoint").withSockJS()
      
    2. 订阅用户消息,和服务端对应为:

      simpMessagingTemplate.convertAndSendToUser(to,"/topic/response", msg);
      
    3. 订阅广播消息,对应服务端:

      @SendTo("/topic/status")
      
    4. 发送消息到消息处理器

      • 前缀配置

        registry.setApplicationDestinationPrefixes("/app");
        
      • 映射配置

        @MessageMapping("/chat/{to}")
        
  • 启动应用

    用Chrome打开http://localhost:8080/chat.html,再在Chrome浏览器上“以访客身份打开一个窗口”同时访问http://localhost:8080/chat.html。此时都要求登录系统,两边分别以wyfadmin用户登录成功后:
    在这里插入图片描述

    两边分别点击连接,提示连接成功后,左边窗口输入“你好”:
    在这里插入图片描述

    左边的信息是所有用户都能收到的信息;右边的上面是左边用户发送的信息,下面是都能收到的信息。我们同样右边发送“你也好”:
    在这里插入图片描述

新书推荐:

我的新书《从企业级开发到云原生微服务:Spring Boot 实战》已出版,内容涵盖了丰富Spring Boot开发的相关知识
购买地址:https://item.jd.com/12760084.html
在这里插入图片描述

主要包含目录有:

第一章 初识Spring Boot(快速领略Spring Boot的美丽)
第二章 开发必备工具(对常用开发工具进行介绍:包含IntelliJ IDEA、Gradle、Lombok、Docker等)
第三章 函数式编程
第四章 Spring 5.x基础(以Spring 5.2.x为基础)
第五章 深入Spring Boot(以Spring Boot 2.2.x为基础)
第六章 Spring Web MVC
第七章 数据访问(包含Spring Data JPA、Spring Data Elasticsearch和数据缓存)
第八章 安全控制(包含Spring Security和OAuth2)
第九章 响应式编程(包含Project Reactor、Spring WebFlux、Reactive NoSQL、R2DBC、Reactive Spring Security)
第十章 事件驱动(包含JMS、RabbitMQ、Kafka、Websocket、RSocket)
第11章 系统集成和批处理(包含Spring Integration和Spring Batch)
第12章 Spring Cloud与微服务
第13章 Kubernetes与微服务(包含Kubernetes、Helm、Jenkins、Istio)
多谢大家支持。

猜你喜欢

转载自blog.csdn.net/wiselyman/article/details/107352885