<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          SpringBoot整合 websocket 實(shí)現(xiàn)群聊,點(diǎn)對(duì)點(diǎn)聊天

          共 6954字,需瀏覽 14分鐘

           ·

          2022-03-03 01:33

          程序員的成長之路
          互聯(lián)網(wǎng)/程序員/技術(shù)/資料共享?
          關(guān)注


          閱讀本文大概需要 7?分鐘。

          來自:blog.csdn.net/qq_38455201/article/details/80374712

          1.websocket

          websocket最偉大之處在于服務(wù)器和客戶端可以在給定的時(shí)間范圍內(nèi)的任意時(shí)刻,相互推送信息。瀏覽器和服務(wù)器只需要要做一個(gè)握手的動(dòng)作,在建立連接之后,服務(wù)器可以主動(dòng)傳送數(shù)據(jù)給客戶端,客戶端也可以隨時(shí)向服務(wù)器發(fā)送數(shù)據(jù)。
          第一、WebSocket是HTML5中的協(xié)議,支持持久連接;而Http協(xié)議不支持持久連接。
          第二、首先,Websocket是一個(gè)持久化的協(xié)議,相對(duì)于HTTP這種非持久的協(xié)議來說
          HTTP的生命周期通過 Request 來界定,也就是一個(gè) Request 一個(gè) Response ,那么在 HTTP1.0 中,這次HTTP請(qǐng)求就結(jié)束了。
          在HTTP1.1中進(jìn)行了改進(jìn),使得有一個(gè)keep-alive,也就是說,在一個(gè)HTTP連接中,可以發(fā)送多個(gè)Request,接收多個(gè)Response。但是請(qǐng)記住 Request = Response , 在HTTP中永遠(yuǎn)是這樣,也就是說一個(gè)request只能有一個(gè)response。而且這個(gè)response也是被動(dòng)的,不能主動(dòng)發(fā)起。
          第三、傳統(tǒng)的http請(qǐng)求,其并發(fā)能力都是依賴同時(shí)發(fā)起多個(gè)TCP連接訪問服務(wù)器實(shí)現(xiàn)的(因此并發(fā)數(shù)受限于瀏覽器允許的并發(fā)連接數(shù)),而websocket則允許我們?cè)谝粭lws連接上同時(shí)并發(fā)多個(gè)請(qǐng)求,即在A請(qǐng)求發(fā)出后A響應(yīng)還未到達(dá),就可以繼續(xù)發(fā)出B請(qǐng)求。由于TCP的慢啟動(dòng)特性(新連接速度上來是需要時(shí)間的),以及連接本身的握手損耗,都使得websocket協(xié)議的這一特性有很大的效率提升。
          第四、http協(xié)議的頭部太大,且每個(gè)請(qǐng)求攜帶的幾百上千字節(jié)的頭部大部分是重復(fù)的,很多時(shí)候可能響應(yīng)都遠(yuǎn)沒有請(qǐng)求中的header空間大。如此多無效的內(nèi)容傳遞是因?yàn)闊o法利用上一條請(qǐng)求內(nèi)容,websocket則因?yàn)閺?fù)用長連接而沒有這一問題。
          第五、當(dāng)需要實(shí)現(xiàn)客戶端刷新消息時(shí),傳統(tǒng)方案往往通過定時(shí)ajax請(qǐng)求實(shí)現(xiàn),實(shí)際上對(duì)多數(shù)用戶多數(shù)時(shí)間下這些請(qǐng)求都是無意義了,并且非常占用資源,websocket資源占用就小很多。

          2.在springboot程序當(dāng)中使用websocket,接下來這套程序能夠?qū)崿F(xiàn)的功能有:

          websocket連接:
          上線通知:
          下線通知:
          在線人數(shù)統(tǒng)計(jì):
          對(duì)所有人聊天:
          一對(duì)一聊天:
          第一步:導(dǎo)入websocket的依賴

          <dependency>
          ????<groupId>org.springframework.bootgroupId>
          ????<artifactId>spring-boot-starter-websocketartifactId>
          dependency>
          第二步:websocket的配置我
          /**
          ?*?websocket的配置
          ?*/

          @Configuration
          public?class?WebSocketStompConfig{
          ????@Bean
          ????public?ServerEndpointExporter?serverEndpointExporter()
          ????
          {
          ????????return?new?ServerEndpointExporter();
          ????}
          }
          第三步:建立ServerEndpoint的java類,能夠接受客戶端發(fā)送過來的信息和發(fā)送給客戶端信息。
          @Component
          @ServerEndpoint("/websocket/{username}")
          public?class?WebSocket?{
          ????private?Logger?logger?=?LoggerFactory.getLogger(this.getClass());
          ????/**
          ?????*?在線人數(shù)
          ?????*/

          ????public?static?int?onlineNumber?=?0;
          ????/**
          ?????*?以用戶的姓名為key,WebSocket為對(duì)象保存起來
          ?????*/

          ????private?static?Map?clients?=?new?ConcurrentHashMap();
          ????/**
          ?????*?會(huì)話
          ?????*/

          ????private?Session?session;
          ????/**
          ?????*?用戶名稱
          ?????*/

          ????private?String?username;
          ????/**
          ?????*?建立連接
          ?????*
          ?????*?@param?session
          ?????*/

          ????@OnOpen
          ????public?void?onOpen(@PathParam("username")?String?username,?Session?session)
          ????
          {
          ????????onlineNumber++;
          ????????logger.info("現(xiàn)在來連接的客戶id:"+session.getId()+"用戶名:"+username);
          ????????this.username?=?username;
          ????????this.session?=?session;
          ????????logger.info("有新連接加入!?當(dāng)前在線人數(shù)"?+?onlineNumber);
          ????????try?{
          ????????????//messageType?1代表上線?2代表下線?3代表在線名單?4代表普通消息
          ????????????//先給所有人發(fā)送通知,說我上線了
          ????????????Map?map1?=?Maps.newHashMap();
          ????????????map1.put("messageType",1);
          ????????????map1.put("username",username);
          ????????????sendMessageAll(JSON.toJSONString(map1),username);
          ?
          ????????????//把自己的信息加入到map當(dāng)中去
          ????????????clients.put(username,?this);
          ????????????//給自己發(fā)一條消息:告訴自己現(xiàn)在都有誰在線
          ????????????Map?map2?=?Maps.newHashMap();
          ????????????map2.put("messageType",3);
          ????????????//移除掉自己
          ????????????Set?set?=?clients.keySet();
          ????????????map2.put("onlineUsers",set);
          ????????????sendMessageTo(JSON.toJSONString(map2),username);
          ????????}
          ????????catch?(IOException?e){
          ????????????logger.info(username+"上線的時(shí)候通知所有人發(fā)生了錯(cuò)誤");
          ????????}
          ?
          ?
          ?
          ????}
          ?
          ????@OnError
          ????public?void?onError(Session?session,?Throwable?error)?{
          ????????logger.info("服務(wù)端發(fā)生了錯(cuò)誤"+error.getMessage());
          ????????//error.printStackTrace();
          ????}
          ????/**
          ?????*?連接關(guān)閉
          ?????*/

          ????@OnClose
          ????public?void?onClose()
          ????
          {
          ????????onlineNumber--;
          ????????//webSockets.remove(this);
          ????????clients.remove(username);
          ????????try?{
          ????????????//messageType?1代表上線?2代表下線?3代表在線名單??4代表普通消息
          ????????????Map?map1?=?Maps.newHashMap();
          ????????????map1.put("messageType",2);
          ????????????map1.put("onlineUsers",clients.keySet());
          ????????????map1.put("username",username);
          ????????????sendMessageAll(JSON.toJSONString(map1),username);
          ????????}
          ????????catch?(IOException?e){
          ????????????logger.info(username+"下線的時(shí)候通知所有人發(fā)生了錯(cuò)誤");
          ????????}
          ????????logger.info("有連接關(guān)閉!?當(dāng)前在線人數(shù)"?+?onlineNumber);
          ????}
          ?
          ????/**
          ?????*?收到客戶端的消息
          ?????*
          ?????*?@param?message?消息
          ?????*?@param?session?會(huì)話
          ?????*/

          ????@OnMessage
          ????public?void?onMessage(String?message,?Session?session)
          ????
          {
          ????????try?{
          ????????????logger.info("來自客戶端消息:"?+?message+"客戶端的id是:"+session.getId());
          ????????????JSONObject?jsonObject?=?JSON.parseObject(message);
          ????????????String?textMessage?=?jsonObject.getString("message");
          ????????????String?fromusername?=?jsonObject.getString("username");
          ????????????String?tousername?=?jsonObject.getString("to");
          ????????????//如果不是發(fā)給所有,那么就發(fā)給某一個(gè)人
          ????????????//messageType?1代表上線?2代表下線?3代表在線名單??4代表普通消息
          ????????????Map?map1?=?Maps.newHashMap();
          ????????????map1.put("messageType",4);
          ????????????map1.put("textMessage",textMessage);
          ????????????map1.put("fromusername",fromusername);
          ????????????if(tousername.equals("All")){
          ????????????????map1.put("tousername","所有人");
          ????????????????sendMessageAll(JSON.toJSONString(map1),fromusername);
          ????????????}
          ????????????else{
          ????????????????map1.put("tousername",tousername);
          ????????????????sendMessageTo(JSON.toJSONString(map1),tousername);
          ????????????}
          ????????}
          ????????catch?(Exception?e){
          ????????????logger.info("發(fā)生了錯(cuò)誤了");
          ????????}
          ?
          ????}
          ?
          ?
          ????public?void?sendMessageTo(String?message,?String?ToUserName)?throws?IOException?{
          ????????for?(WebSocket?item?:?clients.values())?{
          ????????????if?(item.username.equals(ToUserName)?)?{
          ????????????????item.session.getAsyncRemote().sendText(message);
          ????????????????break;
          ????????????}
          ????????}
          ????}
          ?
          ????public?void?sendMessageAll(String?message,String?FromUserName)?throws?IOException?{
          ????????for?(WebSocket?item?:?clients.values())?{
          ????????????????item.session.getAsyncRemote().sendText(message);
          ????????}
          ????}
          ?
          ????public?static?synchronized?int?getOnlineCount()?{
          ????????return?onlineNumber;
          ????}
          ?
          }
          第四步:編寫簡(jiǎn)易的前端頁面
          html>
          <html>
          <head>
          ????<title>websockettitle>
          ????<script?type="text/javascript"?src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.min.js">script>
          ????<script?src="http://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js">script>
          ????<script?src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js">script>
          head>
          ?
          <body>
          ????<div?style="margin:?auto;text-align:?center">
          ????????<h1>Welcome?to?websocketh1>
          ????div>
          ????<br/>
          ????<div?style="margin:?auto;text-align:?center">
          ????????<select?id="onLineUser">
          ????????????<option>--所有--option>
          ????????select>
          ????????<input?id="text"?type="text"?/>
          ????????<button?οnclick="send()">發(fā)送消息button>
          ????div>
          ????<br>
          ????<div?style="margin-right:?10px;text-align:?right">
          ????????<button?οnclick="closeWebSocket()">關(guān)閉連接button>
          ????div>
          ????<hr/>
          ????<div?id="message"?style="text-align:?center;">div>
          ????<input??type="text"?th:value="${username}"?id="username"?style="display:?none"?/>
          body>
          ?
          ?
          <script?type="text/javascript">
          ????var?webSocket;
          ????var?commWebSocket;
          ????if?("WebSocket"?in?window)
          ????{
          ????????webSocket?=?new?WebSocket("ws://localhost:9030/websocket/"+document.getElementById('username').value);
          ?
          ????????//連通之后的回調(diào)事件
          ????????webSocket.onopen?=?function()
          ????????
          {
          ????????????//webSocket.send(?document.getElementById('username').value+"已經(jīng)上線了");
          ????????????console.log("已經(jīng)連通了websocket");
          ????????????setMessageInnerHTML("已經(jīng)連通了websocket");
          ????????};
          ?
          ????????//接收后臺(tái)服務(wù)端的消息
          ????????webSocket.onmessage?=?function?(evt)
          ????????
          {
          ????????????var?received_msg?=?evt.data;
          ????????????console.log("數(shù)據(jù)已接收:"?+received_msg);
          ????????????var?obj?=?JSON.parse(received_msg);
          ????????????console.log("可以解析成json:"+obj.messageType);
          ????????????//1代表上線?2代表下線?3代表在線名單?4代表普通消息
          ????????????if(obj.messageType==1){
          ????????????????//把名稱放入到selection當(dāng)中供選擇
          ????????????????var?onlineName?=?obj.username;
          ????????????????var?option?=?"+onlineName+"";
          ????????????????$("#onLineUser").append(option);
          ????????????????setMessageInnerHTML(onlineName+"上線了");
          ????????????}
          ????????????else?if(obj.messageType==2){
          ????????????????$("#onLineUser").empty();
          ????????????????var?onlineName?=?obj.onlineUsers;
          ????????????????var?offlineName?=?obj.username;
          ????????????????var?option?=?"+"--所有--"+"";
          ????????????????for(var?i=0;i????????????????????if(!(onlineName[i]==document.getElementById('username').value)){
          ????????????????????????option+="+onlineName[i]+""
          ????????????????????}
          ????????????????}
          ????????????????$("#onLineUser").append(option);
          ?
          ????????????????setMessageInnerHTML(offlineName+"下線了");
          ????????????}
          ????????????else?if(obj.messageType==3){
          ????????????????var?onlineName?=?obj.onlineUsers;
          ????????????????var?option?=?null;
          ????????????????for(var?i=0;i????????????????????if(!(onlineName[i]==document.getElementById('username').value)){
          ????????????????????????option+="+onlineName[i]+""
          ????????????????????}
          ????????????????}
          ????????????????$("#onLineUser").append(option);
          ????????????????console.log("獲取了在線的名單"+onlineName.toString());
          ????????????}
          ????????????else{
          ????????????????setMessageInnerHTML(obj.fromusername+"對(duì)"+obj.tousername+"說:"+obj.textMessage);
          ????????????}
          ????????};
          ?
          ????????//連接關(guān)閉的回調(diào)事件
          ????????webSocket.onclose?=?function()
          ????????
          {
          ????????????console.log("連接已關(guān)閉...");
          ????????????setMessageInnerHTML("連接已經(jīng)關(guān)閉....");
          ????????};
          ????}
          ????else{
          ????????//?瀏覽器不支持?WebSocket
          ????????alert("您的瀏覽器不支持?WebSocket!");
          ????}
          ????//將消息顯示在網(wǎng)頁上
          ????function?setMessageInnerHTML(innerHTML)?{
          ????????document.getElementById('message').innerHTML?+=?innerHTML?+?'
          '
          ;
          ????}
          ?
          ????function?closeWebSocket()?{
          ????????//直接關(guān)閉websocket的連接
          ????????webSocket.close();
          ????}
          ?
          ????function?send()?{
          ????????var?selectText?=?$("#onLineUser").find("option:selected").text();
          ????????if(selectText=="--所有--"){
          ????????????selectText?=?"All";
          ????????}
          ????????else{
          ????????????setMessageInnerHTML(document.getElementById('username').value+"對(duì)"+selectText+"說:"+?$("#text").val());
          ????????}
          ????????var?message?=?{
          ????????????"message":document.getElementById('text').value,
          ????????????"username":document.getElementById('username').value,
          ????????????"to":selectText
          ????????};
          ????????webSocket.send(JSON.stringify(message));
          ????????$("#text").val("");
          ?
          ????}
          script>
          ?
          html>
          第五步:跳轉(zhuǎn)到websocket頁面上去
          ????@RequestMapping("/websocket/{name}")
          ????public?String?webSocket(@PathVariable?String?name,Model?model){
          ????????try{
          ????????????logger.info("跳轉(zhuǎn)到websocket的頁面上");
          ????????????model.addAttribute("username",name);
          ????????????return?"websocket";
          ????????}
          ????????catch?(Exception?e){
          ????????????logger.info("跳轉(zhuǎn)到websocket的頁面上發(fā)生異常,異常信息是:"+e.getMessage());
          ????????????return?"error";
          ????????}
          ????}
          以上能夠?qū)崿F(xiàn)的功能有上線通知,下線通知,一對(duì)一聊天,對(duì)所有人聊等功能。
          推薦閱讀:

          月薪一萬在北京生活是什么體驗(yàn)?

          自定義注解+攔截器優(yōu)雅的實(shí)現(xiàn)敏感數(shù)據(jù)的加解密!

          互聯(lián)網(wǎng)初中高級(jí)大廠面試題(9個(gè)G)

          內(nèi)容包含Java基礎(chǔ)、JavaWeb、MySQL性能優(yōu)化、JVM、鎖、百萬并發(fā)、消息隊(duì)列、高性能緩存、反射、Spring全家桶原理、微服務(wù)、Zookeeper、數(shù)據(jù)結(jié)構(gòu)、限流熔斷降級(jí)......等技術(shù)棧!

          ?戳閱讀原文領(lǐng)??!? ? ? ? ? ? ? ??? ??? ? ? ? ? ? ? ? ? ?朕已閱?

          瀏覽 50
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  人妻体内射精一区二区三区 | av影音先锋亚洲第一 | 欧美夜夜爽 | 无码成人精品久久影院三级 | 少妇骚逼 |