国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Spring Boot 實現(xiàn) WebSocket實時數(shù)據(jù)推送-服務(wù)端】

這篇具有很好參考價值的文章主要介紹了【Spring Boot 實現(xiàn) WebSocket實時數(shù)據(jù)推送-服務(wù)端】。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

一、WebSocket配置類
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * @author HFL
 * @date 2022/5/16 14:49
 * 配置類
 */
@Configuration
public class WebSocketConfiguration {

    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
    
}
二、WebSocket服務(wù)端類
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;

/**
 * @author HFL
 * @date 2022/5/16 15:17
 * Websocket應(yīng)用實現(xiàn):
 *  1.建立連接,連接放入連接池
 *  2.關(guān)閉連接,連接移出連接池
 *  3.接收客戶端發(fā)送的消息,并做出相應(yīng)處理
 *  4.注入業(yè)務(wù)層的service
 *  [注意:Spring管理的Bean是單例模式的,而WebSocket不是單例,注入時需要處理一下]
 *  5.異常處理,連接移除連接池
*/
@Slf4j
@Component
@ServerEndpoint("/endPoint/{screen}")
public class WebSocketServer {

    /**
     * 建立連接成功調(diào)用 (Session + 場景)
     */
    @OnOpen
    public void onOpen(Session session,@PathParam("screen") String screen) throws IOException {
        log.info("[onOpen][session({}) 接入, [screen: {}]", session, screen);
        WebSocketServerPool.addDataConnect(session, screen);
        //WebSocketServerPool.sendMessage(session, configurationScreenService.queryAllJsonById(screen));
    }

    /**
     * 關(guān)閉連接時調(diào)用
     * @param session 連接
     */
    @OnClose
    public void onClose(Session session, CloseReason closeReason) {
        log.info("[onClose][session({}) 連接關(guān)閉。關(guān)閉原因是({})}]", session, closeReason);
        WebSocketServerPool.removeConnect(session);
    }

    /**
     * 錯誤時調(diào)用
     * @param session 連接
     * @param throwable 異常
     */
    @OnError
    public void onError(Session session, Throwable throwable) {
        log.info("[onClose][session({}) 發(fā)生異常]", session, throwable);
        WebSocketServerPool.removeConnect(session);
    }

    /**
     * 收到客戶端信息后,根據(jù)接收到的信息進(jìn)行處理
     * @param session 連接
     * @param message 數(shù)據(jù)消息
     */
    @OnMessage
    public void onMessage(Session session, String message) {
        log.info("[onOpen][session({}) 接收到一條消息({})]", session, message);
        // TODO: 2022/5/18 對于客戶端發(fā)送的指令信息,解析后進(jìn)行對應(yīng)的邏輯處理
    }

}
三、WebSocket的連接池類
import javax.websocket.Session;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @author HFL
 * @date 2022/5/16 9:39
 * Websocket連接池、對連接池內(nèi)連接操作 和數(shù)據(jù)推送方法
 */
public class WebSocketServerPool {

    /**
     * WebSocket連接池
     */
    private static ConcurrentMap<Session, String> dataConnect = new ConcurrentHashMap<>();

    /**
     * 將websocket連接,放入連接池
     * @param session websocket連接
     * @param screen 場景ID
     */
    public static void addDataConnect(Session session, String screen){
        dataConnect.put(session, screen);
        Iterator<Map.Entry<Session, String>> iterator = dataConnect.entrySet().iterator();
        synchronized (iterator){
            //移除失效連接
            while(iterator.hasNext()){
                Map.Entry<Session, String> entry = iterator.next();
                Session sessionNew = entry.getKey();
                Map<String, Object> userProperties = sessionNew.getUserProperties();
                if(null != userProperties && null != userProperties.get("ReadyState") && "0" != String.valueOf(userProperties.get("ReadyState"))){
                    iterator.remove();
                }
            }
        }
    }

    /**
     * 將websocket連接從連接池中移除
     * @param session websocket連接
     */
    public static void removeConnect(Session session){
        Iterator<Map.Entry<Session, String>> iterator = dataConnect.entrySet().iterator();
        synchronized (iterator){
            //主動移除連接
            while (iterator.hasNext()){
                if(session.equals(iterator.next().getKey())){
                    iterator.remove();
                }
            }
        }
    }

