精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

SpringBoot使用WebSocket實現即時消息

開發 前端
當以jar包形式運行時需要配置該bean,暴露我們配置的@ServerEndpoint;當我們以war獨立tomcat運行時不能配置該bean。這里有個g-messages.js文件是我寫的一個工具類,用來做連接及心跳檢查用的。

環境:SpringBoot2.4.12.


依賴

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

定義消息類型

  • 抽象消息對象
public class AbstractMessage {
  /**
   *   消息類型
   */
  protected String type ;
  
  /**
   *   消息內容
   */
  protected String content ;
  /**
   *   消息日期
   */
  protected String date ;
}

消息對象子類

1、Ping檢查消息

public class PingMessage extends AbstractMessage {
  public PingMessage() {}
  public PingMessage(String type) {
    this.type = type ;
  }
}

2、系統消息

public class SystemMessage extends AbstractMessage {
  public SystemMessage() {}
  public SystemMessage(String type, String content) {
    this.type = type ;
    this.content = content ;
  }
}

3、點對點消息

public class PersonMessage extends AbstractMessage {
  private String fromName ;
  private String toName ;
}

消息類型定義

public enum MessageType {
  
  /**
   *   系統消息 0000;心跳檢查消息 0001;點對點消息2001
   */
  SYSTEM("0000"), PING("0001"), PERSON("2001") ;
  
  private String type ;
  
  private MessageType(String type) {
    this.type = type ;
  }


  public String getType() {
    return type;
  }


  public void setType(String type) {
    this.type = type;
  }
  
}

WebSocket服務端點

該類作用就是定義客戶端連接的地址

@ServerEndpoint(value = "/message/{username}", 
  encoders = {WsMessageEncoder.class},
  decoders = {WsMessageDecoder.class},
  subprotocols = {"gmsg"},
  configurator = MessageConfigurator.class)  
@Component  
public class GMessageListener {  
  
    public static ConcurrentMap<String, UserSession> sessions = new ConcurrentHashMap<>();
    private static Logger logger = LoggerFactory.getLogger(GMessageListener.class) ;
  
    private String username ;
    
    @OnOpen  
    public void onOpen(Session session, EndpointConfig config, @PathParam("username") String username){
      UserSession userSession = new UserSession(session.getId(), username, session) ;
      this.username = username ;
      sessions.put(username, userSession) ;
      logger.info("【{}】用戶進入, 當前連接數:{}", username, sessions.size()) ; 
    }  
  
    @OnClose  
    public void onClose(Session session, CloseReason reason){  
      UserSession userSession = sessions.remove(this.username) ;
      if (userSession != null) {
        logger.info("用戶【{}】, 斷開連接, 當前連接數:{}", username, sessions.size()) ;
      }
    }
    
    @OnMessage
    public void pongMessage(Session session, PongMessage message) {
      ByteBuffer buffer = message.getApplicationData() ;
      logger.debug("接受到Pong幀【這是由瀏覽器發送】:" + buffer.toString());
    }
    
    @OnMessage
    public void onMessage(Session session, AbstractMessage message) {
      if (message instanceof PingMessage) {
        logger.debug("這里是ping消息");
        return ;
      }
      if (message instanceof PersonMessage) {
        PersonMessage personMessage = (PersonMessage) message ;
        if (this.username.equals(personMessage.getToName())) {
          logger.info("【{}】收到消息:{}", this.username, personMessage.getContent());
        } else {
          UserSession userSession = sessions.get(personMessage.getToName()) ;
          if (userSession != null) {
            try {
            userSession.getSession().getAsyncRemote().sendText(new ObjectMapper().writeValueAsString(message)) ;
          } catch (JsonProcessingException e) {
            e.printStackTrace();
          }
          }
        }
        return ;
      }
      if (message instanceof SystemMessage) {
        logger.info("接受到消息類型為【系統消息】") ; 
        return ;
      }
    }
    
    @OnError
    public void onError(Session session, Throwable error) {
      logger.error(error.getMessage()) ;
    }
}

