websocket front + back end coordination demo

When I was writing the code today, I used a technology as usual and habitually made the technical document into a word… and saved it for easy reference. Because I have a poor memory, I prefer it. This way of recording bits and pieces~~~, (causing me to collect a lot~~~~), I feel that being alone is not as good as having fun with others, so I want to share some techniques with friends who are new to the industry, because this is also me as a newcomer I accumulated little by little when I just graduated, and I hope it can help others.

One: What is WebSocket

  • WebSocket is a new protocol under HTML5 (the websocket protocol is essentially a tcp-based protocol)
  • It realizes the full-duplex communication between the browser and the server, which can better save server resources and bandwidth and achieve the purpose of real-time communication
  • Websocket is a persistent protocol

Two: The principle of websocket

  1. Websocket stipulates a communication specification. Through a handshake mechanism, a TCP-like connection can be established between the client and the server to facilitate communication between them.
  2. Before the emergence of websockets, web interactions were generally short or long connections based on the http protocol
  3. websocket is a brand new protocol, not part of http stateless protocol, the protocol name is “ws

Advantages: reduce resource consumption; real-time push without waiting for client requests; reduce traffic;
Disadvantages: A small number of browsers do not support it, and different browsers support it in different ways.

Application scenarios: smart large screen, message reminder notification, etc.

Three: Code implementation:

1. Add dependencies

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

2.socket sending entity class

/**
 * @Author: mark
 * @Description: TODO
 * @Date: 2023/05/24/11:37
 * @Version: 1.0
 */
@Data//Define attributes at will
public class MessageBean {
    String type;
    String mes;
}

3.socket configuration class

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

@Component
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}
4. Websocket server
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import weiyu.iot.system.datahouse.bean.WebsocketResp;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
 
/**
 * @ServerEndpoint annotation is a class-level annotation, its function is mainly to define the current class as a websocket server,
 * The value of the annotation will be used to monitor the terminal access URL address of the user connection, and the client can connect to the WebSocket server through this URL
 */
@ServerEndpoint("/Websocket")
@Component
@Slf4j
public class Websocket {
 
    //Record connected clients
    public static Map<String, Session> clients = new ConcurrentHashMap<>();
 
    /**
     * userId is associated with sid (to solve the problem of the same user id connecting to multiple web terminals)
     */
    public static Map<String, Set<String>> conns = new ConcurrentHashMap<>();
 
    private String sid = null;
 
 
 
 
    //Some records send message status
    private static int initFlag =0;
 
    private static int tempFlag =0;
    //Variables to distinguish old and new messages
    private static int sum=0;
    /**
     * The method called after the connection is successful
     * @param session
     *
     */
    @OnOpen
    public void onOpen(Session session) {
        this.sid = UUID.randomUUID().toString();
 
        clients. put(this. sid, session);
 
        log.info(this.sid + "Connection open!");
    }
 
    /**
     * The method to call when the connection is closed
     */
    @OnClose
    public void onClose() {
        log.info(this.sid + "Connection disconnected!");
        clients. remove(this. sid);
    }
 
    /**
     * Method to determine whether to connect
     * @return
     */
    public static boolean isServerClose() {
        if (Websocket. clients. values(). size() == 0) {
            log.info("disconnected");
            return true;
        } else {
            log.info("connected");
            return false;
        }
    }
 
    /**
     * Sent to all users
     * @param noticeType
     */
 