    /**
     * 獲取連接池中所有連接
     * @return 連接池所有數(shù)據(jù)
     */
    public static ConcurrentMap<Session, String> getDataConnect(){
        return dataConnect;
    }

    /**
     * Websocket消息推送
     * @param session 連接
     * @param message 消息主體
     * @throws IOException I/O異常
     */
    public static void sendMessage(Session session, String message) throws IOException {
        session.getBasicRemote().sendText(message);
    }
}
四、啟動Spring Boot服務(wù)
import com.ljgk.ems.maitreya.user.annotation.EnableLoginArgResolver;
import com.ljgk.ems.maitreya.validator.config.EnableFormValidator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.EnableScheduling;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * @author HFL
 * @date 2022/5/13 8:40
 * 僅做測試,只需要@SpringBootApplication注釋即可,
 * 其他注釋,用于其他的功能,例如:
 *   @EnableScheduling用于掃描開啟定時任務(wù)即@Scheduled注解的方法
 */
@SpringBootApplication
@EnableDiscoveryClient
@Configuration
@EnableFeignClients(value = {"com.ljgk.ems.maitreya"})
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
@Slf4j
@EnableLoginArgResolver
@EnableFormValidator
@EnableScheduling
public class ServerApplication {

    public static void main(String[] args) throws UnknownHostException {
        ConfigurableApplicationContext application = SpringApplication.run(ConfigurationServerApplication.class, args);
    }
    
}
五、測試WebSocket連接
  1. WebSocket在線測試工具:
    http://www.easyswoole.com/wstool.html
  2. 測試連接
    服務(wù)地址:ws://172.18.42.29:14785/endPoint/1
    服務(wù)啟動的IP:172.18.42.29
    服務(wù)端口:14785
    WS的URl:/endPoint
    入?yún)ⅲ?
    【Spring Boot 實現(xiàn) WebSocket實時數(shù)據(jù)推送-服務(wù)端】
