WebSocket 实现简单聊天功能

利用WebSocket长连接实现即使通讯,可以实现个人单独聊天,内容不需要存服务器,这里只有前端代码,后端负责传递消息和用户列表。

<template>
  <div>
    <div class="content" style="display: flex;">

      <div class="leftChat">
        <div v-for="(item,index) in peopleList" :key="index" @click="userchange(item,index)"
          :class="indexChekck == index ? 'peopelCheck' : 'people'">
          <img :src=" item.avatar ?       baseUrl + item.avatar   : require('@/assets/image/profile.png')" alt=""
            style="width: 50px;height: 50px;"> <span style="width: 60px;font-size: 16px;">{{item.userName}}</span>
          <div class="xaioxi" v-if="item.number >0">{{ item.number >=99 ? '99+' :  item.number+ '+'  }}</div>
        </div>
        <div v-if="peopleList.length ==0">暂无人在线</div>
      </div>

      <div v-if="showPeo" style="position: relative;">
        <div class="top">
          <img :src=" topeople.avatar ?       baseUrl + topeople.avatar   : require('@/assets/image/profile.png')"
            alt="" style="width: 50px;height: 50px;border-radius: 50%;margin-left: 5px;">
          <span style="margin-left: 10px;">{{topeople.userName}}</span>

        </div>
        <!-- 聊天内容 -->
        <div id="message" style="" ref="message">
          <div v-for="(item,idnexs) in   this.allPeople[this.chatIndex].chatList" :key="idnexs"
            style="position: relative;">
            <div class="left" v-if="item.class =='left'">
              <div style="text-align: left;font-size: 14px;">{{item.name }}</div>
              <div style="margin: 10px 0;text-align: left;">
                <!-- <div class="leftText">{{ item.message }}</div>
                <img :src="baseUrl + item.img" alt=""> -->
                <div v-html="item.message" class="leftText"></div>
              </div>

            </div>
            <div class="right" v-if="item.class =='right'">
              <div style="text-align: right;font-size: 14px;">{{item.name }}</div>
              <div style="margin: 10px 0;text-align: right;">
                <!-- <div class="rightText">{{ item.message }}</div> -->
                <div v-html="item.message" class="rightText"></div>
              </div>
            </div>
          </div>
        </div>

        <div id="text" class="editable-container" :contenteditable="true" @keydown="textareaKeydown($event)"></div>
        <!-- <div id="text">

        </div>
        <el-input text="text" id="text" @keydown="textareaKeydown($event)" :v-model="messages"></el-input> -->

        <div @click="sendMessage" class="sendBtn">发送消息</div>
      </div>

    </div>



  </div>
</template>

