SoFunction
Updated on 2024-07-16

Detailed notes on the use of spring boot Websocket

This article is intended as personal notes only, and most of the code is quoted from other people's articles.

springboot project in the use of websocket to do push, although quite simple, but the beginner also stepped on a few potholes, here to record.

There are two ways to use websocket: 1 is to use sockjs, 2 is to use the h5 standard. The use of Html5 standard is naturally more convenient and simple, so the record is with the use of h5.

1、pom

The core is the @ServerEndpoint annotation. This annotation is a Javaee standard in the annotation , tomcat7 above has been implemented , if the traditional method of using tomcat release project , as long as the introduction of javaee standard in the pom file can be used.

  <dependency>
   <groupId>javax</groupId>
   <artifactId>javaee-api</artifactId>
   <version>7.0</version>
   <scope>provided</scope>
  </dependency>

However, when using springboot's built-in tomcat, there is no need to introduce javaee-api, spring-boot is already included. To use springboot's websocket functionality first introduce the springboot component.

    <dependency>
      <groupId></groupId>
      <artifactId>spring-boot-starter-websocket</artifactId>
      <version>1.3.</version>
    </dependency>

By the way, springboot's advanced components automatically reference the base components, like spring-boot-starter-websocket introduces spring-boot-starter-web and spring-boot-starter, so don't reintroduce them.

2. Use @ServerEndpoint to create a websocket endpoint.

The first step is to inject the ServerEndpointExporter, a bean that automatically registers the websocket endpoint declared using the @ServerEndpoint annotation. note that if you are using a standalone servlet container, rather than springboot's built-in containers directly, you should not inject the ServerEndpointExporter, as it will be provided and managed by the container itself.

@Configuration
public class WebSocketConfig {
  @Bean
  public ServerEndpointExporter serverEndpointExporter() {
    return new ServerEndpointExporter();
  }

}

The next step is to write a specific implementation of websocket class, it is very simple, directly on the code:

@ServerEndpoint(value = "/websocket")
@Component
public class MyWebSocket {
  // Static variable to keep track of the current number of online connections. It should be designed to be thread-safe.
  private static int onlineCount = 0;

  // Thread-safe Set of the concurrent package to hold the corresponding MyWebSocket object for each client.
  private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>();

  //Connection session with a client through which data needs to be sent to the client
  private Session session;

  /**
   * :: Methods invoked when the connection is successfully established */
  @OnOpen
  public void onOpen(Session session) {
     = session;
    (this);   // Add to set
    addOnlineCount();      //Online plus 1
    ("A new connection has been added! The current number of people online is " + getOnlineCount());
    try {
      sendMessage(CommonConstant.CURRENT_WANGING_NUMBER.toString());
    } catch (IOException e) {
      ("IO anomaly.");
    }
  }

  /**
   * Methods called by connection closure
   */
  @OnClose
  public void onClose() {
    (this); //delete from set
    subOnlineCount();      //Online minus 1
    ("One connection closed! The current number of people online is " + getOnlineCount());
  }

  /**
   * Methods called upon receipt of a client message
   *
   * @param message Message sent by the client */
  @OnMessage
  public void onMessage(String message, Session session) {
    ("Message from client:" + message);

    //Mass message
    for (MyWebSocket item : webSocketSet) {
      try {
        (message);
      } catch (IOException e) {
        ();
      }
    }
  }

  /**
   * Called on an error
  @OnError
  public void onError(Session session, Throwable error) {
    ("An error has occurred.");
    ();
  }


  public void sendMessage(String message) throws IOException {
    ().sendText(message);
    //().sendText(message);
  }


  /**
   * Mass customized messages
   * */
  public static void sendInfo(String message) throws IOException {
    for (MyWebSocket item : webSocketSet) {
      try {
        (message);
      } catch (IOException e) {
        continue;
      }
    }
  }

  public static synchronized int getOnlineCount() {
    return onlineCount;
  }

  public static synchronized void addOnlineCount() {
    ++;
  }

  public static synchronized void subOnlineCount() {
    --;
  }
}

The only difference between using springboot is that you have to @Component declare it, while using a standalone container is managed by the container itself for websockets, but in springboot even the container is managed by spring.

Although @Component is singleton by default, springboot still initializes a bean for each websocket connection, so it can be saved with a static set.

3. Front-end code

<!DOCTYPE HTML>
<html>
<head>
  <title>My WebSocket</title>
</head>

<body>
Welcome<br/>
<input id="text" type="text" /><button onclick="send()">Send</button>  <button onclick="closeWebSocket()">Close</button>
<div id="message">
</div>
</body>

<script type="text/javascript">
  var websocket = null;

  // Determine whether the current browser supports WebSocket.
  if('WebSocket' in window){
    websocket = new WebSocket("ws://localhost:8084/websocket");
  }
  else{
    alert('Not support websocket')
  }

  // Callback method if a connection error occurs
   = function(){
    setMessageInnerHTML("error");
  };

  // Callback method for successful connection establishment
   = function(event){
    setMessageInnerHTML("open");
  }

  // Callback methods for received messages
   = function(event){
    setMessageInnerHTML();
  }

  // Connection closure callback method
   = function(){
    setMessageInnerHTML("close");
  }

  // Listen to the window close event, when the window is closed, take the initiative to close the websocket connection, to prevent the connection has not been disconnected before closing the window, the server side will throw an exception.
   = function(){
    ();
  }

  // Display the message on the web page
  function setMessageInnerHTML(innerHTML){
    ('message').innerHTML += innerHTML + '<br/>';
  }

  // Close the connection
  function closeWebSocket(){
    ();
  }

  //Send a message
  function send(){
    var message = ('text').value;
    (message);
  }
</script>
</html>

4. Summary

springboot has done a deep integration and optimization, be careful whether to add unwanted dependencies, configurations or declarations. As many of the articles explaining the use of components are integrated with spring, there will be some configuration, when using springboot, because springboot already has its own configuration, and then these configurations may lead to a variety of exceptions.

This is the whole content of this article.