WsMessageEncoder.java類
該類的主要作用是,當發送的消息是對象時,該如何轉換

public class WsMessageEncoder implements Encoder.Text<AbstractMessage> {
  private static Logger logger = LoggerFactory.getLogger(WsMessageDecoder.class) ;
  @Override
  public void init(EndpointConfig endpointConfig) {
  }
  @Override
  public void destroy() {
  }
  @Override
  public String encode(AbstractMessage tm) throws EncodeException {
    String message = null ;
    try {
      message = new ObjectMapper().writeValueAsString(tm);
    } catch (JsonProcessingException e) {
      logger.error("JSON處理錯誤:{}", e) ;
    }
    return message;
  }
}

WsMessageDecoder.java類
該類的作用是,當接收到消息時如何轉換成對象。

public class WsMessageDecoder implements  Decoder.Text<AbstractMessage> {


  private static Logger logger = LoggerFactory.getLogger(WsMessageDecoder.class) ;
  private static Set<String> msgTypes = new HashSet<>() ;
  
  static {
    msgTypes.add(MessageType.PING.getType()) ;
    msgTypes.add(MessageType.SYSTEM.getType()) ;
    msgTypes.add(MessageType.PERSON.getType()) ;
  }
  @Override
  @SuppressWarnings("unchecked")
  public AbstractMessage decode(String s) throws DecodeException {
    AbstractMessage message = null ;
    try {
      ObjectMapper mapper = new ObjectMapper() ;
      Map<String,String> map = mapper.readValue(s, Map.class) ;
      String type = map.get("type") ;
      switch(type) {
        case "0000":
          message = mapper.readValue(s, SystemMessage.class) ;
          break;
        case "0001":
          message = mapper.readValue(s, PingMessage.class) ;
          break;
        case "2001":
          message = mapper.readValue(s, PersonMessage.class) ;
          break;
      }
    } catch (JsonProcessingException e) {
      logger.error("JSON處理錯誤:{}", e) ;
    }
    return message ;
  }


  // 該方法判斷消息是否可以被解碼(轉換)
  @Override
  @SuppressWarnings("unchecked")
  public boolean willDecode(String s) {
    Map<String, String> map = new HashMap<>() ;
    try {
      map = new ObjectMapper().readValue(s, Map.class);
    } catch (JsonProcessingException e) {
      e.printStackTrace();
    }
    logger.debug("檢查消息:【" + s + "】是否可以解碼") ;
    String type = map.get("type") ;
    if (StringUtils.isEmpty(type) || !msgTypes.contains(type)) {
      return false ;
    }
    return true ;
  }
  @Override
  public void init(EndpointConfig endpointConfig) {
  }
  @Override
  public void destroy() {
  }
}

MessageConfigurator.java類
該類的作用是配置服務端點,比如配置握手信息

public class MessageConfigurator extends ServerEndpointConfig.Configurator {
  private static Logger logger = LoggerFactory.getLogger(MessageConfigurator.class) ;
  @Override
  public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
    logger.debug("握手請求頭信息:" + request.getHeaders());
    logger.debug("握手響應頭信息:" + response.getHeaders());
    super.modifyHandshake(sec, request, response);
  }  
}

WebSocke配置類

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

當以jar包形式運行時需要配置該bean,暴露我們配置的@ServerEndpoint;當我們以war獨立tomcat運行時不能配置該bean。

前端頁面

<!doctype html>
<html>
 <head>
  <meta charset="UTF-8">
  <meta name="Author" content="">
  <meta name="Keywords" content="">
  <meta name="Description" content="">
  <script src="g-messages.js?v=1"></script>
  <title>WebSocket</title>
  <style type="text/css">