    public static boolean sendMessage(String noticeType,int count){

        if (sum != count){
            WebsocketResp noticeWebsocketResp = new WebsocketResp();
            noticeWebsocketResp.setNoticeType(noticeType);
            sendMessage(noticeWebsocketResp);
            sum = count;
        }
        //Determine whether the front end has replied or received the message. Equal but not received, not equal. Received
        if (initFlag==tempFlag){
            WebsocketResp noticeWebsocketResp = new WebsocketResp();
            noticeWebsocketResp.setNoticeType(noticeType);
            sendMessage(noticeWebsocketResp);
        } else {
            tempFlag = initFlag;
            log.info("Received the message, don't send the same message");
            return true;
        }
        tempFlag = initFlag;
        log.info("Continue sending if no message is received");
        return false;
    }
 
 
    /**
     * Sent to all users
     * @param websocketResp
     */
    public static void sendMessage(WebsocketResp websocketResp){
        String message = JSONObject.toJSONString(websocketResp);
        for (Session session1 : Websocket. clients. values()) {
            try {
                session1.getBasicRemote().sendText(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
 
    /**
     * Send to a certain user according to the user id
     * **/
    public static void sendMessageByUserId(String userId, WebsocketResp websocketResp) {
        if (!StringUtils. isEmpty(userId)) {
            String message = JSONObject.toJSONString(websocketResp);
            Set<String> clientSet = conns. get(userId);
            if (clientSet != null) {
                Iterator<String> iterator = clientSet. iterator();
                while (iterator. hasNext()) {
                    String sid = iterator. next();
                    Session session = clients. get(sid);
                    if (session != null) {
                        try {
                            session.getBasicRemote().sendText(message);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
 
 
    /**
     * The method called after receiving the client message
     * @param message
     * @param session
     */
 
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("Received message from window" + ":" + message);
        if ("Message has been received".equals(message)){
            //Receive the message, change the value of the flag
            System.out.println("The front end has received the message and started to change the value of initFlag, at this time initFlag=" + initFlag);
            initFlag = initFlag + 1;
            System.out.println("The front end has received the message, and the value of initFlag has been changed, at this time initFlag== " + initFlag);
        }
 
    }
 
    /**
     * Callback function when an error occurs
     * @param error
     */
    @OnError
    public void onError(Throwable error) {
        log.info("Error");
        error. printStackTrace();
    }

5. Take a small test

5.1: Control layer

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import weiyu.iot.system.common.bean.Response;
import weiyu.iot.system.common.bean.ResponseResult;
import weiyu.iot.system.datahouse.bean.MessageBean;
import weiyu.iot.system.datahouse.service.RecycleCustomerService;


/**
 * @Author mark
 * @Description TODO
 * @Date 2023/05/24/14:51
 * @Version 1.0
 */

@RestController
@RequestMapping("/socket")
public class SoketCmd {

    @Autowired
    RecycleCustomerService recycleCustomerService;

@GetMapping("/test")
    public ResponseResult test() {
        MessageBean messageBean = new MessageBean();
        messageBean.setType("aaaa");
        messageBean.setMes("The voltage is too high");
        recycleCustomerService. sendMes(messageBean);
        return Response. OK();
    }
}

5.2: Interface layer

import weiyu.iot.system.datahouse.bean.MessageBean;

/**
 * @Author: mark
 * @Description: TODO
 * @Date: 2023/05/24/13:47
 * @Version: 1.0
 */
public interface RecycleCustomerService {
     void sendMes(MessageBean messageBean);
}

5.3 Implementation layer

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import weiyu.iot.system.datahouse.bean.MessageBean;
import weiyu.iot.system.datahouse.service.RecycleCustomerService;
import weiyu.iot.system.datahouse.socket.Websocket;


@Service("recycleCustomerService")
@Slf4j
public class RecycleCustomerServiceImpl implements RecycleCustomerService {
 
private static int count=0;
@Autowired
private Websocket websocket;

 
@Override
public void sendMes(MessageBean messageBean){
//Test websocket, realize new customers push messages to the front end, until the front end replies
boolean flag = false;
do {
try {
Thread.sleep(300); //Rest for 300 milliseconds
} catch (InterruptedException e) {
e.printStackTrace();
log.error("Error while resting~~~~~~~");
}
//Send a message to the front end
boolean resultFlag = websocket.sendMessage("Real-time data: " + messageBean.toString(),count);
 
flag = resultFlag;
 
if (resultFlag){
log.info("Stop sending data to the front end, because the resultFlag is: {}, indicating that the front end has received the message", resultFlag);
} else {
log.info("Send data to the front end, because resultFlag is: {}", resultFlag);
}
}while ( !flag );
log.info("Stop sending data to the front end, because delFlag is: {}", flag);
count = count + 1;
}

Finally create an html file:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SseEmitter</title>
</head>
<body>
<div id="message"></div>
</body>
<script>
    var limitConnect = 0;
    init();
    function init() {
        //Enable the ip address of the webstocket service ws:// + ip address + access path
        var ws = new WebSocket('ws://127.0.0.1:11002/Websocket');
// get connection status
        console.log('ws connection status:' + ws.readyState);
//Monitor whether the connection is successful
        ws.onopen = function () {
            console.log('ws connection status:' + ws.readyState);
            limitConnect = 0;
            //Send a data if the connection is successful
            ws.send('We have established a connection');
        }
// Listen to the information sent back by the server and process the display
        ws.onmessage = function (data) {
            console.log('Received message from server:');
            console. log(data);
            // After receiving the message, send it to the backend to confirm receipt of the message, and the backend will not repeat the message after receiving it
            ws.send('The message has been received');
            //Close the WebSocket connection after completing the communication
            // ws. close();
        }
// listen for connection close event
        ws.onclose = function () {
            // Monitor the status of websocket during the whole process
            console.log('ws connection status:' + ws.readyState);
            reconnect();
 
        }
// Listen and handle error events
        ws.onerror = function (error) {
            console. log(error);
        }
    }
    function reconnect() {
        limitConnect++;
        console.log("Reconnection" + limitConnect + "time");
        setTimeout(function(){
            init();
        },2000);
 
    }
</script>
</html>
 

Start the service, then open the html file and F12 to see the effect~

This is the rendering of my test:

I try to write as complete as possible and hope it will be useful to everyone! ! !