SpringBoot integrates WebSocket to realize simple chat room

Keywords: Spring Boot websocket

brief introduction

Introduction to WebSocket

WebSocket protocol was born in 2008 and became an international standard in 2011. At present, mainstream browsers have good support.
WebSocket makes the data exchange between the client and the server easier, and allows the server to actively push data to the client. In the WebSocket API, the browser and server only need to complete a handshake, and they can directly create a persistent connection and conduct two-way data transmission.

WebSocket features

  1. Based on TCP protocol, the server-side implementation is relatively easy
  2. It has good compatibility with HTTP protocol. The default ports are also 80 and 443, and the HTTP protocol is used in the handshake stage. Therefore, it is not easy to shield the handshake and can pass through various HTTP proxy servers
  3. The data format is light, the performance overhead is small, and the communication is efficient
  4. You can send text or binary data
  5. There is no homology restriction, and the client can communicate with any server
  6. The protocol identifier is ws (wss if encrypted) and the server URL is the URL.

Integration instance

preparation in advance

1. Add dependency in pom.xml

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>fastjson</artifactId>
	<version>1.2.47</version>
</dependency>

2. Configure the port for page access in the SpringBoot configuration file

server:
  port: 8888

3. Create WebSocket configuration file

@Configuration
public class WebSocketConfig {

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

Send yourself a message

1. Create index.html in the templates directory

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My WebSocket</title>
</head>
<body>
    Message content:<input id="text" type="text" />
    <button onclick="send()">send out</button>
    <button onclick="closeWebSocket()">Close connection</button>
    <div id="message"></div>

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

        if("WebSocket" in window){
            websocket=new WebSocket("ws://localhost:8888/websocket/one");
        }else {
            alert('I won't support it WebSocket');
        }

        websocket.onerror=function () {
            setMessageInnerHTML('websocket Connection error!');
        };

        websocket.onopen=function (event) {
            setMessageInnerHTML('websocket Connection established successfully!');
        };

        websocket.onmessage=function (event) {
            var message=event.data;
            setMessageInnerHTML(message);
        };

        websocket.onclose=function () {
            setMessageInnerHTML('websocket Connection closed!');
        };

        websocket.onbeforeunload=function () {
            websocket.close();
        };

        function setMessageInnerHTML(innerHTML) {
            document.getElementById('message').innerHTML+=innerHTML+'<br/>';
        }

        function closeWebSocket() {
            websocket.close();
        }

        function send(){
            var message=document.getElementById('text').value;
            websocket.send(message);
        }
    </script>
</body>
</html>

2. Create a server. The @ ServerEndpoint annotation is the key to the interaction between the server and the client. Its value (/ websocket/one) should correspond to the request path in the index page

@Slf4j
@ServerEndpoint(value = "/websocket/one")
@Component
public class OneWebSocket {
    //Current number of online connections
    private static AtomicInteger onlineCount=new AtomicInteger(0);

    @OnOpen
    public void onOpen(Session session){
        onlineCount.incrementAndGet();      //Number of lines + 1
        log.info("Add connection:{},Number of people currently online:{}",session.getId(),onlineCount.get());
    }

    @OnClose
    public void onClose(Session session){
        onlineCount.decrementAndGet();      //Online number - 1
        log.info("Close connection:{},Number of people currently online:{}",session.getId(),onlineCount.get());
    }

    @OnMessage
    public void onMessage(String message,Session session){
        log.info("Server receives client[{}]Message:{}",session.getId(),message);
        sendMessage("Hello, "+message,session);
    }

    @OnError
    public void onError(Session session,Throwable error){
        log.error("Send error!");
        error.printStackTrace();
    }

    private void sendMessage(String message,Session toSession){
        try {
            log.info("Server to client[{}]send message{}",toSession.getId(),message);
            toSession.getBasicRemote().sendText(message);
        } catch (IOException e) {
            log.error("The server failed to send a message to the client:{}",e);
        }
    }
}

3. Visit the index page. When entering the page, the connection between the server and the client will be established. After entering the content to be sent in the text box, click send to see the following effect

Mass messaging

1. Modify the connection address of index.html

websocket=new WebSocket("ws://localhost:8888/websocket/oneToMany");

2. Create server

@Slf4j
@ServerEndpoint(value = "/websocket/oneToMany")
@Component
public class OneToManyWebSocket {
    //Current number of online connections
    private static AtomicInteger onlineCount=new AtomicInteger(0);

    //Currently online clients
    private static Map<String, Session> clients=new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session){
        onlineCount.incrementAndGet();      //Number of lines + 1
        clients.put(session.getId(),session);
        log.info("Add connection:{},Number of people currently online:{}",session.getId(),onlineCount.get());
    }

    @OnClose
    public void onClose(Session session){
        onlineCount.decrementAndGet();      //Online number - 1
        clients.remove(session.getId());
        log.info("Close connection:{},Number of people currently online:{}",session.getId(),onlineCount.get());
    }

    @OnMessage
    public void onMessage(String message,Session session){
        log.info("Server receives client[{}]Message:{}",session.getId(),message);
        sendMessage("Hello, "+message,session);
    }

    @OnError
    public void onError(Session session,Throwable error){
        log.error("Send error!");
        error.printStackTrace();
    }

    private void sendMessage(String message,Session fromSession){
        for (Map.Entry<String,Session> sessionEntry:clients.entrySet()){
            Session toSession=sessionEntry.getValue();
            if (!fromSession.getId().equals(toSession.getId())){
                log.info("Server to client[{}]send message{}",toSession.getId(),message);
                toSession.getAsyncRemote().sendText(message);
            }
        }
    }
}

3. Open multiple pages in the browser and select a page to send a message

One to one chat room

1. Modify the code of index.html page

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My WebSocket</title>
</head>
<body>
    <div>
        ID:<span id="id"></span>
    </div>
    Message content:<input id="text" type="text" />
    target ID: <input id="toId" type="text" />
    <button onclick="send()">send out</button>
    <button onclick="closeWebSocket()">Close connection</button>
    <div id="message"></div>

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