</style>
  <script>
  let gm = null ;
  let username = null ;
  function ListenerMsg({url, protocols = ['gmsg'], options = {}}) {
    if (!url){ 
      throw new Error("未知服務地址") ;
    }
    gm = new window.__GM({
      url: url,
      protocols: protocols
    }) ;
    gm.open(options) ;
  }
  ListenerMsg.init = (user) => {
    if (!user) {
      alert("未知的當前登錄人") ;
      return ;
    }
    let url = `ws://localhost:8080/message/${user}` ;
    let msg = document.querySelector("#msg")
    ListenerMsg({url, options: {
      onmessage (e) {
        let data = JSON.parse(e.data) ;
        let li = document.createElement("li") ;
        li.innerHTML = "【" + data.fromName + "】對你說:" + data.content ;
        msg.appendChild(li) ;
      }
    }}) ;
  }
  function enter() {
    username = document.querySelector("#nick").value ;
    ListenerMsg.init(username) ;
    document.querySelector("#chat").style.display = "block" ;
    document.querySelector("#enter").style.display = "none" ;
    document.querySelector("#cu").innerText = username ;
  }
  function send() {
    let a = document.querySelector("#toname") ;
    let b = document.querySelector("#content") ;
    let toName = a.value ;
    let content = b.value ;
    gm.sendMessage({type: "2001", content, fromName: username, toName}) ;
    a.value = '' ;
    b.value = '' ;
  }
</script>
 </head>
 <body>
  <div id="enter">
    <input id="nick"/><button type="button" onclick="enter()">進入</button>
  </div>
  <hr/>
  <div id="chat" style="display:none;">
    當前用戶:<b id="cu"></b><br/>
    用戶:<input id="toname" name="toname"/><br/><br/>
    內容:<textarea id="content" rows="3" cols="22"></textarea><br/>
    <button type="button" onclick="send()">發送</button>
  </div>
  <div>
    <ul id="msg">
    </ul>
  </div>
 </body>
</html>

這里有個g-messages.js文件是我寫的一個工具類,用來做連接及心跳檢查用的。

到此所有的代碼完畢,接下來測試

測試

打開兩個標簽頁,以不同的用戶進入。

圖片


圖片


輸入對方用戶名發送消息

圖片


圖片


成功了,簡單的websocket。我們生產環境還就這么完的,8g內存跑了6w的用戶。

責任編輯:武曉燕 來源: Spring全家桶實戰案例源碼
相關推薦

2021-03-25 08:29:33

SpringBootWebSocket即時消息

2025-06-30 01:45:00

Netty輪詢HTTP 協議

2020-10-09 12:45:19

創建消息即時消息編程語言

2020-10-09 15:00:56

實時消息編程語言

2019-09-29 15:25:13

CockroachDBGoJavaScript

2019-10-28 20:12:40

OAuthGuard中間件編程語言

2020-03-31 12:21:20

JSON即時消息編程語言

2020-10-12 09:20:13

即時消息Access頁面編程語言

2020-10-19 16:20:38

即時消息Conversatio編程語言

2020-10-16 14:40:20

即時消息Home頁面編程語言

2021-02-05 07:28:11

SpringbootNettyWebsocke

2015-03-18 15:37:19

社交APP場景

2022-06-28 08:37:07

分布式服務器WebSocket

2020-10-10 20:51:10

即時消息編程語言

2023-07-26 07:28:55

WebSocket服務器方案

2021-03-26 08:16:32

SpringbootWebsocket前端

2024-09-02 09:31:19

2010-05-24 09:51:37

System Cent

2024-11-14 11:56:45

2024-09-12 14:50:08

點贊
收藏

51CTO技術棧公眾號