六、遇到的問題
  1. 服務(wù)啟動報錯:
    【Spring Boot 實現(xiàn) WebSocket實時數(shù)據(jù)推送-服務(wù)端】

    2022-06-09 10:31:27.616:[ERROR] [main:18941] [org.springframework.boot.SpringApplication.reportFailure:826] --> Application run failed 
    java.lang.IllegalStateException: Failed to register @ServerEndpoint class: class com.ljgk.ems.maitreya.configuration.websocket.WebSocketServer$$EnhancerBySpringCGLIB$$8a624780
    	at org.springframework.web.socket.server.standard.ServerEndpointExporter.registerEndpoint(ServerEndpointExporter.java:159)
    	at org.springframework.web.socket.server.standard.ServerEndpointExporter.registerEndpoints(ServerEndpointExporter.java:134)
    	at org.springframework.web.socket.server.standard.ServerEndpointExporter.afterSingletonsInstantiated(ServerEndpointExporter.java:112)
    	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:896)
    	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878)
    	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
    	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
    	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
    	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
    	at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
    	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
    	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
    	at com.ljgk.ems.maitreya.ConfigurationServerApplication.main(ConfigurationServerApplication.java:36)
    Caused by: javax.websocket.DeploymentException: UT003027: Class class com.ljgk.ems.maitreya.configuration.websocket.WebSocketServer$$EnhancerBySpringCGLIB$$8a624780 was not annotated with @ClientEndpoint or @ServerEndpoint
    	at io.undertow.websockets.jsr.ServerWebSocketContainer.addEndpointInternal(ServerWebSocketContainer.java:735)
    	at io.undertow.websockets.jsr.ServerWebSocketContainer.addEndpoint(ServerWebSocketContainer.java:628)
    	at org.springframework.web.socket.server.standard.ServerEndpointExporter.registerEndpoint(ServerEndpointExporter.java:156)
    	... 12 common frames omitted
    

    原因:
    WebSocketServer類被代理了,我出現(xiàn)這個問題的原因是做了整個項目的接口攔截,然后做了接口的日志切面處理,導(dǎo)致這個類被代理了,而@ServerEndpoint注解在處理WebSocketServer時,取到了代理的類,無法處理導(dǎo)致的異常。

    解決辦法:

    ? 將WebSocketServer類從日志處理的切面中排除掉即可。

  2. 加入業(yè)務(wù)處理時報錯:
    【Spring Boot 實現(xiàn) WebSocket實時數(shù)據(jù)推送-服務(wù)端】

    java.lang.NullPointerException: null
    	at com.ljgk.ems.maitreya.configuration.websocket.WebSocketServer.onOpen(WebSocketServer.java:47)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:497)
    	at io.undertow.websockets.jsr.annotated.BoundMethod.invoke(BoundMethod.java:87)
    	at io.undertow.websockets.jsr.annotated.AnnotatedEndpoint$3.run(AnnotatedEndpoint.java:158)
    	at io.undertow.websockets.jsr.ServerWebSocketContainer$1.call(ServerWebSocketContainer.java:170)
    	at io.undertow.websockets.jsr.ServerWebSocketContainer$1.call(ServerWebSocketContainer.java:167)
    

    原因:
    通過注解@Resource自動注入的ConfigurationScreenService的Bean為空,即Spring容器中,ConfigurationScreenService沒有注入進(jìn)去,因為Spring管理的Bean的作用域和WebSocket的作用域不同,Spring管理的Bean都是單例,WebSocket不是。
    解決辦法:

    ? 將截圖中通過@Resource注解注入ConfigurationScreenService的方式換成下面方式:

    /**
     * @author HFL
     * @date 2022/5/16 15:17
     * Websocket應(yīng)用實現(xiàn):
     *  1.建立連接,連接放入連接池
     *  2.關(guān)閉連接,連接移出連接池
     *  3.接收客戶端發(fā)送的消息,并做出相應(yīng)處理
     *  4.注入業(yè)務(wù)層的service
     *  [注意:Spring管理的Bean是單例模式的,而WebSocket不是單例,注入時需要處理一下]
     *  5.異常處理,連接移除連接池
    */
    @Slf4j
    @Component
    @ServerEndpoint("/endPoint/{screen}")
    public class WebSocketServer {
    
        private static ConfigurationScreenService configurationScreenService;
    
        @Resource
        public void setConfigurationScreenService(ConfigurationScreenService configurationScreenService){
            WebSocketServer.configurationScreenService = configurationScreenService;
        }
    
        /**
         * 建立連接成功調(diào)用 (Session + 場景ID)
         */
        @OnOpen
        public void onOpen(Session session,@PathParam("screen") String screen) throws IOException {
            log.info("[onOpen][session({}) 接入, [screen: {}]", session, screen);
            WebSocketServerPool.addDataConnect(session, screen);
            WebSocketServerPool.sendMessage(session, configurationScreenService.queryAllJsonById(screen));
        }
    	
    	...
    
    }
    
七、擴(kuò)展(實現(xiàn)實時推送數(shù)據(jù))
  • 定時任務(wù),輪詢連接池中的連接,并取到對于的場景、綁定的設(shè)備,即可查詢最新數(shù)據(jù),最后推送至客戶端。(最簡單實現(xiàn))

    import cn.hutool.json.JSONUtil;
    import com.ljgk.ems.maitreya.configuration.entity.Content;
    import com.ljgk.ems.maitreya.configuration.service.ConfigurationScreenDataService;
    import com.ljgk.ems.maitreya.configuration.vm.ScreenDataJsonVm;
    import com.ljgk.ems.maitreya.configuration.websocket.WebSocketServerPool;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.Resource;
    import javax.websocket.Session;
    import java.io.IOException;
    import java.util.List;
    import java.util.concurrent.ConcurrentMap;
    
    /**
     * @author HFL
     * @date 2022/6/88:35
     */
    @Slf4j
    @Component
    public class ScreenPushScheduledTask {
    
        @Resource
        private ConfigurationScreenDataService configurationScreenDataService;
    
        /**
         * 5秒一次
         * 定時場景數(shù)據(jù)推送
         */
        @Scheduled(cron = "0/5 * * * * ? ")
        public void executeScreenDataPush(){
            try {
                ConcurrentMap<Session, String> dataConnect = WebSocketServerPool.getDataConnect();
                //查詢待推送場景
                dataConnect.keySet().forEach(session -> {
                    try {
                        String screen = dataConnect.get(session);
                        //查詢需要的場景對應(yīng)的元件需要的值,并按規(guī)則組裝成JSON
                        List<ScreenDataJsonVm> screenDataJsonVms = configurationScreenDataService.queryDataJson(screen);
                        WebSocketServerPool.sendMessage(session, JSONUtil.toJsonStr(screenDataJsonVms));
                    } catch (IOException e) {
                        log.error("WebSocket SendMessage Error, Session:[{}], Exception : [{}]", session, e.getMessage());
                    }
                });
            }catch (Exception e){
                log.error("WebSocket Scheduler Executor Error : [{}]", e.getMessage());
            }
        }
    
    }
    
  • 監(jiān)聽Binlog日志,將MySql中變化數(shù)據(jù)取出,推送至客戶端。

  • RocketMq實現(xiàn),將變化數(shù)據(jù)寫入隊列,WS服務(wù)端消費(fèi)隊列中數(shù)據(jù)時,推送至客戶端。

