Java Servlet 初探 WebSocket

在 Java Servlet 中使用 WebSocket。

WebSocket

在 Servlet 中使用 WebSocket 的話比較不一樣,沒有要用到 Servlet API 了,取而代之的是 javax.websocket 這個包。

首先!我們要先下載 websocket 的相依性 ( 這次專案要裝的相依性也就僅此爾爾 )

<!-- https://mvnrepository.com/artifact/jakarta.websocket/jakarta.websocket-api -->
<dependency>
    <groupId>jakarta.websocket</groupId>
    <artifactId>jakarta.websocket-api</artifactId>
    <version>2.1.0</version>
    <scope>provided</scope>
</dependency>
@ServerEndpoint("/websocket")
public class WebSocketServer {
    @OnMessage
    public void onMessage(String message, Session session) throws IOException, InterruptedException {
          System.out.println("從您的網頁收到一封訊息: 「" + message + "」");
    }

    @OnOpen
    public void onOpen() {
        System.out.println("與客戶端建立連線了!");
    }

    @OnClose
    public void onClose() {
        System.out.println("連線關閉!");
    }

    @OnError
    public void onError(Session session, Throwable t) {
        System.out.println("連線發生錯誤!");
    }

}

在我們的 WebSocket 中,是使用 @ServerEndpoint() 這個標註來註記他為 WebSocket 服務,裡面的參數當然就是指定訪問 url 的位置了!

在我們的物件中 分別又有四個事件:

  • @OnOpen - 當與客戶端連線建立
  • @OnClose - 當客戶端取消連線
  • @OnError - 發生錯誤
  • @OnMessage - 客戶端傳送訊息過來

其中分別是 @OnError 與 @OnMessage 會收到 Session 物件 (也就是會話物件) 透過這個 Session 物件,我們就可以與客戶端進行溝通。

可以是取得一些客戶端的基本查詢資訊,亦或是推送訊息給客戶端、關閉會話 等等... 那知道這些之後,來個簡單的範例吧!

public class WebSocketServer {
    @OnMessage
    public void onMessage(String message, Session session) throws IOException, InterruptedException {
        session.getBasicRemote().sendText("從您的網頁收到一封訊息: 「" + message + "」");

        int sendMessages = 0;
        while (sendMessages < 10) {
            Thread.sleep(500);;
            sendMessages++;
            session.getBasicRemote().sendText(
                    "伺服器推送第 " + sendMessages + " 筆訊息"
            );
        }
        session.getBasicRemote().sendText("這是伺服器推送的最後一筆訊息 要再收到伺服起的訊息就再敲我一下吧!!");
//        session.close(); // 關閉會話
    }

    @OnOpen
    public void onOpen() {
        System.out.println("與客戶端建立連線了!");
    }

    @OnClose
    public void onClose() {
        System.out.println("連線關閉!");
    }

    @OnError
    public void onError(Session session, Throwable t) {
        System.out.println("連線發生錯誤!");
    }
}

阿如果前面的 Tomcat 環境忘了怎麽建議可以參考這篇!「Tomcat + Servlet + IntelliJ」

這裡還有簡單的 Vue 前端程式碼,也可以參考一下:

<template>
  <div id="app">
    <h2>伺服器回應訊息:</h2>
    <div class="resp-box">
      <p v-for="(respMsg, index) in respMsgArr" :key="index">
        {{respMsg}}
      </p>
    </div>
    <input type="text" v-model="msg">
    <button @click="sendMsg">送出訊息</button>
  </div>
</template>

<script>
export default {
  name: 'App',
  created () {
    this.subWebSocket()
  },
  data () {
    return {
      mySocket: null,
      msg: '', // 傳給伺服器的訊息
      respMsgArr: [] // 伺服器回應過的訊息
    }
  },
  methods: {
    subWebSocket () {
      console.log('連線中...')
      this.mySocket = new WebSocket('ws://localhost:8080/web-socket/websocket')

      // 註冊事件
      this.mySocket.onopen = () => this.onOpen()
      this.mySocket.onerror = () => this.onError()
      this.mySocket.onmessage = (msg) => this.onMessage(msg)
    },
    /**
     * 連線成功事件
     */
    onOpen () {
      console.log('連線成功')
    },
    /**
     * 連線失敗事件
     */
    onError () {
      console.log('連結失敗')
    },
    /**
     * 接受到伺服器訊息
     */
    onMessage (msg) {
      this.respMsgArr.push(msg.data)
    },
    sendMsg () {
      this.mySocket.send(this.msg)
    }
  }
}
</script>

<style>
.resp-box {
  padding: 10px;
  border: 1px solid black;
}
</style>