这是简单界面,实现简单聊天,只能和在线的人聊天,无法和不在线的聊天,

      getIs() {
        let that = this
        //判断当前浏览器是否支持WebSocket
        if ('WebSocket' in window) {
          websocket = new WebSocket("ws://自己的地址" );
          
        } else {
          alert('Not support websocket');
        }
        //接收到消息的回调方法
        websocket.onmessage = function (event) {
          that.showMessage(event.data);
          let data = JSON.stringify(event.data);
          if (data.dataType == 3) {
            alert(data.message);
          }
        }
      },
      showMessage(message) {
        let data = JSON.parse(message);
        let messages = ''
        if (data.dataType == 1) {

          let arr = []
          if (this.allPeople.length != 0) {
            arr = this.peopleList
          }
          this.peopleList = data.userList
          this.peopleList.forEach(item => {
            for (let i = 0; i < arr.length; i++) {
              if (item.userId == arr[i].userId) {
                item.number = arr[i].number ? arr[i].number : 0
              }
            }
          })
          let array = data.userList
          if (this.allPeople.length != 0) {
            this.allPeople.forEach((item) => {
              for (let i = 0; i < array.length; i++) {
                let n = 0
                let m = 0
                if (item.id != array[i].userId) {
                  n++
                } else {
                  m++
                }
                if (n >= array.length) {
                  this.allPeople.push({
                    id: array[i].userId,
                    chatList: [],
                    number: 0,
                    isTrue: true
                  })
                }
                if (m >= 1) {
                  item.isTrue = true
                } else {
                  item.isTrue = false
                }
              }
            })
          } else {
            for (let i = 0; i < array.length; i++) {
              this.allPeople.push({
                id: array[i].userId,
                chatList: [],
                number: 0,
                isTrue: true
              })
            }
          }

          //   console.log('所有列表', this.allPeople);
        } else if (data.dataType == 2) {
          messages = data.message
          this.allPeople.forEach((item, index) => {
            if (item.id == data.fromUserId) {
              this.allPeople[index].chatList.push({
                class: 'left',
                message: data.message,
                name: data.fromUserName,
                // img: '/profile/signature/2021/12/09/64c9f089-b0fb-4a3f-a51b-8240369a09d6.jpeg',
              })
            }
          })
          this.peopleList.forEach(item => {
            if (item.userId == data.fromUserId && data.fromUserId != this.toUserId) {
              item.number++
            }
          })
          this.$forceUpdate()
          //   console.log('人员信息', this.peopleList);
          this.$emit('newchatChange')
          //   console.log('dsadsad', this.allPeople[this.chatIndex]);
          this.$nextTick(() => {
            let ele = document.getElementById("message");
            //判断元素是否出现了滚动条
            if (ele) {
              ele.scrollTop = ele.scrollHeight;
            }
            //设置滚动条到最底部
          })
        } else if (data.dataType == 4) {
          this.$message('对方已掉线,您发送的消息对方已经看不到了')

        }
        // console.log('data', data, this.peopleList);
        // document.getElementById('messages').innerHTML += messages + '<br/>';
      },
      userchange(val, index) {
        this.indexChekck = index
        this.showPeo = true
        this.topeople = val
        this.toUserId = val.userId
        // console.log('点击了', val);
        this.allPeople.forEach((item, index) => {
          if (item.id == this.toUserId) {
            this.chatIndex = index
            this.allPeople[this.chatIndex].number = 0
          }
        })

        this.peopleList.forEach(item => {
          if (item.userId == this.toUserId) {
            item.number = 0
          }
        })
        this.$nextTick(() => {
          let ele = document.getElementById("message");
          //判断元素是否出现了滚动条
          if (ele) {
            ele.scrollTop = ele.scrollHeight;

          }
          //设置滚动条到最底部
        })
        // console.log('dsadsadasdsad', this.allPeople[this.chatIndex]);
      },
      //监听按键操作
      textareaKeydown(event) {
        if (event.ctrlKey && event.keyCode === 13) {
          event.preventDefault() // 阻止浏览器默认换行操作

        } else if (event.keyCode === 13) {
          //enter
          this.sendMessage();
          event.preventDefault() // 阻止浏览器默认换行操作
          return false
        }
      },
      //发送消息
      sendMessage() {
        // if (websocket) {
        //   // websocket.close();
        // } else {
        //   this.getIs()
        // }
        var msgBak = document.getElementById('text').innerHTML;
        if (msgBak != null && msgBak != "") {
          //   console.log('消息列表', this.chatList);
          let data = {
            toUserId: this.toUserId,
            message: msgBak
          }
          var map2json = JSON.stringify(data)
          if (map2json.length < 8000) {
            websocket.send(map2json);
            document.getElementById('text').innerHTML = null;
            this.allPeople[this.chatIndex].chatList.push({
              class: 'right',
              message: msgBak,
              name: localStorage.getItem('nickName')
            })
            //   console.log('发送消息', this.allPeople);

            this.$nextTick(() => {
              let ele = document.getElementById("message");
              //判断元素是否出现了滚动条

              //设置滚动条到最底部
              ele.scrollTop = ele.scrollHeight;
            })

          } else {
            this.$message('文本或者图片太长了,少写一点吧')
            document.getElementById('text').innerHTML = null;

          }
        } else {
          this.$message('请输入内容')
        }
        this.messages = null
      },

