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

SpringBoot2.0集成WebSocket

這篇具有很好參考價值的文章主要介紹了SpringBoot2.0集成WebSocket。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

適用于單客戶端,一個賬號登陸一個客戶端,登陸多個客戶端會報錯

The remote endpoint was in state [TEXT_FULL_WRITING]?

這是因為此時的session是不同的,只能鎖住一個session,解決此問題的方法把全局靜態(tài)對象鎖住,因為賬號是唯一的

http://t.csdn.cn/e6LjH
        <!-- websocket -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

新建配置類

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * @Description 開啟springboot對websocket的支持
 * @Author WangKun
 * @Date 2023/8/14 17:21
 * @Version
 */
@ConditionalOnProperty(name = "spring.profiles.active", havingValue = "dev")
@Configuration
public class WebSocketConfig{

    /**
     * @Description 注入一個ServerEndpointExporter, 會自動注冊使用@ServerEndpoint注解
      * @param
     * @Throws
     * @Return org.springframework.web.socket.server.standard.ServerEndpointExporter
     * @Date 2023-08-14 17:26:31
     * @Author WangKun
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}
@ConditionalOnProperty(name = "spring.profiles.active", havingValue = "dev")

這個注解需要打上聲明是開發(fā)環(huán)境,否則在tomcat部署中會報錯

新建服務(wù)類

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.stereotype.Component;

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

/**
 * @Description websocket服務(wù),不考慮分組
 * @Author WangKun
 * @Date 2023/8/14 17:29
 * @Version
 */
@ConditionalOnClass(value = WebSocketConfig.class)
@ServerEndpoint("/websocket/{userId}")
@Component
@Slf4j
public class WebSocket {
     //在線計數(shù)器
    private static int onlineCount = 0;
    //存放每個客戶端對應(yīng)的WebSocket對象。
    private static final ConcurrentHashMap<String, WebSocket> WEB_SOCKET_MAP = new ConcurrentHashMap<>();

    //與某個客戶端的連接會話,需要通過它來給客戶端發(fā)送數(shù)據(jù)
    private Session session;
    private String userId;

    /**
     * @param
     * @Description 在線數(shù)
     * @Throws
     * @Return int
     * @Date 2023-08-14 17:47:19
     * @Author WangKun
     */
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    /**
     * @param
     * @Description 在線數(shù)加1
     * @Throws
     * @Return void
     * @Date 2023-08-14 17:47:32
     * @Author WangKun
     */
    public static synchronized void addOnlineCount() {
        WebSocket.onlineCount++;
    }

    /**
     * @param
     * @Description 在線數(shù)減1
     * @Throws
     * @Return void
     * @Date 2023-08-14 17:47:47
     * @Author WangKun
     */
    public static synchronized void subOnlineCount() {
        WebSocket.onlineCount--;
    }

    /**
     * @param session
     * @param userId
     * @Description 建立連接
     * @Throws
     * @Return void
     * @Date 2023-08-14 17:52:08
     * @Author WangKun
     */
    @OnOpen
    public void onOpen(final Session session, @PathParam("userId") String userId) {
        this.session = session;
        this.userId = userId;
        // 防止前端刷新重連用戶重復(fù),存在計數(shù)器不累加
        if (WEB_SOCKET_MAP.containsKey(userId)) {
            WEB_SOCKET_MAP.remove(userId);
            WEB_SOCKET_MAP.put(userId, this);
        } else {
            WEB_SOCKET_MAP.put(userId, this);
            addOnlineCount();
        }
        sendMessage(String.valueOf(ResponseCode.CONNECT_SUCCESS.getCode())); //自定義成功返回碼
        log.info("用戶--->{} 連接成功,當(dāng)前在線人數(shù)為--->{}", userId, getOnlineCount());
    }

