Spring Boot integrates Websocket communication

introduce

Websocket is a persistent protocol that implements full-duplex communication between the browser and the server. Instead of having a response only after the browser sends a request like HTTP, WebSocket enables the server to actively send a message to the browser.

Spring Boot project integration implementation

  1. Add dependencies in pom.xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
Copy the code
  1. Integrate the TextWebSocketHandler class or implement the AbstractWebSocketHandler interface
@Component public class WebSocketMsgHandler extends TextWebSocketHandler { private final Logger logger = LoggerFactory.getLogger(WebSocketMsgHandler.class); Public static ConcurrentHashMap<String, WebSocketSession> SESSIONS = new ConcurrentHashMap<>(); public static ConcurrentHashMap<String, WebSocketSession> SESSIONS = new ConcurrentHashMap<>(); @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { String userId = (String) session.getAttributes().get("userId"); WebSocketSession old = SESSIONS.get(userId); // TODO removes old connections of the current node. In multi-instance multi-node deployment, old sessions of other nodes can be removed through MQ broadcast messages. = null && ! old.getId().equals(session.getId())) { String oldId = old.getId(); old.sendMessage(new TextMessage("logout")); old.close(); Logger. info(" Delete old connections, current connections :{},session key:{},session ID :{}", sessions.size (), userId,oldId); } SESSIONS.put(userId, session); Logger. info(" Open connection, current connection number :{}, Session Key :{},session ID :{}", session.size (), userId, session.getid ()); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { String userId = (String) session.getAttributes().get("userId"); SESSIONS.remove(userId); Logger. info(" Connection closed, current connection number :{},session key:{}", sessions.size (), userId); } @Override public void handleTransportError(WebSocketSession session, Throwable e) throws Exception { String userId = (String) session.getAttributes().get("userId"); Logger. info(" connection failed,userId: + userId+ "," + LLDB etMessage(), e); } @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { String userId = (String) session.getAttributes().get("userId"); Logger. info(" received front-end push message,userId:{}, message content :{} ", userId, message); } /** * If it is a service cluster, the node on which the user's session is located cannot be determined * In this case, MQ can be used to broadcast the message to each service node. After the service node receives the broadcast message, * @param userId * @param message * @throws IOException */ public static void sendMsg(String userId, String message) throws IOException { WebSocketSession session = SESSIONS.get(userId); if (session ! = null) { if (session.isOpen()) { session.sendMessage(new TextMessage(message)); return; } SESSIONS.remove(userId); }}}Copy the code
  1. Websocket configuration
@Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Autowired private WebSocketMsgHandler webSocketMsgHandler; @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { HandshakeInterceptor HandshakeInterceptor = new handshakeInterceptor () {// Call @override public Boolean before handling the handshake beforeHandshake(ServerHttpRequest req, ServerHttpResponse resp, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {// // String userId = ((ServletServerHttpRequest) req).getServletRequest().getParameter("userId"); // attributes.put("userId",userId); return true; } @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception Exception) {// Call after handshake}}; registry.addHandler(webSocketMsgHandler, "/websocket") .addInterceptors(handshakeInterceptor) .setAllowedOrigins("*"); registry.addHandler(webSocketMsgHandler, "/websocket_sockjs").addInterceptors(handshakeInterceptor) // cross-domain.setallowedOrigins ("*") // To enable SockJS, the front-end needs to import the sockjs.js library and connect with.withsockjs () as SockJS; }}Copy the code
  1. Native WebSocket front-end sample page, using the WS protocol
<! DOCTYPEHTML>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <base href="http://localhost:8080/">
    <title>My WebSocket</title>
</head>
<body lang="en">
<table>
    <tr>
        <td style="width: 80px; text-align: right;">The url address:</td>
        <td>
            <input id="websocket_url" type="text" value=Ws: / / "127.0.0.1:2001 / websocket." "/>
            <button onclick="openWs()" >Open</button>
            <button onclick="closeWs()" >Close</button>
        </td>
    </tr>
    <tr>
        <td style="width: 80px; text-align: right;">User id:</td>
        <td><input id="userId" type="text" value="123456"/></td>
    </tr>
    <tr>
        <td style="width: 80px; text-align: right;">Message:</td>
        <td>
            <input id="msg" type="text"/>
            <button onclick="send()">Send</button>
        </td>
    </tr>
</table>
<div>Server push message:</div>
<div id="message" style="border: 1px solid grey; width: 600px; min-height: 150px;"></div>
</body>

<script type="text/javascript">
    var websocket = null;
    var isOpen = false;
    function openWs() {
        if(websocket ! =null) {
            websocket.close();
        }
        var ws_url = document.getElementById('websocket_url').value;
        var userId = document.getElementById('userId').value;
        websocket = new WebSocket(ws_url + "? userId=" + userId);

        // Connection error callback method
        websocket.onerror = function (e) {
            setMessageInnerHTML("error");
            console.info("error:");
            console.info(e);
        };

        // The callback method for successfully establishing the connection
        websocket.onopen = function (event) {
            isOpen = true;
            setMessageInnerHTML("open");
            console.info("onopen:");
            console.info(event)
        }
        // The callback method that received the message
        websocket.onmessage = function (event) {
            setMessageInnerHTML(event.data);
        }
        // A callback method to close the connection
        websocket.onclose = function (e) {
            isOpen = false;
            setMessageInnerHTML("close");
            console.info("onclose:");
            console.info(e); }}// Close the connection
    function closeWs() {
        if(websocket ! =null) { websocket.close(); }}// Listen for window closing events, when the window is closed, actively close websocket connection, to prevent the connection is not closed, the server will throw exceptions.
    window.onbeforeunload = function () {
        closeWs();
    }

    // Displays the message on the web page
    function setMessageInnerHTML(innerHTML) {
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }

    // Send a message
    function send() {
        if(! isOpen) { setMessageInnerHTML("websocket is close");
            return;
        }
        var message = document.getElementById('msg').value;
        websocket.send(message);
    }
</script>
</html>
Copy the code
  1. Native SOckJS front-end example page, using HTTP protocol, need to import sockjs.js library
<! DOCTYPE HTML> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <base href="http://localhost:8080/"> <title>My WebSocket < / title > < script SRC = "https://cdn.bootcdn.net/ajax/libs/sockjs-client/1.5.0/sockjs.js" > < / script > < / head > < body lang="en"> <table> <tr> <td style="width: 80px; text-align: right;" > url: < / td > < td > < input id = "websocket_url" type = "text" value = "http://127.0.0.1:2001/websocket_sockjs" / > < button onclick="openWs()" >Open</button> <button onclick="closeWs()" >Close</button> </td> </tr> <tr> <td style="width: 80px; text-align: right;" > user id: < / td > < td > < input id = "userId" type = "text" value = "123456" / > < / td > < / tr > < tr > < td style = "width: 80 px; text-align: right;" > message: < / td > < td > < input id = "MSG" type = "text" / > < button onclick = "send ()" > send < / button > < / td > < / tr > < / table > < div > server push message: </div> <div id="message" style="border: 1px solid grey; width: 600px; min-height: 150px;" ></div> </body> <script type="text/javascript"> var websocket = null; var isOpen = false; function openWs() { if (websocket ! = null) { websocket.close(); } var ws_url = document.getElementById('websocket_url').value; var userId = document.getElementById('userId').value; websocket = new SockJS(ws_url + "? userId=" + userId); Websocket. onerror = function (e) {setMessageInnerHTML("error"); console.info("error:"); console.info(e); }; Websocket. onopen = function (event) {isOpen = true; setMessageInnerHTML("open"); console.info("onopen:"); Console. info(event)} websocket. onMessage = function (event) {setMessageInnerHTML(event.data); } // websocket.onclose = function (e) {isOpen = false; setMessageInnerHTML("close"); console.info("onclose:"); console.info(e); Function closeWs() {if (websocket! = null) { websocket.close(); }} // Listen for window closing events, when the window is closed, actively close the Websocket connection, to prevent the connection is not disconnected to close the window, the server will throw exceptions. window.onbeforeunload = function () { closeWs(); Function setMessageInnerHTML(innerHTML) {document.getelementById ('message').innerhtml += innerHTML + '<br/>'; } function send() {if (! isOpen) { setMessageInnerHTML("websocket is close"); return; } var message = document.getElementById('msg').value; websocket.send(message); } </script> </html>Copy the code