国产精品嫩草99av在线_一区在线视频观看_欧美高清一区_欧美 日韩 国产 一区_99精品欧美一区二区三区_久久大香伊蕉在人线观看热2_一色屋精品视频在线观看网站_在线亚洲国产精品网站_亚洲区一区二区三区_你懂的视频一区二区

當(dāng)前位置:首頁(yè) > 科技  > 軟件

SpringBoot使用WebSocket實(shí)現(xiàn)即時(shí)消息

來(lái)源: 責(zé)編: 時(shí)間:2023-08-14 22:01:09 451觀看
導(dǎo)讀環(huán)境:SpringBoot2.4.12.依賴<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupI

環(huán)境:SpringBoot2.4.12.6eo28資訊網(wǎng)——每日最新資訊28at.com


依賴

<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>

定義消息類型

  • 抽象消息對(duì)象
public class AbstractMessage {  /**   *   消息類型   */  protected String type ;    /**   *   消息內(nèi)容   */  protected String content ;  /**   *   消息日期   */  protected String date ;}

消息對(duì)象子類6eo28資訊網(wǎng)——每日最新資訊28at.com

1、Ping檢查消息6eo28資訊網(wǎng)——每日最新資訊28at.com

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

2、系統(tǒng)消息6eo28資訊網(wǎng)——每日最新資訊28at.com

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

3、點(diǎn)對(duì)點(diǎn)消息6eo28資訊網(wǎng)——每日最新資訊28at.com

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

消息類型定義6eo28資訊網(wǎng)——每日最新資訊28at.com

