Building a Simple Multi-Person Chat System Based on SpringBoot+WebSocket

Posted by wookie on Thu, 10 Oct 2019 14:20:48 +0200

Preface

_Today, I Let's have a brief look.

What is WebSocket

Firstly, what is WebSocket? WebSocket is a protocol for full-duplex communication over a single TCP connection. This is a more official statement. In short, in a TCP connection, the two sides of the communication can communicate with each other. For example, when A and B are on the phone, when A is talking, B can also talk to interact with information, which is called full-duplex communication. Corresponding to the single-work communication, and half-duplex communication, single-work communication is only from A to B communications, such as computers and printers. Semi-duplex communication is AB can communicate with each other, but at the same time only one-way communication, such as walkie-talkies.

What's the difference between WebSocket and http

Similarities

Are all based on TCP, which transmits data through TCP protocol.

Difference

_HTTP protocol is a one-way protocol, that is, the browser can only request resources from the server, the server can transmit data to the browser, and the server can not actively transfer data to the browser. It is divided into long connection and short connection. Short connection is that each HTTP request needs three shakes of hands to send its own request, each request corresponds to a response; long connection is to maintain the connection in a short time and keep the TCP open continuously, referring to the TCP connection.

_WebSocket is a two-way communication protocol. After establishing a connection, both WebSocket server and client can actively send or receive data to each other. Like Socket, WebSocket is a simple simulation Socket protocol based on Web. WebSocket needs handshake connection, similar to TCP, it also needs handshake between client and server. Connection. Only after successful connection can we communicate with each other. When WebSocket establishes handshake connection, data is transmitted through http protocol, "GET/chat HTTP/1.1", which only uses some simple fields of http protocol. But after the connection is established, the real data transmission phase does not require the participation of http protocol.

Usefulness

_. WebSocket solves the long-term round-robin problem that the client initiates multiple http requests to the server resource browser.

Using WebSocket to Build a Multi-Person Chat System

  1. The jar package for introducing WebSocket

Gradle:

compile group: 'org.springframework.boot', name: 'spring-boot-starter-websocket', version: '2.1.8.RELEASE'

Maven:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
    <version>2.1.8.RELEASE</version>
</dependency>
  1. Add support for WebSocket

Inject ServerEndpoint Exporter, which automatically registers Web ocket endpoint using the @ServerEndpoint annotation declaration.

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

/**
 * @author: zp
 * @Date: 2019-09-18 10:03
 * @Description:
 */
@Configuration
public class AppConfiguration {

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

}
  1. Creating Implementation Classes of WebSocket

The value in@ServerEndpoint("/webSocket/{page}") is the address to be accessed, which is somewhat similar to @RequestMapping in Controller. Then implement @OnOpen, @OnClose, @onMessage, @Error.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author: zp
 * @Date: 2019-09-20 15:12
 * @Description:
 */
@Component
@ServerEndpoint("/webSocket/{page}")
public class WebSocket {
    private Logger log = LoggerFactory.getLogger(this.getClass());

    /**
     * Used to record the number of people in the room
     */
    private static AtomicInteger onlinePersons = new AtomicInteger(0);

    /**
     * Used to record rooms and numbers
     */
    private static Map<String,Set> roomMap = new ConcurrentHashMap(8);

    @OnOpen
    public void open(@PathParam("page") String page, Session session) throws IOException {
        Set set = roomMap.get(page);
        // If it's a new room, create a mapping, and if the room already exists, put the user in.
        if(set == null){
            set = new CopyOnWriteArraySet();
            set.add(session);
            roomMap.put(page,set);
        }else{
            set.add(session);
        }
        // Number of rooms + 1
        onlinePersons.incrementAndGet();
        log.info("new user{}Enter the chat,Number of rooms:{}",session.getId(),onlinePersons);
    }

    @OnClose
    public void close(@PathParam("page") String page, Session session){
        // If a user leaves, the corresponding information is removed.
        if(roomMap.containsKey(page)){
            roomMap.get(page).remove(session);
        }
        // Number of rooms - 1
        onlinePersons.decrementAndGet();
        log.info("user{}Quit chatting,Number of rooms:{}",session.getId(),onlinePersons);
    }

    @OnMessage
    public void reveiveMessage(@PathParam("page") String page, Session session,String message) throws IOException {
        log.info("Accept Users{}Data:{}",session.getId(),message);
        // Stitching together user information
        String msg = session.getId()+" : "+ message;
        Set<Session> sessions = roomMap.get(page);
        // Push messages to all users in the room
        for(Session s : sessions){
            s.getBasicRemote().sendText(msg);
        }
    }

    @OnError
    public void error(Throwable throwable){
        try {
            throw throwable;
        } catch (Throwable e) {
            log.error("unknown error");
        }
    }
}

Write a super simple page test

I'm sorry that I can't write a nice ui with some dishes on the front end. I'm sorry to hear that __________.

<html>
<head>
    <meta charset="UTF-8"></meta>
    <title>springboot project WebSocket test demo</title>
</head>
<body>
<h3>springboot project websocket test demo</h3>
<h4>Test instructions</h4>
<h5>Data in the text box, Click'Send Test',The data in the text box is sent to the background. websocket,When the background receives it, it pushes the data to the front end and displays it below. Click Close Connection to close the connection. websocket;You can track the code to understand the specific process; there are detailed comments on the code</h5>
<br />
<input id="text" type="text" />
<button onclick="send()">Send Test</button>
<hr />
<button onclick="clos()">Close the connection</button>
<hr />
<div id="message"></div>
<script>
    var websocket = null;
    if('WebSocket' in window){
        websocket = new WebSocket("ws://127.0.0.1:9999/webSocket/1");
    }else{
        alert("Your browser does not support it websocket");
    }
    websocket.onerror = function(){
        setMessageInHtml("send error!");
    }
    websocket.onopen = function(){
        setMessageInHtml("Connect successfully!")
        setTimeout(function(){setMessageInHtml("Welcome to here!")
    },2000)
    }
    websocket.onmessage = e => setMessageInHtml(e.data)
    websocket.onclose = function(){
        setMessageInHtml("Connection disconnected!")
    }
    window.onbeforeunload = function(){
        clos();
    }
    function setMessageInHtml(message){
        document.getElementById('message').innerHTML += message+"</br>";
    }
    function clos(){
        websocket.close(3000,"Forced closure");
    }
    function send(){
        var msg = document.getElementById('text').value;
        websocket.send(msg);
    }
</script>
</body>
</html>

test

Postscript

I hope we have a little harvest every day.

If you find it useful, pay attention to me.

Topics: Java Session socket Spring