Spring Boot integrates WebSocket to easily push information!

In a project development, the Netty network application framework and MQTT were used to send and receive message data, which requires the background to actively push the obtained messages to the front end. Therefore, MQTT was used, which is hereby recorded.

1, What is websocket?

WebSocket protocol is a new network protocol based on TCP. It realizes the full duplex communication between the client and the server. Everyone who has studied computer network knows that since it is full duplex, it shows that the server can actively send information to the client.

This coincides with our push technology or the function of multiplayer online chat.

Why not use HTTP protocol?

This is because HTTP is simplex communication. Communication can only be initiated by the client. The client requests it and the server handles it, which is too troublesome. So websocket came into being.

Let's start the integration directly with Springboot. The following cases have been tested successfully on my own computer. You can modify them according to your own functions.

My project structure is as follows:

2, Use steps

1. Add dependency

Maven dependency:

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

2. Enable Springboot support for WebSocket

Enabling WebSocket support is also very simple. A few words of code are done:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
 * @ Auther: Ma Chaowei
 * @ Date: 2020/06/16/14:35
 * @ Description: Enable WebSocket support
 */
@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

This is recommended for the latest Spring Boot tutorial: https://github.com/javastacks/spring-boot-best-practice

3. Core configuration: WebSocketServer

Because WebSocket is similar to the form of client and server (using ws protocol), the WebSocket server here is actually equivalent to a Controller of ws protocol

  • @ServerEndpoint annotation is a class level annotation. Its main function is to define the current class as a websocket server. The value of the annotation will be used to listen for the access URL address of the terminal connected by the user. The client can connect to the websocket server through this URL
  • Create a new ConcurrentHashMap webSocketMap, which is used to receive the WebSocket of the current userId to facilitate the push message of userId between transfers.

The following is the specific business code:

package cc.mrbird.febs.external.webScoket;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * Created with IntelliJ IDEA.
 * @ Auther: Ma Chaowei
 * @ Date: 2020/06/16/14:35
 * @ Description:
 * @ ServerEndpoint Annotation is a class level annotation. Its main function is to define the current class as a websocket server,
 * The value of the annotation will be used to monitor the access URL address of the terminal connected by the user. The client can connect to the WebSocket server through this URL
 */
@Component
@Slf4j
@Service
@ServerEndpoint("/api/websocket/{sid}")
public class WebSocketServer {
    //Static variable, used to record the current number of online connections. It should be designed to be thread safe.
    private static int onlineCount = 0;
    //The thread safe Set of concurrent package is used to store the MyWebSocket object corresponding to each client.
    private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();

    //The connection session with a client needs to send data to the client through it
    private Session session;

    //Receive sid
    private String sid = "";