八、參考

1. WebSocket原理及技術(shù)簡介
2. Java實現(xiàn)WebSocket服務(wù)端
3. Java Websocket——服務(wù)器端
4.【W(wǎng)ebSocket】SpringBoot整合WebSocket 注入Bean的方式文章來源地址http://www.zghlxwxcb.cn/news/detail-424830.html

到了這里,關(guān)于【Spring Boot 實現(xiàn) WebSocket實時數(shù)據(jù)推送-服務(wù)端】的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Spring Boot集成WebSocket實現(xiàn)消息推送

    Spring Boot集成WebSocket實現(xiàn)消息推送

    項目中經(jīng)常會用到消息推送功能,關(guān)于推送技術(shù)的實現(xiàn),我們通常會聯(lián)想到輪詢、comet長連接技術(shù),雖然這些技術(shù)能夠?qū)崿F(xiàn),但是需要反復(fù)連接,對于服務(wù)資源消耗過大,隨著技術(shù)的發(fā)展,HtML5定義了WebSocket協(xié)議,能更好的節(jié)省服務(wù)器資源和帶寬,并且能夠更實時地進(jìn)行通訊。

    2023年04月08日
    瀏覽(21)
  • webSocket實現(xiàn)數(shù)據(jù)的實時推送(附:前后端代碼)

    ? ? ? ? 之前開發(fā)的一個管理系統(tǒng)項目中,首頁是數(shù)據(jù)大屏展示,一開始我是用JS的 setInterval() 方法,設(shè)置一個時間,每過時間發(fā)起一次 ajax 請求。雖然也能湊活著用,但總感覺不是最優(yōu)的方法,而且還比較占用資源,所以學(xué)習(xí) WebSocke ,以下是本人的一些學(xué)習(xí)心得及前后端的

    2024年02月02日
    瀏覽(22)
  • Spring Boot整合WebSocket實現(xiàn)實時通信,前端實時通信,前后端實時通信

    實時通信在現(xiàn)代Web應(yīng)用中扮演著越來越重要的角色,無論是在線聊天、股票價格更新還是實時通知,WebSocket都是實現(xiàn)這些功能的關(guān)鍵技術(shù)之一。Spring Boot作為一個簡化企業(yè)級應(yīng)用開發(fā)的框架,其對WebSocket的支持也非常友好。本文將詳細(xì)介紹如何在Spring Boot中整合WebSocket,實現(xiàn)一

    2024年04月27日
    瀏覽(51)
  • WebSocket:實現(xiàn)實時互動、數(shù)據(jù)推送的利器,你了解多少

    WebSocket:實現(xiàn)實時互動、數(shù)據(jù)推送的利器,你了解多少

    WebSocket技術(shù)是一種基于TCP協(xié)議的全雙工通信協(xié)議,它允許瀏覽器和服務(wù)器之間進(jìn)行實時、雙向的通信。相比傳統(tǒng)的HTTP請求-響應(yīng)模式,WebSocket提供了持久連接,可以實時地推送數(shù)據(jù),減少了通信的延遲。 WebSocket的工作原理是通過建立一條持久連接來實現(xiàn)實時通信。首先,瀏覽

    2024年01月18日
    瀏覽(22)
  • vue和node使用websocket實現(xiàn)數(shù)據(jù)推送,實時聊天

    vue和node使用websocket實現(xiàn)數(shù)據(jù)推送,實時聊天

    需求:node做后端根據(jù)websocket,連接數(shù)據(jù)庫,數(shù)據(jù)庫的字段改變后,前端不用刷新頁面也能更新到數(shù)據(jù),前端也可以發(fā)送消息給后端,后端接受后把前端消息做處理再推送給前端展示 使用node ./app.js運(yùn)行項目 在需要使用websocket連接的頁面引入 默認(rèn)如下: id為243 在數(shù)據(jù)庫改為

    2024年02月15日
    瀏覽(30)
  • Vue使用WebSocket實現(xiàn)實時獲取后端推送的數(shù)據(jù)。

    Vue可以使用WebSocket實現(xiàn)實時獲取后端推送的數(shù)據(jù)。 1.在Vue項目中安裝WebSocket庫 可以使用npm或yarn安裝WebSocket庫: 2.創(chuàng)建WebSocket連接 在Vue組件中創(chuàng)建WebSocket連接,連接到后端WebSocket服務(wù)器,代碼如下: 上面的代碼中,使用WebSocket連接到后端WebSocket服務(wù)器,通過監(jiān)聽onmessage事件,

    2024年02月08日
    瀏覽(26)
  • 實現(xiàn)實時互動:用Spring Boot原生WebSocket打造你的專屬聊天室

    實現(xiàn)實時互動:用Spring Boot原生WebSocket打造你的專屬聊天室

    ?? @ 作者: 一恍過去 ?? @ 主頁: https://blog.csdn.net/zhuocailing3390 ?? @ 社區(qū): Java技術(shù)棧交流 ?? @ 主題: 實現(xiàn)實時互動:用Spring Boot原生WebSocket打造你的專屬聊天室 ?? @ 創(chuàng)作時間: 2023年08月04日 WebSocket 實現(xiàn)聊天室的原理包括建立 WebSocket 連接的握手過程、保持連接狀態(tài)以

    2024年02月10日
    瀏覽(25)
  • Spring Boot進(jìn)階(49):實時通信不再是夢想,SpringBoot+WebSocket助你輕松實現(xiàn)前后端即時通訊!

    Spring Boot進(jìn)階(49):實時通信不再是夢想,SpringBoot+WebSocket助你輕松實現(xiàn)前后端即時通訊!

    ????????在上一期,我對WebSocket進(jìn)行了基礎(chǔ)及理論知識普及學(xué)習(xí),WebSocket是一種基于TCP協(xié)議實現(xiàn)的全雙工通信協(xié)議,使用它可以實現(xiàn)實時通信,不必?fù)?dān)心HTTP協(xié)議的短連接問題。Spring Boot作為一款微服務(wù)框架,也提供了輕量級的WebSocket集成支持,本文將介紹如何在Spring Boot項

    2024年02月11日
    瀏覽(21)
  • Spring Boot 3 + Vue 3 整合 WebSocket (STOMP協(xié)議) 實現(xiàn)廣播和點對點實時消息

    Spring Boot 3 + Vue 3 整合 WebSocket (STOMP協(xié)議) 實現(xiàn)廣播和點對點實時消息

    ?? 作者主頁: 有來技術(shù) ?? 開源項目: youlai-mall ?? vue3-element-admin ?? youlai-boot ?? 倉庫主頁: Gitee ?? Github ?? GitCode ?? 歡迎點贊 ?? 收藏 ?留言 ?? 如有錯誤敬請糾正! WebSocket是一種在Web瀏覽器與Web服務(wù)器之間建立雙向通信的協(xié)議,而Spring Boot提供了便捷的WebSocket支持

    2024年02月02日
    瀏覽(18)
  • kafak消費(fèi)數(shù)據(jù),webSocket實時推送數(shù)據(jù)到前端

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包