zoukankan      html  css  js  c++  java
  • springboot + websocket 实现聊天室

    1.前言

    实现聊天室有很多种方式 netty, websocket等,我们这里直接使用websocket技术,websocket是一种服务器向客户端发送信息的技术,而不是传统的servlet客户端发送请求,然后服务器给出响应.

    现在比较流行的框架是springboot,而且spring官方也支持websocket,这里借鉴了spring的官网文档,不排除以后技术会发生变化.

    2.实现

    2.1依赖

        implementation 'org.springframework.boot:spring-boot-starter-websocket'
        testImplementation 'org.springframework.boot:spring-boot-starter-test'
        implementation 'org.webjars:webjars-locator-core'
        implementation 'org.webjars:sockjs-client:1.0.2'
        implementation 'org.webjars:stomp-websocket:2.3.3'
        implementation 'org.webjars:bootstrap:3.3.7'
        implementation 'org.webjars:jquery:3.1.1-1'

    2.2配置文件

    @Configuration
    @EnableWebSocketMessageBroker
    public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    
        @Override
        public void registerStompEndpoints(StompEndpointRegistry registry) {
            registry.addEndpoint("/gs-guide-websocket").withSockJS();
        }
    
        @Override
        public void configureMessageBroker(MessageBrokerRegistry registry) {
            registry.enableSimpleBroker("/topic","/user");
            registry.setApplicationDestinationPrefixes("/app");
        }
    
    }
    setApplicationDestinationPrefixes 定义了websocket应用的访问前缀,
    addEndpoint  定义了socketjs的连接,

    enableSimpleBroker 定义了启用的广播路径,如果这里不加上路径的话,websocket无法广播,也就是不法向客户端发送消息


    2.3消息类

    public class HelloMessage {
        private String name;
    
        public HelloMessage() {
            super();
        }
    
        public HelloMessage(String name) {
            super();
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
        
        
    }
    
    
    public class Greeting {
        private String content;
    
        public Greeting() {
            super();
            // TODO Auto-generated constructor stub
        }
    
        public Greeting(String content) {
            super();
            this.content = content;
        }
    
        public String getContent() {
            return content;
        }
    
        public void setContent(String content) {
            this.content = content;
        }
        
    }

    没什么好说的,信息载体类

    2.4controller

    @Controller
    public class GreetingController {
        
        @Autowired
        private SimpMessagingTemplate simpMessagingTemplate;
    
        
        @MessageMapping("/hello")
        //@SendTo
        //@SendToUser
        public Greeting greeting(HelloMessage message) throws InterruptedException {
            Greeting result = new Greeting("Hello,"+HtmlUtils.htmlEscape(message.getName()));
            TimeUnit.SECONDS.sleep(1L);
            simpMessagingTemplate.convertAndSendToUser("bob", "/queue/position-updates", result);
            return new Greeting("Hello,"+HtmlUtils.htmlEscape(message.getName()));
        }
    
    }

    我们可以使用 SendTo 定义返回路径,也可以使用 SendToUser 定义返回的用户,这些都是使用注解定义的,如果想要更灵活的可以使用 SimpMessagingTemplate 这个类来广播消息.

    2.5 前端实现

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    
    <body>
      <noscript>
        <h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websocket relies on Javascript being
          enabled. Please enable
          Javascript and reload this page!</h2>
      </noscript>
      <div id="main-content" class="container">
        <div class="row">
          <div class="col-md-6">
            <form class="form-inline">
              <div class="form-group">
                <label for="connect">WebSocket connection:</label>
                <button id="connect" class="btn btn-default" type="submit">Connect</button>
                <button id="disconnect" class="btn btn-default" type="submit" disabled="disabled">Disconnect
                </button>
              </div>
            </form>
          </div>
          <div class="col-md-6">
            <form class="form-inline">
              <div class="form-group">
                <label for="name">What is your name?</label>
                <input type="text" id="name" class="form-control" placeholder="Your name here...">
              </div>
              <button id="send" class="btn btn-default" type="submit">Send</button>
            </form>
          </div>
        </div>
        <div class="row">
          <div class="col-md-12">
            <table id="conversation" class="table table-striped">
              <thead>
                <tr>
                  <th>Greetings</th>
                </tr>
              </thead>
              <tbody id="greetings">
              </tbody>
            </table>
          </div>
        </div>
      </div>
    
    
    
    
      <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/stompjs@2.3.3/lib/stomp.min.js"></script>
      <script>
        var stompClient = null;
    
        function setConnected(connected) {
          $("#connect").prop("disabled", connected);
          $("#disconnect").prop("disabled", !connected);
          if (connected) {
            $("#conversation").show();
          }
          else {
            $("#conversation").hide();
          }
          $("#greetings").html("");
        }
    
        function connect() {
          var socket = new SockJS('/gs-guide-websocket');
          stompClient = Stomp.over(socket);
          stompClient.connect({}, function (frame) {
            setConnected(true);
            console.log('Connected: ' + frame);
            stompClient.subscribe('/user/bob/queue/position-updates', function (greeting) {
            console.log(greeting)
              showGreeting(JSON.parse(greeting.body).content);
            });
          });
        }
    
        function disconnect() {
          if (stompClient !== null) {
            stompClient.disconnect();
          }
          setConnected(false);
          console.log("Disconnected");
        }
    
        function sendName() {
          stompClient.send("/app/hello", {}, JSON.stringify({ 'name': $("#name").val() }));
        }
    
        function showGreeting(message) {
          $("#greetings").append("<tr><td>" + message + "</td></tr>");
        }
    
        $(function () {
          $("form").on('submit', function (e) {
            e.preventDefault();
          });
          $("#connect").click(function () { connect(); });
          $("#disconnect").click(function () { disconnect(); });
          $("#send").click(function () { sendName(); });
        });
      </script>
    </body>
    
    </html>

    自己看代码吧 就不多解释了,剩下就是根据业务需要改改就可以.

    主要看 connect 和 sendName 方法

     
  • 相关阅读:
    谷歌 colab调用 Kaggle 数据集
    TensorFlow/Keras binary_crossentropy损失函数
    R语言 pivot_longer 图表变换
    R语言 ggplot2 柱状图
    R语言 ggplot2 笔记
    Bash 批量删除指定后缀的文件
    MacBook 风扇控制软件 Macs Fan Control
    R语言 dplyr selec 辅助函数
    R语言一次性更新全部packages
    R语言 glue 版本冲突
  • 原文地址:https://www.cnblogs.com/lishuaiqi/p/15069833.html
Copyright © 2011-2022 走看看