js部分实现用户列表查询,发送消息,以及接收消息,有消息会提示,

一下是全部代码

<template>
  <div>
    <!-- <div id="messages"></div> -->
    <div class="content" style="display: flex;">

      <div class="leftChat">
        <div v-for="(item,index) in peopleList" :key="index" @click="userchange(item,index)"
          :class="indexChekck == index ? 'peopelCheck' : 'people'">
          <img :src=" item.avatar ?       baseUrl + item.avatar   : require('@/assets/image/profile.png')" alt=""
            style="width: 50px;height: 50px;"> <span style="width: 60px;font-size: 16px;">{{item.userName}}</span>
          <div class="xaioxi" v-if="item.number >0">{{ item.number >=99 ? '99+' :  item.number+ '+'  }}</div>
        </div>
        <div v-if="peopleList.length ==0">暂无人在线</div>
      </div>

      <div v-if="showPeo" style="position: relative;">
        <div class="top">
          <img :src=" topeople.avatar ?       baseUrl + topeople.avatar   : require('@/assets/image/profile.png')"
            alt="" style="width: 50px;height: 50px;border-radius: 50%;margin-left: 5px;">
          <span style="margin-left: 10px;">{{topeople.userName}}</span>

        </div>
        <!-- 聊天内容 -->
        <div id="message" style="" ref="message">
          <div v-for="(item,idnexs) in   this.allPeople[this.chatIndex].chatList" :key="idnexs"
            style="position: relative;">
            <div class="left" v-if="item.class =='left'">
              <div style="text-align: left;font-size: 14px;">{{item.name }}</div>
              <div style="margin: 10px 0;text-align: left;">
                <!-- <div class="leftText">{{ item.message }}</div>
                <img :src="baseUrl + item.img" alt=""> -->
                <div v-html="item.message" class="leftText"></div>
              </div>

            </div>
            <div class="right" v-if="item.class =='right'">
              <div style="text-align: right;font-size: 14px;">{{item.name }}</div>
              <div style="margin: 10px 0;text-align: right;">
                <!-- <div class="rightText">{{ item.message }}</div> -->
                <div v-html="item.message" class="rightText"></div>
              </div>
            </div>
          </div>
        </div>

        <div id="text" class="editable-container" :contenteditable="true" @keydown="textareaKeydown($event)"></div>
        <!-- <div id="text">

        </div>
        <el-input text="text" id="text" @keydown="textareaKeydown($event)" :v-model="messages"></el-input> -->

        <div @click="sendMessage" class="sendBtn">发送消息</div>
      </div>

    </div>



  </div>
