1. 程式人生 > 其它 >springboot + websocket 實現聊天室

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/[email protected]/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/[email protected]/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>

自己看程式碼吧 就不多解釋了,剩下就是根據業務需要改改就可以.