Build a simple multi-user chat system based SpringBoot + WebSocket

Foreword

  Today nothing else, take a look at the WebSocket protocol. Simply look at it.

What is WebSocket

  First, look at what WebSocket that? WebSocket protocol is a full duplex communication over a single TCP connection. This is that, in a TCP connection, mutual communication can communicate a more official statement, the point is simple. For example, A and B on the phone, talking all the time A, B can talk to interact with information, which is called full-duplex communication. Corresponds to simplex communication, and half duplex communication, the communication is only simplex communication from A to B, such as computers and printers. AB half duplex communication can communicate with each other, but at the same time only one-way communication, such as walkie-talkie.

Http WebSocket and what's the difference

Http relationship with the WebSocket

Same point

  They are built on top of TCP, TCP protocol to transmit data through.

difference

  HTTP protocol is a one-way agreement, the browser can only request resources from the server, the server can transmit the data to the browser and the server can not take the initiative to deliver data to the browser. Divided into short and long connection connection, short connection is required each three-way handshake to send their request http request, each request corresponds to a response; long link is a short time to stay connected constantly to keep TCP open, referring to the TCP connections.

  WebSocket a two-way communication protocol, after the connection is established, WebSocket server and client can take the initiative to send or receive data to each other, just as Socket, the difference is a simple WebSocket is a simulation based on the establishment of the Web Socket protocol; WebSocket need handshaking, it also needs similar to TCP client and server-side handshake, to communicate with each other after a successful connection. WebSocket handshake when establishing the connection, the data is transmitted through the http protocol, "GET / chat HTTP / 1.1", there is only used a few simple http protocol fields. But after the connection is established, the actual data transmission stage is not required to participate in the http protocol.

usefulness

  WebSocket solve the client to initiate multiple http requests to the server resources browser must go through a long period of polling problems.

Use WebSocket to build a multi-user chat system

  1. Jar package introduced 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 WebSocket support

  Injection ServerEndpointExporter, the bean will be automatically registered to use @ServerEndpoint annotation statement Websocket endpoint.

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. Create a WebSocket implementation class

  @ServerEndpoint ( "/ webSocket / {page}") is the address value need to access, and the Controller @RequestMapping somewhat similar. Then implement @OnOpen (open connection), @ OnClose (close connection), @ onMessage (message is received), @ Error (trigger an exception).

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());

    /**
     * 用来记录房间的人数
     */
    private static AtomicInteger onlinePersons = new AtomicInteger(0);

    /**
     * 用来记录房间及人数
     */
    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(set == null){
            set = new CopyOnWriteArraySet();
            set.add(session);
            roomMap.put(page,set);
        }else{
            set.add(session);
        }
        // 房间人数+1
        onlinePersons.incrementAndGet();
        log.info("新用户{}进入聊天,房间人数:{}",session.getId(),onlinePersons);
    }

    @OnClose
    public void close(@PathParam("page") String page, Session session){
        // 如果某个用户离开了,就移除相应的信息
        if(roomMap.containsKey(page)){
            roomMap.get(page).remove(session);
        }
        // 房间人数-1
        onlinePersons.decrementAndGet();
        log.info("用户{}退出聊天,房间人数:{}",session.getId(),onlinePersons);
    }

    @OnMessage
    public void reveiveMessage(@PathParam("page") String page, Session session,String message) throws IOException {
        log.info("接受到用户{}的数据:{}",session.getId(),message);
        // 拼接一下用户信息
        String msg = session.getId()+" : "+ message;
        Set<Session> sessions = roomMap.get(page);
        // 给房间内所有用户推送信息
        for(Session s : sessions){
            s.getBasicRemote().sendText(msg);
        }
    }

    @OnError
    public void error(Throwable throwable){
        try {
            throw throwable;
        } catch (Throwable e) {
            log.error("未知错误");
        }
    }
}

Write a super simple page to test

  The front end la carte, write nice ui, forgive me ~

<html>
<head>
    <meta charset="UTF-8"></meta>
    <title>springboot项目WebSocket测试demo</title>
</head>
<body>
<h3>springboot项目websocket测试demo</h3>
<h4>测试说明</h4>
<h5>文本框中数据数据,点击‘发送测试’,文本框中的数据会发送到后台websocket,后台接受到之后,会再推送数据到前端,展示在下方;点击关闭连接,可以关闭该websocket;可以跟踪代码,了解具体的流程;代码上有详细注解</h5>
<br />
<input id="text" type="text" />
<button onclick="send()">发送测试</button>
<hr />
<button onclick="clos()">关闭连接</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("您的浏览器不支持websocket");
    }
    websocket.onerror = function(){
        setMessageInHtml("send error!");
    }
    websocket.onopen = function(){
        setMessageInHtml("连接成功!")
        setTimeout(function(){setMessageInHtml("欢迎来到这里!")
    },2000)
    }
    websocket.onmessage = e => setMessageInHtml(e.data)
    websocket.onclose = function(){
        setMessageInHtml("连接断开!")
    }
    window.onbeforeunload = function(){
        clos();
    }
    function setMessageInHtml(message){
        document.getElementById('message').innerHTML += message+"</br>";
    }
    function clos(){
        websocket.close(3000,"强制关闭");
    }
    function send(){
        var msg = document.getElementById('text').value;
        websocket.send(msg);
    }
</script>
</body>
</html>

test

file

postscript

  I hope we have a little harvest day ~

file

If you find it useful to focus on me ~

Guess you like

Origin www.cnblogs.com/menmenz/p/11647822.html