</template>
<!-- <script src="./"></script> -->
<script>
  let websocket = null;

  export default {
    data() {
      return {
        messagesss: null,
        chatIndex: -1,
        allPeople: [], //所有人的消息
        indexChekck: -1,
        chatList: [],
        showPeo: false,
        topeople: {},
        toUserId: null,
        baseUrl: process.env.VUE_APP_BASE_API,
        peopleList: [],
        messages: null,
        id: localStorage.getItem('userId'),
        shakeList: [],
      }
    },
    mounted() {

      let time = null
      time = setInterval(() => {
        if (websocket) {
          websocket.close();
          this.getIs()
        } else {
          this.getIs()
        }
      }, 30000);

      this.getIs()
    },

    methods: {
      getIs() {
        let that = this
        //判断当前浏览器是否支持WebSocket
        if ('WebSocket' in window) {
          websocket = new WebSocket("ws://自己的地址" + this.id);
         
        } else {
          alert('Not support websocket');
        }
        //接收到消息的回调方法
        websocket.onmessage = function (event) {
          that.showMessage(event.data);
          let data = JSON.stringify(event.data);
          if (data.dataType == 3) {
            alert(data.message);
          }
        }
      },
      showMessage(message) {
        let data = JSON.parse(message);
        let messages = ''
        if (data.dataType == 1) {

          let arr = []
          if (this.allPeople.length != 0) {
            arr = this.peopleList
          }
          this.peopleList = data.userList
          this.peopleList.forEach(item => {
            for (let i = 0; i < arr.length; i++) {
              if (item.userId == arr[i].userId) {
                item.number = arr[i].number ? arr[i].number : 0
              }
            }
          })
          let array = data.userList
          if (this.allPeople.length != 0) {
            this.allPeople.forEach((item) => {
              for (let i = 0; i < array.length; i++) {
                let n = 0
                let m = 0
                if (item.id != array[i].userId) {
                  n++
                } else {
                  m++
                }
                if (n >= array.length) {
                  this.allPeople.push({
                    id: array[i].userId,
                    chatList: [],
                    number: 0,
                    isTrue: true
                  })
                }
                if (m >= 1) {
                  item.isTrue = true
                } else {
                  item.isTrue = false
                }
              }
            })
          } else {
            for (let i = 0; i < array.length; i++) {
              this.allPeople.push({
                id: array[i].userId,
                chatList: [],
                number: 0,
                isTrue: true
              })
            }
          }

          //   console.log('所有列表', this.allPeople);
        } else if (data.dataType == 2) {
          messages = data.message
          this.allPeople.forEach((item, index) => {
            if (item.id == data.fromUserId) {
              this.allPeople[index].chatList.push({
                class: 'left',
                message: data.message,
                name: data.fromUserName,
                // img: '/profile/signature/2021/12/09/64c9f089-b0fb-4a3f-a51b-8240369a09d6.jpeg',
              })
            }
          })
          this.peopleList.forEach(item => {
            if (item.userId == data.fromUserId && data.fromUserId != this.toUserId) {
              item.number++
            }
          })
          this.$forceUpdate()
          //   console.log('人员信息', this.peopleList);
          this.$emit('newchatChange')
          //   console.log('dsadsad', this.allPeople[this.chatIndex]);
          this.$nextTick(() => {
            let ele = document.getElementById("message");
            //判断元素是否出现了滚动条
            if (ele) {
              ele.scrollTop = ele.scrollHeight;
            }
            //设置滚动条到最底部
          })
        } else if (data.dataType == 4) {
          this.$message('对方已掉线,您发送的消息对方已经看不到了')

        }
        // console.log('data', data, this.peopleList);
        // document.getElementById('messages').innerHTML += messages + '<br/>';
      },
      userchange(val, index) {
        this.indexChekck = index
        this.showPeo = true
        this.topeople = val
        this.toUserId = val.userId
        // console.log('点击了', val);
        this.allPeople.forEach((item, index) => {
          if (item.id == this.toUserId) {
            this.chatIndex = index
            this.allPeople[this.chatIndex].number = 0
          }
        })

        this.peopleList.forEach(item => {
          if (item.userId == this.toUserId) {
            item.number = 0
          }
        })
        this.$nextTick(() => {
          let ele = document.getElementById("message");
          //判断元素是否出现了滚动条
          if (ele) {
            ele.scrollTop = ele.scrollHeight;

          }
          //设置滚动条到最底部
        })
        // console.log('dsadsadasdsad', this.allPeople[this.chatIndex]);
      },
      //监听按键操作
      textareaKeydown(event) {
        if (event.ctrlKey && event.keyCode === 13) {
          event.preventDefault() // 阻止浏览器默认换行操作

        } else if (event.keyCode === 13) {
          //enter
          this.sendMessage();
          event.preventDefault() // 阻止浏览器默认换行操作
          return false
        }
      },
      //发送消息
      sendMessage() {
        // if (websocket) {
        //   // websocket.close();
        // } else {
        //   this.getIs()
        // }
        var msgBak = document.getElementById('text').innerHTML;
        if (msgBak != null && msgBak != "") {
          //   console.log('消息列表', this.chatList);
          let data = {
            toUserId: this.toUserId,
            message: msgBak
          }
          var map2json = JSON.stringify(data)
          if (map2json.length < 8000) {
            websocket.send(map2json);
            document.getElementById('text').innerHTML = null;
            this.allPeople[this.chatIndex].chatList.push({
              class: 'right',
              message: msgBak,
              name: localStorage.getItem('nickName')
            })
            //   console.log('发送消息', this.allPeople);

            this.$nextTick(() => {
              let ele = document.getElementById("message");
              //判断元素是否出现了滚动条

              //设置滚动条到最底部
              ele.scrollTop = ele.scrollHeight;
            })

          } else {
            this.$message('文本或者图片太长了,少写一点吧')
            document.getElementById('text').innerHTML = null;

          }
        } else {
          this.$message('请输入内容')
        }
        this.messages = null
      },
    }
  }

