天天看點

WebSocket後端調用前端總結

所需依賴

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

實體類

import lombok.Data;

@Data
public class NoticeWebsocketResp {
    //通知類型
    private String noticeType;

    //通知内容
    private Object noticeInfo;
}

           

保持連接配接的Bean

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

@Configuration
public class WebSocketConfig {

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

配置類

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;


@Slf4j
@Component
@ServerEndpoint(value = "/SetRulesLogsend/{buildingId}")
public class SetRulesLogSocket { //記錄連接配接的用戶端
        public static Map<String, Session> clients = new ConcurrentHashMap<>();

        /**
         * buildingId關聯sid(解決同一使用者id,在多個web端連接配接的問題)
         */
        public static Map<String, Set<String>> conns = new ConcurrentHashMap<>();

        private String sid = null;

        private String buildingId;


        /**
         * 連接配接成功後調用的方法
         * @param session
         * @param buildingId
         */
        @OnOpen
        public void onOpen(Session session, @PathParam("buildingId") String buildingId) {
            this.sid = UUID.randomUUID().toString();
            this.buildingId = buildingId;
            clients.put(this.sid, session);

            Set<String> clientSet = conns.get(buildingId);

            if (clientSet==null){
                clientSet = new HashSet<>();
                conns.put(buildingId,clientSet);
            }
            clientSet.add(this.sid);
            log.info(this.sid + "連接配接開啟!");
        }

        /**
         * 連接配接關閉調用的方法
         */
        @OnClose
        public void onClose() {
            log.info(this.sid + "連接配接斷開!");
            clients.remove(this.sid);
        }

        /**
         * 判斷是否連接配接的方法
         * @return
         */
        public static boolean isServerClose() {
            if (SetRulesLogSocket.clients.values().size() == 0) {
                log.info("已斷開");
                return true;
            }else {
                log.info("已連接配接");
                return false;
            }
        }

        /**
         * 發送給所有使用者
         * @param noticeType
         */
        public static void sendMessage(String noticeType){
            NoticeWebsocketResp noticeWebsocketResp = new NoticeWebsocketResp();
            noticeWebsocketResp.setNoticeType(noticeType);
            sendMessage(noticeWebsocketResp);
        }


        /**
         * 發送給所有使用者
         * @param noticeWebsocketResp
         */
        public static void sendMessage(NoticeWebsocketResp noticeWebsocketResp){
            String message = JSONObject.toJSONString(noticeWebsocketResp);
            for (Session session1 : SetRulesLogSocket.clients.values()) {
                try {
                    session1.getBasicRemote().sendText(message);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        /**
         * 根據buildingId-id發送給某一個使用者
         * **/
        public static void sendMessageBybuildingId(String buildingId, NoticeWebsocketResp noticeWebsocketResp) {
            if (!StringUtils.isEmpty(buildingId)) {
                String message = JSONObject.toJSONString(noticeWebsocketResp);
                Set<String> clientSet = conns.get(buildingId);
                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();
                            }
                        }
                    }
                }
            }
        }

        /**
         * 收到用戶端消息後調用的方法
         * @param message
         * @param session
         */
        @OnMessage
        public void onMessage(String message, Session session) {
            log.info("收到來自項目"+this.buildingId+"的資訊:"+message);
        }

        /**
         * 發生錯誤時的回調函數
         * @param error
         */
        @OnError
        public void onError(Throwable error) {
            log.info("錯誤");
            error.printStackTrace();
        }
}
           

測試類

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.iot.base.entity.SetRulesLog;
import com.iot.base.service.ISetRulesLogService;
import com.iot.common.api.ApiResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@RestController
public class wsController {
    @Autowired
    private ISetRulesLogService setRulesLog;
    @Autowired
    private SetRulesLogSocket socket;
    @GetMapping("/test")
    public ApiResult test() {
    //擷取需要的資料通過sendMessageBybuildingId類發送給對應的會話
        List<SetRulesLog> list = setRulesLog.list(Wrappers.<SetRulesLog>lambdaQuery().eq(SetRulesLog::getReadStatus, 0));
        Map<String, List<SetRulesLog>> collect = list.stream().collect(Collectors.groupingBy(SetRulesLog::getBuildId));
        collect.forEach((k,v)->{
            NoticeWebsocketResp noticeWebsocketResp = new NoticeWebsocketResp();
            noticeWebsocketResp.setNoticeType(k);
            noticeWebsocketResp.setNoticeInfo(v);
            socket.sendMessageBybuildingId(k,noticeWebsocketResp);
        });
        return ApiResult.ok();
    }
}
           

前端代碼

<!DOCTYPE HTML>
<html>
<head>
        <meta charset="UTF-8">
        <title>My WebSocket</title>
        <style>
            #message{
        margin-top: 40px;
        border: 1px solid gray;
        padding:20px;
                }
        </style>
</head>
<body>
<button onclick="conectWebSocket()">連接配接WebSocket</button>
<button onclick="closeWebSocket()">斷開連接配接</button>
<hr />
<br />
消息:<input id="text" type="text" />
<button onclick="send()">發送消息</button>
<div id="message"></div>
</body>
<script type="text/javascript">
    var websocket = null;
    function conectWebSocket(){
        //判斷目前浏覽器是否支援WebSocket
        if ('WebSocket'in window) {
            // 連接配接資訊 我的兩個測試頁面隻有該處不同
            //websocket = new WebSocket("ws://localhost:8082/SetRulesLogsend/7");
            websocket = new WebSocket("ws://localhost:8082/SetRulesLogsend/8");
        } else {
            alert('Not support websocket')
        }
        //連接配接發生錯誤的回調方法
        websocket.onerror = function() {
            setMessageInnerHTML("error");
        };
        //連接配接成功建立的回調方法
        websocket.onopen = function(event) {
            setMessageInnerHTML("Loc MSG: 成功建立連接配接");
        }
        //接收到消息的回調方法
        websocket.onmessage = function(event) {
            setMessageInnerHTML(event.data);
        }
        //連接配接關閉的回調方法
        websocket.onclose = function() {
            setMessageInnerHTML("Loc MSG:關閉連接配接");
        }
        //監聽視窗關閉事件,當視窗關閉時,主動去關閉websocket連接配接,防止連接配接還沒斷開就關閉視窗,server端會抛異常。
        window.onbeforeunload = function() {
            websocket.close();
        }
    }
    //将消息顯示在網頁上
    function setMessageInnerHTML(innerHTML) {
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }
    //關閉連接配接
    function closeWebSocket() {
        websocket.close();
    }
    //發送消息
    function send() {
        var message = document.getElementById('text').value;
        websocket.send(message);
    }
</script>
</html>

           

測試結果:

WebSocket後端調用前端總結

總結:WebSocket後端調用前端非自動進行,需要線程來觸發此代碼實作向前端通訊。做需求時需要考慮怎麼觸發