    /**
     * Method successfully called after connection establishment
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        this.session = session;
        webSocketSet.add(this);     //Add to set
        this.sid = sid;
        addOnlineCount();           //Online number plus 1
        try {
            sendMessage("conn_success");
            log.info("A new window starts listening:" + sid + ",The number of people currently online is:" + getOnlineCount());
        } catch (IOException e) {
            log.error("websocket IO Exception");
        }
    }

    /**
     * Method called by connection closure
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);  //Delete from set
        subOnlineCount();           //Online number minus 1
        //When disconnected, update the motherboard occupancy to release
        log.info("Released sid For:"+sid);
        //Here is the business to be handled when you release
        log.info("One connection is closed! The number of people currently online is" + getOnlineCount());

    }

    /**
     * Method of calling after receiving client message
     * @ Param message Messages sent by clients
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("Received from window" + sid + "Information:" + message);
        //Mass messaging
        for (WebSocketServer item : webSocketSet) {
            try {
                item.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @ Param session
     * @ Param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("An error occurred");
        error.printStackTrace();
    }

    /**
     * Realize server active push
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    /**
     * Mass customization message
     */
    public static void sendInfo(String message, @PathParam("sid") String sid) throws IOException {
        log.info("Push message to window" + sid + ",Push content:" + message);

        for (WebSocketServer item : webSocketSet) {
            try {
                //Here, you can set to push only to this sid. If it is null, all will be pushed
                if (sid == null) {
//                    item.sendMessage(message);
                } else if (item.sid.equals(sid)) {
                    item.sendMessage(message);
                }
            } catch (IOException e) {
                continue;
            }
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

    public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() {
        return webSocketSet;
    }
}

4. Test Controller

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 *
 * @ Auther: Ma Chaowei
 * @ Date: 2020/06/16/14:38
 * @ Description:
 */
@Controller("web_Scoket_system")
@RequestMapping("/api/socket")
public class SystemController {
    //Page request
    @GetMapping("/index/{userId}")
    public ModelAndView socket(@PathVariable String userId) {
        ModelAndView mav = new ModelAndView("/socket1");
        mav.addObject("userId", userId);
        return mav;
    }

    //Push data interface
    @ResponseBody
    @RequestMapping("/socket/push/{cid}")
    public Map pushToWeb(@PathVariable String cid, String message) {
        Map<String,Object> result = new HashMap<>();
        try {
            WebSocketServer.sendInfo(message, cid);
            result.put("code", cid);
            result.put("msg", message);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }
}

5. Test page index html

<!DOCTYPE html>
<html>

    <head>
        <meta charset="utf-8">
        <title>Java back-end WebSocket of Tomcat realization</title>
        <script type="text/javascript" src="js/jquery.min.js"></script>
    </head>

    <body>
        <div id="main" style="width: 1200px;height:800px;"></div>
        Welcome<br/><input id="text" type="text" />
        <button onclick="send()">send message</button>
        <hr/>
        <button onclick="closeWebSocket()">close WebSocket connect</button>
        <hr/>
        <div id="message"></div>
    </body>
    <script type="text/javascript">
        var websocket = null;
        //Judge whether the current browser supports WebSocket
        if('WebSocket' in window) {
            //Change to your address
            websocket = new WebSocket("ws://192.168.100.196:8082/api/websocket/100");
        } else {
            alert('Current browser Not support websocket')
        }

        //Callback method with connection error
        websocket.onerror = function() {
            setMessageInnerHTML("WebSocket Connection error");
        };

        //Callback method for successful connection establishment
        websocket.onopen = function() {
            setMessageInnerHTML("WebSocket Connection successful");
        }
        var U01data, Uidata, Usdata
        //Callback method for receiving message
        websocket.onmessage = function(event) {
            console.log(event);
            setMessageInnerHTML(event);
            setechart()
        }

        //Callback method for connection closure
        websocket.onclose = function() {
            setMessageInnerHTML("WebSocket Connection closed");
        }

        //Listen for window closing events. When the window is closed, take the initiative to close the websocket connection to prevent closing the window before the connection is disconnected, and the server side will throw exceptions.
        window.onbeforeunload = function() {
            closeWebSocket();
        }

        //Display messages on Web pages
        function setMessageInnerHTML(innerHTML) {
            document.getElementById('message').innerHTML += innerHTML + '<br/>';
        }

        //Close WebSocket connection
        function closeWebSocket() {
            websocket.close();
        }

        //send message
        function send() {
            var message = document.getElementById('text').value;
            websocket.send('{"msg":"' + message + '"}');
            setMessageInnerHTML(message + "&#13;");
        }
    </script>

</html>

6. Result display

backstage:

If there is a connection request

Foreground display:

summary

In this case, I encountered a problem, that is, when WebSocket starts up, it takes precedence over the spring container, which leads to calling Service in WebSocketServer and reporting null pointer exceptions.

Therefore, you need to statically initialize the required service s in WebSocketServer:

As shown in the figure:

The following configuration is also required:

Original link: https://blog.csdn.net/MacWx/article/details/111319558

Copyright notice: This is Mr. Dashu, the blogger of CSDN The original article follows CC 4.0 BY-SA copyright agreement. Please attach the source link of the original text and this statement for reprint.

Recent hot article recommendations:

1.600 + Java interview questions and answers (2021 latest edition)

2.Finally got the IntelliJ IDEA activation code through the open source project. It's really fragrant!

3.Ali Mock tools are officially open source and kill all Mock tools on the market!

4.Spring Cloud 2020.0.0 is officially released, a new and subversive version!

5.Java development manual (Songshan version) is the latest release. Download it quickly!

Feel good, don't forget to like + forward!

Added by Michan on Sat, 19 Feb 2022 17:48:16 +0200