</script>

<style lang="scss">
  .editable-container {
    img {
      max-width: 190px !important;
      max-height: auto !important;
    }
  }

  .leftText img {
    max-width: 190px !important;
    max-height: auto !important;
  }

  .rightText img {
    max-width: 190px !important;
    max-height: auto !important;
  }

</style>
<style lang="scss" scoped>
  .top {
    display: flex;
    align-items: center;
    border-bottom: rgb(167, 162, 162) 1px solid;
    height: 60px;
    line-height: 60px;
    width: 500px;
    background: #f5f5f5;
  }

  .content {
    position: fixed;
    // position: absolute;
    top: 100px;
    right: 60px;
    z-index: 999;
  }

  #message {
    padding: 10px;
    overflow: hidden;
    overflow: scroll;
    width: 500px;
    background: #f5f5f5;
    height: 400px;

  }

  .sendBtn {
    font-size: 14px;
    color: #07c160;
    border-radius: 5px;
    position: absolute;
    right: 20px;
    bottom: 10px;
    height: 30px;
    line-height: 30px;
    padding: 0 10px 0 10px;
    text-align: center;
    background: white;
  }

  .sendBtn:hover {
    background: #cecbcb;

  }



  #text {
    padding: 10px;
    border-top: 1px rgb(167, 162, 162) solid;
    background: #f5f5f5;
    width: 500px;
    height: 140px;
    overflow: hidden;
    overflow: scroll;

    img {
      width: 70px !important;
      height: 70px !important;
    }
  }

  #text::-webkit-scrollbar {
    display: none
  }

  .leftChat {
    min-width: 100px;
    padding: 10px;
    background: #e6e6e6;
    border-right: 1px rgb(167, 162, 162) solid;
    overflow: hidden;
    overflow: scroll;
    height: 600px;

    .xaioxi {
      position: absolute;
      top: 0px;
      right: 10px;
      width: 25px;
      height: 15px;
      border-radius: 10px;
      background: red;
      color: white;
      font-size: 12px;
      line-height: 15px;
      text-align: center;
    }

    // /deep/ .el-badge__content,
    // .el-badge__content--undefined,
    // .is-fixed {
    //   top: 5px;
    //   right: 35px;
    // }

    .people {
      position: relative;
      border-bottom: 1px solid rgb(167, 162, 162);
      margin-top: 10px;
      padding-bottom: 5px;
      display: flex;
      align-items: center;

      span {
        margin-left: 10px;
      }
    }

    .peopelCheck {
      position: relative;
      border-bottom: 1px solid rgb(167, 162, 162);
      margin-top: 10px;
      padding-bottom: 5px;
      display: flex;
      align-items: center;
      background: #cac8c6;

      span {
        margin-left: 10px;
      }
    }
  }

  // 去除滚动条显示
  #message::-webkit-scrollbar {
    display: none
  }

  // 去除滚动条显示
  .leftChat::-webkit-scrollbar {
    display: none
  }

  .left {
    // width: 100%;
    // float: left;
    margin-top: 20px;
    margin-right: 0px;

  }

  .right {
    // width: 100%;
    margin-top: 20px;
    // float: right;
    margin-right: 0px;
  }

  .rightText {
    margin-right: 0;
    line-height: 1.5;
    padding: 10px 20px;
    border-radius: 15px;
    color: #f7f8f8;
    background-color: #00a5ff;
    width: auto;
    max-width: 80%;
    display: inline-block;
    text-align: start;
    // width: 100%;
    line-height: 25px;

    white-space: normal;
    word-break: break-all;
    word-wrap: break-word;
    // min-width: 200px;
    // min-height: 200px;

    img {
      width: 150px !important;
      height: 150px !important;
    }

  }



  .leftText {

    white-space: normal;
    word-break: break-all;
    word-wrap: break-word;
    margin-left: 0px;
    line-height: 1.5;
    padding: 10px 20px;
    border-radius: 15px;
    color: black;
    background-color: #ffffff;
    width: auto;
    max-width: 80%;
    display: inline-block;
  }

