An overview of the

The WebSocket story series is planned as a five-part, six-chapter introduction to WebSocket and how to quickly build and use the capabilities WebSocket provides in Springboot. This series is planned to include the following articles:

Part 1: What WebSocket is and what it Does Part 2: How to Use STOMP to Quickly Build WebSocket broadcast message Patterns in Spring In Springboot, how to use WebSocket and STOMP to quickly build point-to-point messaging mode (2) in Springboot, how to implement custom WebSocket message proxy in web chat rooms

The main line of this article

This article, the last in this series, will show you another way to implement WebSocket. Again, we’ll use a simple chat room as an example. At this point we can also choose different implementation methods according to the specific situation.

This article is suitable for readers

Aspiring young people who want to learn how to customize the implementation of more complex WebSocket product logic on Springboot.

Use WebSocket support provided by Tomcat

The JSR356 specification was released as early as Java EE 7. Tomcat7.0.47 also supports a unified WebSocket interface. These apis provided by Tomcat can also be easily used with Springboot. Today we are going to experience a Tomcat implementation of WebSocket.

1. Introduce dependencies

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
Copy the code

Tomcat is built into Springboot, so we can directly import this advanced component of Spring. By the way, Springboot’s advanced components automatically reference basic components, such as spring-boot-starter-websocket, which introduces spring-boot-starter-Web and spring-boot-starter, so don’t repeat them.

2. Use @ServerEndpoint to create a WebSocket Endpoint

The first step is to inject ServerEndpointExporter, which automatically registers the WebSocket Endpoint declared with the @ServerEndpoint annotation.

package com.draw.wsdraw.websocket;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter(a) {
        return newServerEndpointExporter(); }}Copy the code

Then we’ll implement the implementation class for the WebSocket service, in this case WebSocketServer, and remember to declare it in the form of @ServerEndpint and @Component. Although @Component is singleton by default, Springboot initializes a Bean for each WebSocket connection, so it can be stored in a static Map. In other words, every time a user initiates a connection to the server, a WebSocketServer object is created and stored in a HashMap by roomId for later use.

When you create a ServerEndpoint, there are several functional methods that need to be implemented: OnOpen, OnMessage, OnClose, and OnError.

  • @OnOpen: Is called by the server when the client initiates the connection establishment to the server. The parameters that can be passed in are Session(WebSocket Session) and EndpointConfig. Alternatively, you can add parameters annotated with @PathParam. The parameter we annotate here is the roomId, the parameter on the request address carried when the connection is established, which does the same thing as the {INFO} parameter we introduced in the previous article.
  • @OnMessage: called when a message arrives from the client, including the Session. Depending on the form of the message, either a String or Reader argument is passed in for text messages, or a byte[] or InputStream argument is passed in for binary messages.
  • @OnClose: Called when the WebSocket is closed or disconnected.
  • @OnError: Called when an error occurs, passing in an abnormal Session and an error message.

Rewrite the above method, you can realize the server business logic of WebSocket.

@ServerEndpoint("/webSocket/{roomId}")
@Component
public class WebSocketServer {
    private static ConcurrentHashMap<String, List<WebSocketServer>> webSocketMap =
            new ConcurrentHashMap<>(3);

    // A connection session with a client through which to send data to the client
    private Session session;

    / / receive roomId
    private String roomId = "";

    /** * Connection established successfully called method */
    @OnOpen
    public void onOpen(Session session, EndpointConfig config, @PathParam("roomId") String roomId) {
        if (roomId == null || roomId.isEmpty()) return;
        this.session = session;
        this.roomId = roomId;
        addSocketServer2Map(this);
        try {
            sendMessage("Connection successful".true);
        } catch (IOException e) {
        }
    }

    /** * the connection closes the called method */
    @OnClose
    public void onClose(a) {
        List<WebSocketServer> wssList = webSocketMap.get(roomId);
        if(wssList ! =null) {
            for (WebSocketServer item : wssList) {
                if (item.session.getId().equals(session.getId())) {
                    wssList.remove(item);
                    if (wssList.isEmpty()) {
                        webSocketMap.remove(roomId);
                    }
                    break; }}}}/** * The method called after receiving the client message */
    @OnMessage
    public void onMessage(String message, Session session) {
        // Group message
        String msg = filterMessage(message);
        if(msg ! =null) { sendInfo(msg, roomId, session); }}/** * The method called */ when an error occurs
    @OnError
    public void onError(Session session, Throwable error) {}Copy the code

In this way, the server side of the code is finished, only part of the source code is posted here, after the article will give the project source address.

3. Implement the client page

<script type="text/javascript">
    var ws;
    
    function setConnected(connected){
        document.getElementById('connect').disabled = connected;
        document.getElementById('disconnect').disabled = ! connected;document.getElementById('conversationDiv').style.visibility = connected ? 'visible' : 'hidden';
        $("#response").html();
    }

    function connect(){
        var roomId = $('#roomId').val();
        ws = new WebSocket('ws://localhost:8080/webSocket/' + roomId);
        ws.onopen = WSonOpen;
        ws.onmessage = WSonMessage;
        ws.onclose = WSonClose;
        ws.onerror = WSonError;
    }

    function WSonOpen() {
        var message = {
            name:'Server'.chatContent:'Connection successful'
        }
        setConnected(true);
        showResponse(message)
    };

    function WSonMessage(event) {
        var message = {
            name:'Server'.chatContent:event.data
        }
        showResponse(message)
    };

    function WSonClose() {
        var message = {
            name:'Server'.chatContent:'Disconnected'
        }
        showResponse(message)
    };

    function WSonError() {
        var message = {
            name:'Server'.chatContent:'Connection error! '
        }
        showResponse(message)
    };

    function disconnect(){
        ws.close()
        setConnected(false);
        console.log("Disconnected");
    }

    function sendMessage(){
        var chatContent = $("#chatContent").val();
        var roomId = $('#roomId').val();
        ws.send(JSON.stringify({'roomId':roomId,'chatContent':chatContent}))
    }

    function showResponse(message){
         var response = $("#response").val();
         $("#response").val(response+message.name+':'+message.chatContent+'\n');
    }
</script>
Copy the code

The client page implements simple connect, disconnect, and message sending functions. I’m not going to go into that.

4. Demo screenshots

The source address

This article source address:

Another way to implement WebSocket

conclusion

This article directly uses the WebSocket provided by Tomcat, which is also a relatively flexible way of implementation. You only need to follow the above steps to achieve it. Focus on writing business logic code.

Throughout the series, we introduced several ways to implement WebSocket, some highly integrated, some relatively flexible. You can choose the appropriate way according to the actual business needs. That’s the end of the series. Thank you for reading.

Xiaoming produced, must be a boutique

Welcome to pay attention to xNPE technology forum, more original dry goods daily push.