    /**
     * @param message
     * @Description 向客戶端發(fā)送消息 session.getBasicRemote()與session.getAsyncRemote()的區(qū)別
     * @Throws
     * @Return void
     * @Date 2023-08-14 17:51:07
     * @Author WangKun
     */
    public void sendMessage(String message) {
        try {
            // 加鎖避免阻塞
             synchronized (session){
                 this.session.getBasicRemote().sendText(message);
             }
        } catch (IOException e) {
            log.error("向客戶端發(fā)送消息--->{}", e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

    /**
     * @param
     * @Description 關(guān)閉連接
     * @Throws
     * @Return void
     * @Date 2023-08-14 17:52:30
     * @Author WangKun
     */
    @OnClose
    public void onClose(Session session) {
        if (!WEB_SOCKET_MAP.isEmpty()  && WEB_SOCKET_MAP.containsKey(userId)) {
            this.session = session;
            WEB_SOCKET_MAP.remove(userId);
            subOnlineCount();
            log.info("用戶--->{} 關(guān)閉連接!當(dāng)前在線人數(shù)為--->{}", userId, getOnlineCount());
        }
    }

    /**
     * @param message
     * @param session
     * @Description 收到客戶端消息
     * @Throws
     * @Return void
     * @Date 2023-08-15 10:54:55
     * @Author WangKun
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        //這一塊可以操作數(shù)據(jù),比如存到數(shù)據(jù)

        //判斷心跳是否存活, 防止心跳自動斷開,再重連
        synchronized (session) {
          if ("ping".equalsIgnoreCase(message) && !WEB_SOCKET_MAP.isEmpty() && WEB_SOCKET_MAP.containsKey(userId)) {
            WEB_SOCKET_MAP.get(userId).sendMessage("pong");
           }
          log.info("收到來自客戶端用戶:{} 消息:--->{}", userId, message);
        }
    }

    /**
     * @param session
     * @param error
     * @Description 發(fā)生錯誤時
     * @Throws
     * @Return void
     * @Date 2023-08-15 10:55:27
     * @Author WangKun
     */
    @OnError
    public void onError(Session session, Throwable error) {
        if (!WEB_SOCKET_MAP.isEmpty() && WEB_SOCKET_MAP.containsKey(userId)) {
            WEB_SOCKET_MAP.remove(userId);
            subOnlineCount();
            log.error("用戶--->{} 錯誤!" + userId, "原因--->{}" + error.getMessage());
            error.printStackTrace();
        }
    }

    /**
     * @param userId
     * @param message
     * @Description 通過userId向客戶端發(fā)送消息(指定用戶發(fā)送)
     * @Throws
     * @Return void
     * @Date 2023-08-14 18:01:35
     * @Author WangKun
     */
    public static void sendTextMessageByUserId(String userId, String message) {
        log.info("服務(wù)端發(fā)送消息到用戶{},消息:{}", userId, message);
        if (!WEB_SOCKET_MAP.isEmpty() && StringUtils.isNotBlank(userId) && WEB_SOCKET_MAP.containsKey(userId)) {
            WEB_SOCKET_MAP.get(userId).sendMessage(message);
        } else {
            log.error("用戶{}不在線", userId);
        }
    }

    /**
     * @param message
     * @Description 群發(fā)自定義消息
     * @Throws
     * @Return void
     * @Date 2023-08-14 18:03:38
     * @Author WangKun
     */
    public static void sendTextMessage(String message) {
        // 如果在線一個就廣播
        log.info("廣播數(shù)據(jù)到當(dāng)前在線人,人數(shù):{}", getOnlineCount());
        if (getOnlineCount() > 0 && !WEB_SOCKET_MAP.isEmpty()) {
            for (String item : WEB_SOCKET_MAP.keySet()) {
                WEB_SOCKET_MAP.get(item).sendMessage(message);
                log.info("服務(wù)端發(fā)送消息到用戶{},消息:{}", item, message);
            }
        }
    }
}

@ConditionalOnClass(value = WebSocketConfig.class)

指定使用自定義配置文件文章來源地址http://www.zghlxwxcb.cn/news/detail-674943.html

到了這里,關(guān)于SpringBoot2.0集成WebSocket的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

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

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

相關(guān)文章

  • 【SpringBoot2】SpringBoot開發(fā)實用篇

    【SpringBoot2】SpringBoot開發(fā)實用篇

    ? 什么是熱部署?簡單說就是你程序改了,現(xiàn)在要重新啟動服務(wù)器,嫌麻煩?不用重啟,服務(wù)器會自己悄悄的把更新后的程序給重新加載一遍,這就是熱部署。 ? 熱部署的功能是如何實現(xiàn)的呢?這就要分兩種情況來說了,非springboot工程和springboot工程的熱部署實現(xiàn)方式完全

    2023年04月25日
    瀏覽(31)
  • 1、Springboot2簡介

    在學(xué)習(xí) SpringBoot 之前,建議先具備 SpringMVC(控制層)、Spring(業(yè)務(wù)層)和 Mybatis(持久層)的相關(guān)知識 Spring 框架雖然很出色,但是有一個明顯的缺點(diǎn):配置文件過于繁瑣和復(fù)雜; 在單體項目中,因為配置文件只需要編寫一遍即可,所以該缺點(diǎn)只是一個小問題; 在微服務(wù)項目

    2024年02月05日
    瀏覽(22)
  • SpringBoot2-核心技術(shù)(一)

    SpringBoot2-核心技術(shù)(一)

    1. properties 同以前的用法 2. yaml YAML : “YAML Ain‘t Markup Language ”(yaml 不是一種遞歸標(biāo)記語言) 的遞歸縮寫, 在開發(fā)這種語言時,YAML 的意思是:Yet Another Markup Language (仍是一種標(biāo)記語言) 非常適合用來做以數(shù)據(jù)為中心的配置文件 1. 基本語法 key: value ; value與: 之間存在空格

    2024年02月07日
    瀏覽(16)
  • SpringBoot2.0(Lombok,SpringBoot統(tǒng)一返回封裝)

    SpringBoot2.0(Lombok,SpringBoot統(tǒng)一返回封裝)

    ? java工程中,我們要創(chuàng)建很多的java Bean。這些javaBean中都會寫getter,setter,equals,hashCode和toString的模板代碼,這些代碼都沒啥技術(shù)含量。 ? 那么我們就是使用Lombok來自動生成這些代碼,通過注解的方式。提高我們的工作效率。 ? Lombok的原理:JSR 269插件化注解處理。就是在

    2024年02月09日
    瀏覽(22)
  • 【SpringBoot】SpringBoot2.x知識點(diǎn)雜記

    本文僅供學(xué)習(xí)交流使用 為什么要使用 Spring Boot 因為Spring, SpringMVC 需要使用的大量的配置文件 (xml文件) 還需要配置各種對象,把使用的對象放入到spring容器中才能使用對象 需要了解其他框架配置規(guī)則。 SpringBoot 就相當(dāng)于 不需要配置文件的Spring+SpringMVC。 常用的框架和第三

    2024年02月03日
    瀏覽(19)
  • 3、SpringBoot2之配置文件

    3、SpringBoot2之配置文件

    在 Spring Boot 工程中,實行統(tǒng)一的配置管理,即所有參數(shù)配置都會集中到一個固定位置和命名的文件中; 配置文件的固定位置是在 src/main/resources 目錄下,該目錄是 Spring Boot 工程默認(rèn)的類路徑(classpath); 配置文件的命名格式為:application+后綴+擴(kuò)展名,擴(kuò)展名可以是 propert

    2024年02月04日
    瀏覽(22)
  • springboot2.7整合springSecurity

    springboot2.7整合springSecurity

    本著前人栽樹,后人乘涼的這種思想,自己花了一些時間,用心的整理了一套springboot整合springsecurity的教程。 該教程是基于springboot2.7.3版本開發(fā)的,在2.7以上版本中,springSecurity已經(jīng)廢棄了WebSecurityConfigurerAdapter,而是使用 bean 注入的方式,詳情可參閱官方文檔:https://spring

    2023年04月21日
    瀏覽(22)
  • 6、SpringBoot2之整合Mybatis

    6、SpringBoot2之整合Mybatis

    創(chuàng)建名為springboot_mybatis的新module,過程參考3.1節(jié) 注意:雖然本文使用的是 spring boot 2.7.18 和 MySQL 5.7 ,但是出于可移植性、可擴(kuò)展性和兼容性方面的考慮, druid 的啟動器使用的是 spring boot 3 版本的,MySQL 的驅(qū)動使用的是 MySQL 8 版本的。 注意:@MapperScan 注解的作用是將指定位置

    2024年02月03日
    瀏覽(29)
  • 8、SpringBoot2之打包及運(yùn)行

    8、SpringBoot2之打包及運(yùn)行

    為了演示高級啟動時動態(tài)配置參數(shù)的使用,本文在SpringBoot2之配置文件的基礎(chǔ)上進(jìn)行 普通的 web 項目,會被打成一個 war 包,然后再將 war 包放到 tomcat 的 webapps 目錄中; 當(dāng) tomcat 啟動時,在 webapps 目錄中的 war 包會自動解壓,此時便可訪問該 web 項目的資源或服務(wù); 因為 spri

    2024年02月03日
    瀏覽(24)
  • Springboot2.0快速入門(第一章)

    Springboot2.0快速入門(第一章)

    Spring是一個開源框架,2003 年興起的一個輕量級的Java 開發(fā)框架,作者:Rod Johnson 。 Spring是為了解決企業(yè)級應(yīng)用開發(fā)的復(fù)雜性而創(chuàng)建的,簡化開發(fā)。 為了降低Java開發(fā)的復(fù)雜性,Spring采用了以下4種關(guān)鍵策略: 1、基于POJO的輕量級和最小侵入性編程,所有東西都是bean; 2、通過

    2024年02月11日
    瀏覽(24)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包