public enum MessageType {    /**   *   系統(tǒng)消息 0000;心跳檢查消息 0001;點(diǎn)對(duì)點(diǎn)消息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服務(wù)端點(diǎn)

該類作用就是定義客戶端連接的地址6eo28資訊網(wǎng)——每日最新資訊28at.com

@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("【{}】用戶進(jìn)入, 當(dāng)前連接數(shù):{}", username, sessions.size()) ;     }        @OnClose      public void onClose(Session session, CloseReason reason){        UserSession userSession = sessions.remove(this.username) ;      if (userSession != null) {        logger.info("用戶【{}】, 斷開(kāi)連接, 當(dāng)前連接數(shù):{}", username, sessions.size()) ;      }    }        @OnMessage    public void pongMessage(Session session, PongMessage message) {      ByteBuffer buffer = message.getApplicationData() ;      logger.debug("接受到Pong幀【這是由瀏覽器發(fā)送】:" + 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("接受到消息類型為【系統(tǒng)消息】") ;         return ;      }    }        @OnError    public void onError(Session session, Throwable error) {      logger.error(error.getMessage()) ;    }}

WsMessageEncoder.java類
該類的主要作用是,當(dāng)發(fā)送的消息是對(duì)象時(shí),該如何轉(zhuǎn)換6eo28資訊網(wǎng)——每日最新資訊28at.com

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處理錯(cuò)誤:{}", e) ;    }    return message;  }}

WsMessageDecoder.java類
該類的作用是,當(dāng)接收到消息時(shí)如何轉(zhuǎn)換成對(duì)象。6eo28資訊網(wǎng)——每日最新資訊28at.com

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處理錯(cuò)誤:{}", e) ;    }    return message ;  }  // 該方法判斷消息是否可以被解碼(轉(zhuǎn)換)  @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類
該類的作用是配置服務(wù)端點(diǎn),比如配置握手信息6eo28資訊網(wǎng)——每日最新資訊28at.com

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("握手請(qǐng)求頭信息:" + request.getHeaders());    logger.debug("握手響應(yīng)頭信息:" + response.getHeaders());    super.modifyHandshake(sec, request, response);  }  }

WebSocke配置類

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

當(dāng)以jar包形式運(yùn)行時(shí)需要配置該bean,暴露我們配置的@ServerEndpoint;當(dāng)我們以war獨(dú)立tomcat運(yùn)行時(shí)不能配置該bean。6eo28資訊網(wǎng)——每日最新資訊28at.com

前端頁(yè)面

<!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("未知服務(wù)地址") ;    }    gm = new window.__GM({      url: url,      protocols: protocols    }) ;    gm.open(options) ;  }  ListenerMsg.init = (user) => {    if (!user) {      alert("未知的當(dāng)前登錄人") ;      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 + "】對(duì)你說(shuō):" + 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>  <id="enter">    <input id="nick"/><button type="button" onclick="enter()">進(jìn)入</button>  </div>  <hr/>  <id="chat" style="display:none;">    當(dāng)前用戶:<b id="cu"></b><br/>    用戶:<input id="toname" name="toname"/><br/><br/>    內(nèi)容:<textarea id="content" rows="3" cols="22"></textarea><br/>    <button type="button" onclick="send()">發(fā)送</button>  </div>  <div>    <ul id="msg">    </ul>  </div> </body></html>

這里有個(gè)g-messages.js文件是我寫的一個(gè)工具類,用來(lái)做連接及心跳檢查用的。6eo28資訊網(wǎng)——每日最新資訊28at.com

到此所有的代碼完畢,接下來(lái)測(cè)試6eo28資訊網(wǎng)——每日最新資訊28at.com

測(cè)試

打開(kāi)兩個(gè)標(biāo)簽頁(yè),以不同的用戶進(jìn)入。6eo28資訊網(wǎng)——每日最新資訊28at.com

圖片6eo28資訊網(wǎng)——每日最新資訊28at.com


6eo28資訊網(wǎng)——每日最新資訊28at.com

圖片6eo28資訊網(wǎng)——每日最新資訊28at.com


6eo28資訊網(wǎng)——每日最新資訊28at.com

輸入對(duì)方用戶名發(fā)送消息6eo28資訊網(wǎng)——每日最新資訊28at.com

圖片6eo28資訊網(wǎng)——每日最新資訊28at.com


6eo28資訊網(wǎng)——每日最新資訊28at.com

圖片6eo28資訊網(wǎng)——每日最新資訊28at.com


6eo28資訊網(wǎng)——每日最新資訊28at.com

成功了,簡(jiǎn)單的websocket。我們生產(chǎn)環(huán)境還就這么完的,8g內(nèi)存跑了6w的用戶。6eo28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://m.rrqrq.com/showinfo-26-5718-0.htmlSpringBoot使用WebSocket實(shí)現(xiàn)即時(shí)消息

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: 停止過(guò)度設(shè)計(jì)中等規(guī)模的前端應(yīng)用程序

下一篇: 提升Go的HTTP路由器的提案

標(biāo)簽:
  • 熱門焦點(diǎn)
Top 国产精品嫩草99av在线_一区在线视频观看_欧美高清一区_欧美 日韩 国产 一区_99精品欧美一区二区三区_久久大香伊蕉在人线观看热2_一色屋精品视频在线观看网站_在线亚洲国产精品网站_亚洲区一区二区三区_你懂的视频一区二区
蜜桃av久久久亚洲精品| 91精品婷婷国产综合久久| 欧美一区国产一区| 国产精品一区二区免费不卡| 美女尤物国产一区| 秋霞电影网一区二区| 婷婷夜色潮精品综合在线| 亚洲综合在线免费观看| 亚洲欧美日韩精品久久久久| 国产精品免费久久久久| 国产精品女主播av| 自拍偷拍国产精品| 亚洲日韩欧美一区二区在线| 亚洲精品视频免费观看| 一区二区三区**美女毛片| 一区二区三区不卡视频在线观看| 亚洲精品国产a| 午夜视频一区在线观看| 天堂久久一区二区三区| 久久激情综合网| 国产成人免费视频网站 | 国产精品一区2区| 处破女av一区二区| 欧美在线日韩精品| 亚洲黄色一区| 一本一本大道香蕉久在线精品| 色悠悠亚洲一区二区| 欧美偷拍一区二区| 日韩欧美一卡二卡| 国产精品女人毛片| 亚洲国产你懂的| 国产一区二区三区在线观看精品 | 国产在线不卡一区| 99re热视频这里只精品| 在线亚洲伦理| 在线成人高清不卡| 国产精品伦理在线| 免费精品视频在线| 99久久婷婷国产精品综合| 亚洲第一伊人| 欧美性视频一区二区三区| 精品国产乱码久久久久久老虎| 国产精品久久久久影院老司| 婷婷久久综合九色国产成人| 国产精品亚洲成人| 亚洲免费不卡| 欧美一区二区二区| 中文字幕日韩精品一区| 蜜臀va亚洲va欧美va天堂| 99在线精品观看| 亚洲综合视频一区| 精品999在线播放| 亚洲成a人片在线不卡一二三区| 国产永久精品大片wwwapp| 精品不卡视频| 欧美精品一二三| 一区二区三区日韩精品视频| 国产精品影视在线观看| 国产日韩欧美| 久久一二三国产| 卡一卡二国产精品| 亚洲国内欧美| 日韩精品专区在线影院重磅| 亚洲国产精品久久久久秋霞影院| 粉嫩嫩av羞羞动漫久久久 | 精品国产乱码久久久久久影片| 樱花影视一区二区| aaa国产一区| 在线免费不卡电影| 伊人色综合久久天天人手人婷| 国产激情精品久久久第一区二区| 在线亚洲自拍| 国产欧美日韩另类视频免费观看| 黑人巨大精品欧美黑白配亚洲| 在线亚洲自拍| 国产精品久久久久久久久久久免费看 | 国产精品久久毛片a| 看电影不卡的网站| 欧美专区18| 中文在线资源观看网站视频免费不卡 | 国产精品无人区| 国产成人免费高清| 欧美在线一区二区三区| 亚洲最大成人综合| 精品91视频| 久久久久国产精品免费免费搜索| 精品一区二区国语对白| 亚洲免费综合| 夜夜精品视频一区二区| 91麻豆免费看片| 精品国产一区二区三区四区四 | 亚洲欧美日韩另类精品一区二区三区 | 久久国产精品一区二区三区四区| 亚洲欧洲精品一区二区三区 | 制服丝袜亚洲色图| 日本最新不卡在线| 久久精品综合一区| 一区二区三区加勒比av| 影音先锋久久久| 国产精品乱码人人做人人爱| 99久久久免费精品国产一区二区 | 国产精选一区二区三区| 欧美日韩精品三区| 激情av综合网| 欧美日韩不卡一区| 国产美女在线精品| 91精品国产综合久久精品app | 成人少妇影院yyyy| 精品久久久久久亚洲综合网| 国产成人在线视频网址| 欧美色图一区二区三区| 激情欧美一区二区| 欧美一区二区三区在线看| 国产suv精品一区二区883| 欧美一卡在线观看| 99久久精品国产毛片| 欧美一区二区三区成人| 丁香另类激情小说| 久久午夜免费电影| 欧美日韩p片| 亚洲美女在线国产| 免费亚洲一区二区| 美女视频网站黄色亚洲| 777亚洲妇女| 99久久er热在这里只有精品15| 久久精品人人做人人综合| 欧美日韩成人一区二区三区| 亚洲免费观看高清在线观看| 久久久噜噜噜| 国产精品一区二区视频| 久久午夜羞羞影院免费观看| 黑人一区二区| 午夜精品久久久久久久| 欧美精选在线播放| 99久久久国产精品免费蜜臀| 亚洲人被黑人高潮完整版| 久久伊人一区二区| 国产乱子轮精品视频| 欧美极品美女视频| 色偷偷88欧美精品久久久| 国产成人在线影院| ●精品国产综合乱码久久久久| 久久久久一区| av电影一区二区| 亚洲国产精品久久久久秋霞影院| 欧美精品乱码久久久久久| 欧美国产日本| 日本在线不卡视频| 国产日韩欧美电影| 欧美亚洲国产一卡| 欧美午夜一区| 亚洲黑丝在线| 国产一区二区三区在线观看免费 | 精品久久五月天| 国产精品免费一区二区三区在线观看 | 国产黄人亚洲片| 伊人一区二区三区| 91麻豆精品国产自产在线观看一区| 久久国产精品亚洲va麻豆| 成人免费视频caoporn| 亚洲国产精品一区二区尤物区| 日韩午夜电影av| 国产精品一区二区三区四区五区 | 一区二区三区欧美久久| 日韩欧美一二区| 色香色香欲天天天影视综合网 | 精品少妇一区二区| 久久精品中文| 18成人免费观看视频| 国产成人av一区二区| 午夜精品123| 国产精品二三区| 欧美r级电影在线观看| 麻豆亚洲精品| 99精品视频网| 欧美日韩成人| 成人app在线观看| 激情图区综合网| 午夜精品久久久久久不卡8050| 日本一区二区三区视频视频| 在线成人免费观看| 在线一区二区三区四区五区 | 日韩欧美一区二区三区在线| 色妹子一区二区| 国产精品美女诱惑| 狠狠综合久久| 欧美69wwwcom| 91在线你懂得| 成人av影视在线观看| 国产久卡久卡久卡久卡视频精品| 视频一区二区中文字幕| 又紧又大又爽精品一区二区| 欧美经典一区二区三区| 日韩欧美另类在线| 67194成人在线观看| 欧洲一区二区三区在线| 久久精品国产第一区二区三区最新章节 | 国产精品免费视频观看| 国产欧美一区二区精品久导航| 欧美精品一区二区蜜臀亚洲|