</style>
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
A:要实现基于Spring Boot和WebSocket聊天功能,可以按以下步骤进行。 1. 集成WebSocket依赖。在Spring Boot项目的pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` 2. 创建WebSocket配置类。在Spring Boot项目中,创建一个WebSocket配置类,用于配置WebSocket相关的参数和处理器等。具体代码如下: ```java @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(new ChatWebSocketHandler(), "/chat").setAllowedOrigins("*"); } } ``` 上面的代码创建了一个名为“/chat”的WebSocket处理器,同时允许所有来源的连接。 3. 创建WebSocket处理器。在Spring Boot项目中,创建一个WebSocket处理器,用于处理WebSocket连接和消息等。具体代码如下: ```java public class ChatWebSocketHandler extends TextWebSocketHandler { private List<WebSocketSession> sessions = new ArrayList<>(); @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { sessions.add(session); } @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { for (WebSocketSession s : sessions) { s.sendMessage(message); } } } ``` 上面的代码创建了一个名为ChatWebSocketHandler的WebSocket处理器,它可以接收和发送文本消息。handleTextMessage方法对于接收到的消息进行处理,然后将它发送给所有连接的客户端。 4. 创建聊天页面。在Web应用程序中,创建一个聊天页面,允许用户在页面上输入和发送消息。具体代码如下: ```html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>聊天室</title> <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script> </head> <body> <input id="username" type="text" placeholder="请输入用户名"><br> <textarea id="message" placeholder="请输入消息"></textarea><br> <button id="sendBtn">发送</button> <script> var ws; $("#sendBtn").click(function () { if (!ws) { alert("WebSocket未连接"); return; } var username = $("#username").val(); var message = $("#message").val(); if (!username) { alert("请输入用户名"); return; } if (!message) { alert("请输入消息"); return; } var data = { username: username, message: message }; ws.send(JSON.stringify(data)); $("#message").val(""); }); $(function () { ws = new WebSocket("ws://" + location.host + "/chat"); ws.onopen = function () { console.log("WebSocket已连接"); }; ws.onclose = function () { console.log("WebSocket已关闭"); ws = null; }; ws.onmessage = function (event) { console.log(event.data); }; }); </script> </body> </html> ``` 上面的HTML代码创建了一个简单聊天页面,包含一个用户名输入框、一个消息输入框和一个发送按钮。通过WebSocket连接服务器并发送消息。 5. 测试聊天功能。启动Spring Boot应用程序,然后使用多个浏览器窗口或标签页打开聊天页面,在页面上输入和发送消息,验证聊天功能是否正常工作。 至此,完成了Spring Boot和WebSocket实现聊天功能的整个过程。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值