一本久道综合久久精品| 香蕉大人久久国产成人av| 久久久久成人黄色影片| 日本91av在线播放| 亚洲色图100p| 国产精品xxx在线观看| 欧美日韩一区二区精品| 一区二区三区我不卡| 亚洲成人精品女人久久久| 亚洲欧美日韩综合国产aⅴ| 这里只有视频精品| 国产精品久久久久久亚洲色 | 一区二区视频免费观看| 欧美国产先锋| 亚洲深夜福利网站| 欧美精品色视频| 香蕉成人av| 亚洲午夜久久久久久久久电影院 | 五月天中文字幕一区二区| 任我爽在线视频精品一| www.com在线观看| 日韩精品福利网| 97精品国产97久久久久久| 五月婷婷欧美激情| 人人香蕉久久| 精品久久免费看| 五月天中文字幕在线| 五月天av在线| 亚洲图片自拍偷拍| 三级网在线观看| 国产美女性感在线观看懂色av| 国产成人精品免费视频网站| 国产精品视频自在线| 五月婷婷中文字幕| 欧美日本中文| 麻豆成人在线看| 精品一区二区6| 国产精品日韩精品中文字幕| 日韩精品免费在线| 婷婷五月精品中文字幕| 色播一区二区| 日韩欧美卡一卡二| 涩涩网站在线看| 国产资源一区| 欧美偷拍一区二区| 成人在线观看a| 二区三区不卡| 色综合久久久久综合体桃花网| 福利视频一二区| 深夜国产在线播放| 一区二区三区欧美日| 中文字幕在线观看一区二区三区| 成人精品一区二区三区免费| 国产丝袜在线精品| 日本免费一区二区三区| 可以在线观看的av| 久久久99精品久久| 日韩欧美亚洲日产国产| 国产理论电影在线观看| 久久精品无码一区二区三区| 人偷久久久久久久偷女厕| 日本韩国一区| 久久亚洲精精品中文字幕早川悠里| 韩国精品一区二区三区六区色诱| 丰满肥臀噗嗤啊x99av| 成人一区二区三区视频在线观看 | 国产精品少妇在线视频| 一呦二呦三呦精品国产| 欧美日韩三级一区| 加勒比av中文字幕| 精品午夜av| 精品国产在天天线2019| 中文字幕乱码在线| 视频国产一区| 日韩一二三在线视频播| 欧美黑人精品一区二区不卡| 亚洲国产一区二区精品专区| 5252色成人免费视频| 五月天激情四射| 日韩高清不卡一区| 91免费看片在线| 性色av蜜臀av| 2022国产精品视频| 亚洲欧洲免费无码| 性xxxfreexxxx性欧美| 亚洲一区二区3| 777米奇影视第四色| 日本一区二区中文字幕| 日韩免费电影一区| 国产三级视频网站| 亚洲国产一成人久久精品| 国外色69视频在线观看| 波多野结衣在线观看视频| 狠狠狠色丁香婷婷综合激情| 国产伦精品一区二区三区视频免费 | 久久在线91| 91精品中国老女人| 姝姝窝人体www聚色窝| 国产日韩精品久久久| 玖玖精品在线视频| 91av亚洲| 日韩一区二区在线看| 西西444www无码大胆| 1024精品久久久久久久久| 91国内精品久久| 国产精品久久久久久久成人午夜| 成人avav影音| 在线观看免费黄色片| 亚洲欧美韩国| 日韩欧美一二三区| 无码人妻丰满熟妇啪啪欧美| 亚洲成人资源| 成人免费自拍视频| 韩国三级在线观看久| 亚洲激情校园春色| av在线网址导航| 亚洲警察之高压线| 欧美另类极品videosbestfree| 激情网站在线观看| av亚洲产国偷v产偷v自拍| 香蕉精品视频在线| 成人性生交大片免费网站 | 国产精品久久精品| 日韩专区第一页| 一区二区三区四区蜜桃| 一区二区三区免费播放| 亚洲精品推荐| 51午夜精品视频| 污污视频在线免费看| 亚洲男人的天堂在线观看| 男人插女人下面免费视频| 亚洲激情播播| 欧美孕妇孕交黑巨大网站| 亚洲第一视频在线| 亚洲精品久久嫩草网站秘色| 亚洲欧美自拍另类日韩| 郴州新闻综合频道在线直播| 日韩**中文字幕毛片| 天天操天天射天天舔| 亚洲一区二区欧美| 在线看黄色的网站| 欧美性久久久| av激情久久| 免费在线看电影| 日韩写真欧美这视频| 国产精品免费人成网站酒店 | 国产精品免费观看在线| 你懂的视频在线| 色中色一区二区| www.自拍偷拍| 丝袜美腿亚洲综合| 手机在线观看国产精品| 成人全视频在线观看在线播放高清| 国产性猛交xxxx免费看久久| 中文字幕第315页| 国产精品少妇自拍| 免费一区二区三区在线观看 | 国产精品va在线观看无码| 亚洲天堂中文字幕在线观看| 久久久久久久成人| 凸凹人妻人人澡人人添| 欧美日韩亚洲一区二区| 久久久久亚洲av无码a片| 男人的j进女人的j一区| 亚洲一二三区精品| 精品国模一区二区三区欧美| 欧美精品videosex牲欧美| 手机av免费在线观看| 色综合中文综合网| 久久久免费看片| 国产一区二区三区四区五区美女| 久久久国内精品| 欧美日韩麻豆| 国产日韩精品视频| 制服丝袜在线播放| 亚洲精品一区中文字幕乱码| 日韩精品一区不卡| √…a在线天堂一区| 中文字幕第10页| 99国内精品| 亚洲一区二区高清视频| 国产在线不卡一区二区三区| 韩国一区二区电影| 不卡在线视频| 日韩欧美成人午夜| 精产国品一区二区| 亚洲免费资源在线播放| 99久久人妻精品免费二区| 日韩成人av影视| 欧美视频在线第一页| 亚洲资源网站| 91免费在线观看网站| 国产精欧美一区二区三区蓝颜男同| 中文字幕国产精品久久| 性猛交xxxx乱大交孕妇印度| 色狠狠色狠狠综合| 欧美成人综合色| 国产三级精品视频| 国产香蕉精品视频| 另类综合日韩欧美亚洲| 国产婷婷一区二区三区| 四虎成人精品永久免费av九九| 99久久精品久久久久久ai换脸| 人人视频精品| 久久久久久久爱| 欧美尤物美女在线| 亚洲精品自拍第一页| 国产欧美熟妇另类久久久 | 91av久久久| 欧美日韩亚洲国产一区| 手机在线免费看毛片| 国产欧美日产一区| 亚洲啪av永久无码精品放毛片| 老司机免费视频一区二区三区| 国产精品久久中文字幕| **女人18毛片一区二区| 亚洲精品一区二| 日韩黄色网络| 国产91视觉| 国产激情一区| 国产精品网址在线| 欧美香蕉视频| 999精品一区| 中文日韩在线| 97精品国产97久久久久久粉红| 久久91麻豆精品一区| 高清国产在线一区| 国产精品**亚洲精品| 国产精品96久久久久久| 成人性生交大片免费看网站| 久久精品国产亚洲精品| 成人免费高清在线播放| 国产视频综合在线| 欧美一级片免费| 欧美r级在线观看| www.激情五月| 欧美一区二区视频在线观看2020 | 欧美人妖巨大在线| 最近中文在线观看| 91国内精品野花午夜精品| 欧美性猛交bbbbb精品| 懂色av一区二区三区| 日本天堂网在线观看| 亚洲国产精品一区二区久久 | 99re久久精品国产| 成人国产一区二区三区精品| 性折磨bdsm欧美激情另类| 国产黄色成人av| 男人添女人荫蒂国产| 激情成人综合网| 日韩高清在线一区二区| 国产一区二区美女| 色偷偷中文字幕| 粉嫩嫩av羞羞动漫久久久| 一级全黄裸体片| 丁香五精品蜜臀久久久久99网站 | 露出调教综合另类| 国产日韩三区| 亚洲宅男网av| 亚洲 日韩 国产第一区| 国产精品7m凸凹视频分类| 在线观看三级网站| 欧美日韩三级| 日本十八禁视频无遮挡| 麻豆91精品| 五月天激情视频在线观看| 麻豆国产91在线播放| 丰满饥渴老女人hd| av资源站一区| 国产精品免费无码| 1区2区3区精品视频| 久久久久久久久久久久久久免费看 | 内射一区二区三区| 亚洲一区二区影院| 在线能看的av| 欧美日韩亚洲国产综合| www.蜜臀av.com| 亚洲精品午夜精品| 日韩毛片久久久| 久久久免费精品视频| 一区二区三区四区日本视频| 成人激情免费在线| 加勒比色老久久爱综合网| 亚洲精品一区二区毛豆| 午夜精品av| 日本男人操女人| 国产高清精品在线| 精品无人区无码乱码毛片国产| 亚洲婷婷国产精品电影人久久| 久久网中文字幕| 91成人网在线| 亚洲国产精品久久人人爱潘金莲 | 免费污网站在线观看| 亚洲天天做日日做天天谢日日欢| 国产视频91在线| 欧美美女bb生活片| 香蕉av一区二区三区| 久久精品国产69国产精品亚洲| www.超碰在线| 91久久精品国产| 嫩草一区二区三区| 97中文字幕在线| 久久精品国产一区二区三区免费看| 91超薄肉色丝袜交足高跟凉鞋| 国产精品视频免费| 成人免费区一区二区三区| 制服丝袜亚洲网站| 男人av在线| 欧美精品精品精品精品免费| 国产91欧美| 欧美激情国产日韩| 欧美视频在线观看| 污污网站免费看| 久久久久久夜精品精品免费| 国产在线综合网| 5858s免费视频成人| 国产在线色视频| 91精品国产91| 91国内精品| 大片在线观看网站免费收看| 日本va欧美va精品| 加勒比一区二区| 午夜精品一区在线观看| 精品国产99久久久久久宅男i| 在线观看不卡av| 自拍偷自拍亚洲精品被多人伦好爽| 俄罗斯精品一区二区| 亚洲综合婷婷| 污网站在线免费| 国产精品入口麻豆九色| 亚洲AV无码成人精品区东京热| 亚洲精品videossex少妇| 欧美日韩在线视频免费观看| 成人美女av在线直播| 亚洲成av人电影| 狠狠干狠狠操视频| 国产精品久久影院| 中文字幕人妻一区二区三区视频 | 国产精品视频看看| 日韩欧美亚洲综合| 天堂√在线中文官网在线| 91精品国产乱码久久久久久蜜臀| 国产精品美女在线观看直播| 精品成在人线av无码免费看| 国产精品18久久久久久久久 | 欧美搞黄网站| 国产精品91av| 亚洲高清一区二区三区| 可以免费看毛片的网站| 97人人做人人爱| 亚欧日韩另类中文欧美| 成人午夜视频免费在线观看| 久久久久国产精品麻豆ai换脸 | av最新在线观看| 欧美二区乱c少妇| 最新国产露脸在线观看| 99久久精品免费看国产一区二区三区| 亚洲午夜极品| 国产毛片毛片毛片毛片毛片毛片| 婷婷丁香激情综合| 毛片免费在线| 国产精品色视频| 久久精品久久久| www.美色吧.com| 欧美日韩在线视频一区| 国产美女视频一区二区三区| 国产深夜精品福利| 欧美日韩午夜| 日本xxxx裸体xxxx| 欧美性欧美巨大黑白大战| 国产精品va在线观看视色| 国产精品久久波多野结衣| 久久av一区| 搜索黄色一级片| 亚洲精品aⅴ中文字幕乱码| 成人va天堂| 中国老女人av| 99久久国产综合精品麻豆| 欧美一区二区三区久久久| 久久精品影视伊人网| 国产厕拍一区| 国产一二三四在线视频| 亚洲视频免费在线| 五月天福利视频| 国产精品自产拍在线观| 欧美日韩一区二区三区四区在线观看| 黄色录像a级片| 欧美高清你懂得| 精精国产xxxx视频在线野外| 亚洲精品在线免费看| 成人h动漫精品一区二| 中文字幕+乱码+中文乱码91| 欧美极品xxxx| 欧美激情电影| 国产又粗又长又爽| 欧美日韩第一区日日骚| 色老头在线一区二区三区| 异国色恋浪漫潭| 久久久久久亚洲综合| 亚洲精品字幕在线观看|