        if("WebSocket" in window){
            websocket=new WebSocket("ws://localhost:8888/websocket/oneToOne");
        }else {
            alert('I won't support it WebSocket');
        }

        websocket.onerror=function () {
            setMessageInnerHTML('websocket Connection error!');
        };

        websocket.onopen=function (event) {
            setMessageInnerHTML('websocket Connection established successfully!');
        };

        websocket.onmessage=function (event) {
            var message=event.data;
            if (message.length>11 && message.substring(0,12)=="send userId:"){
                document.getElementById('id').innerText=message.substring(12,message.length);
            }else{
                setMessageInnerHTML(message);
            }
        };

        websocket.onclose=function () {
            setMessageInnerHTML('websocket Connection closed!');
        };

        websocket.onbeforeunload=function () {
            websocket.close();
        };

        function setMessageInnerHTML(innerHTML) {
            document.getElementById('message').innerHTML+=innerHTML+'<br/>';
        }

        function closeWebSocket() {
            websocket.close();
        }

        function send(){
            var id=document.getElementById('toId').value;
            var message=document.getElementById('text').value;
            var sendMsg="{\"userId\":"+id+",\"message\":\""+message+"\"}";
            websocket.send(sendMsg);
        }
    </script>
</body>
</html>

2. Create server and MyMessage classes

@Slf4j
@ServerEndpoint(value = "/websocket/oneToOne")
@Component
public class OneToOneWebSocket {
    //Current number of online connections
    private static AtomicInteger onlineCount=new AtomicInteger(0);

    //Currently online clients
    private static Map<String, Session> clients=new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session){
        onlineCount.incrementAndGet();      //Number of lines + 1
        clients.put(session.getId(),session);
        log.info("Add connection:{},Number of people currently online:{}",session.getId(),onlineCount.get());
        sendMessage("send userId:"+session.getId(),session);
    }

    @OnClose
    public void onClose(Session session){
        onlineCount.decrementAndGet();      //Online number - 1
        clients.remove(session.getId());
        log.info("Close connection:{},Number of people currently online:{}",session.getId(),onlineCount.get());
    }

    @OnMessage
    public void onMessage(String message,Session session){
        log.info("Server receives client[{}]Message:{}",session.getId(),message);
        try{
            MyMessage myMessage= JSON.parseObject(message, MyMessage.class);
            if (myMessage!=null){
                Session toSession=clients.get(myMessage.getUserId());
                if (toSession!=null){
                    sendMessage(session.getId()+": "+myMessage.getMessage(),toSession);
                }
                sendMessage(session.getId()+": "+myMessage.getMessage(),session);
            }
        }catch (Exception e){
            log.error("Parsing failed:{}",e);
        }
    }

    @OnError
    public void onError(Session session,Throwable error){
        log.error("Send error!");
        error.printStackTrace();
    }

    private void sendMessage(String message,Session toSession){
        try {
            log.info("Server to client[{}]send message{}",toSession.getId(),message);
            toSession.getBasicRemote().sendText(message);
        } catch (Exception e) {
            log.error("The server failed to send a message to the client:{}",e);
        }
    }
}
@Data
@NoArgsConstructor
public class MyMessage {
    private String userId;
    private String message;
}

3. Open two pages in the browser


Posted by NFWriter on Mon, 27 Sep 2021 01:14:42 -0700