聊天广场(Vue+WebSocket+SpringBoot)

由于心血来潮想要做个聊天室项目 ,但是仔细找了一下相关教程,却发现这么多的WebSocket教程里面,很多都没有介绍详细,代码都有所残缺,所以这次带来一个比较完整得使用WebSocket的项目。

目录

一、效果展示

二、准备工作

一、前端框架,Vue + elementUI组件 +JsCookie

二、后端 SpringBoot + websocket包

三、前端代码

四、后端代码


一、效果展示

1.用户交流


二、准备工作

一、前端框架,Vue + elementUI组件 +JsCookie

新建一个vue项目

引入以下组件与依赖

npm i element-ui -S
npm install js-cookie

二、后端 SpringBoot + websocket包

创建SpringBoot项目后

在pom.xml文件中引入以下依赖:

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

注意项目前端为8081端口,后端为8080端口,所以先运行后端再运行前端


三、前端代码

在App.vue中即可引入以下代码:

html:

<template>

  <div id="Layout">
    <el-container>
      <el-aside width="200px">Aside</el-aside>
      <el-container>
        <el-header style="background-color: rgb(245, 245, 245); border-bottom: 1px solid grey;">
          <h3>聊天广场</h3>
        </el-header>

        <el-main style="background-color: rgb(244, 245, 247);
        min-height: 700px; max-height: 700px; ">

          <div id="chatContent" style="padding-left: 10px; line-height: normal; ">
            <!-- 循环输出对话内容 -->
            <el-scrollbar v-for="(message, index) in messages" :key="index">
              <div ref="scrollbar" v-if="message.sender !== senderName" class="chat-message" id="ChatContentCard" style=" background-color: white;
              margin-top: 20px; 
              box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)  
              ">
                <el-avatar :size="40"
                  src="https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png"></el-avatar>
                <div class="message-content" style="width: 100%;">
                  <div style="text-align: left; text-indent: 1em;"> {{ message.sender }}</div>
                  <div id="chatContentText">{{ message.text }}</div>
                </div>
              </div>

              <div ref="scrollbar" v-if="message.sender === senderName" id="myChatContentCard">
                <el-avatar :size="40"
                  src="https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg"></el-avatar>
                <div class="message-content" style="width: 100%;">
                  <div style="text-align: left; text-indent: 1em;"> {{ message.sender }}</div>
                  <div id="chatContentText">{{ message.text }}</div>
                </div>
              </div>
            </el-scrollbar>
          </div>
        </el-main>


        <!-- 底层交互框 -->
        <el-footer style="height: 190px; background-color: rgb(244, 245, 247); ">

          <div id="Gadget" style="background-color: rgb(244, 245, 247); height: 35px; margin-bottom: 10px;">

            <el-upload class="upload-demo" ref="upload" action="https://jsonplaceholder.typicode.com/posts/"
              :on-preview="handlePreview" :on-remove="handleRemove" :file-list="fileList" :auto-upload="false" style="float: left;">

              <el-button slot="trigger" size="small" type="primary"><i class="el-icon-picture-outline-round"></i></el-button>

              <el-button style="margin-left: 10px;" size="small" type="success" @click="submitUpload">上传到服务器</el-button>
              
            </el-upload>


          </div>

          <el-form @submit.native.prevent="sendMessage"
            style="background-color: rgb(244, 245, 247); height: 80%; width: 100%; position: relative;">
            <el-input v-model="messageInput" rows="4" resize="none" type="textarea" placeholder="请输入内容......."
              @keyup.enter="sendMessage" style="height: 100%; max-height: 60px; ">
            </el-input>
            <div style="text-align: right; background-color: rgb(244, 245, 247); margin-top: 34px;">
              <el-button type="primary" @click="sendMessage">发送</el-button>
            </div>

          </el-form>
        </el-footer>


      </el-container>
    </el-container>

  </div>
</template>

script:

<script>
import Cookies from 'js-cookie';


export default {
  computed: {
    senderName() {
      return Cookies.get('account') || '游客';
    }
  },
  name: 'App',
  data() {
    return {
      messages: [],
      messageInput: '',
      ws: null,
      fileList: []
    };
  },
  mounted() {
    this.initWebSocket();
  },
  beforeDestroy() {
    this.closeWebSocket();
  },
  methods: {
    initWebSocket() {
      this.ws = new WebSocket('ws://localhost:8080/chat');
      this.ws.onopen = () => {
        console.log('Connected to server.');
      };
      this.ws.onmessage = (event) => {
        try {
          let messageData;
          if (isJson(event.data)) {
            messageData = JSON.parse(event.data);
          } else {
            messageData = { text: event.data };
          }
          this.messages.push({
            sender: messageData.sender || 'Anonymous',
            text: messageData.text,
          });

          // 使用Vue.nextTick确保DOM更新后再执行滚动操作
          this.$nextTick(() => {
            // 确保scrollbar存在且已渲染
            if (this.$refs.scrollbar) {
              // 直接滚动到底部,不需要使用contentSize
              // this.$refs.scrollbar.$el.scrollTop = this.$refs.scrollbar.$el.scrollHeight;
            }
          });
        } catch (error) {
          console.error('Error parsing message:', error);
        }

      };


      // 辅助函数,检查字符串是否可能是JSON格式
      function isJson(str) {
        try {
          JSON.parse(str);
        } catch (e) {
          return false;
        }
        return true;
      }


      this.ws.onerror = (error) => {
        console.error('WebSocket error:', error);
      };
      this.ws.onclose = () => {
        console.log('Disconnected from server.');
      };
    },
    sendMessage() {
      console.log('调用sendMessage');
      const senderName = Cookies.get('account');
      if (senderName === null) {
        this.senderName = "游客";
      }
      if (this.messageInput.trim() !== '') {
        this.ws.send(JSON.stringify({ sender: senderName, text: this.messageInput }));
        this.messageInput = ''; // 清空输入框
      }
    },
    closeWebSocket() {
      if (this.ws && this.ws.readyState === WebSocket.OPEN) {
        this.ws.close();
      }
    },


// 文件上传函数
submitUpload() {
        this.$refs.upload.submit();
      },
      handleRemove(file, fileList) {
        console.log(file, fileList);
      },
      handlePreview(file) {
        console.log(file);
      }


  },
};
</script>

css:

<style scoped>
.chat-message {
  display: flex;
  align-items: center;
  margin-bottom: 10px;
}

.message-content {
  margin-left: 10px;
}

#Layout {
  line-height: normal;
}

/* 添加动画关键帧 */
@keyframes slideInFromLeft {
  0% {
    transform: translateX(-100%);
    opacity: 0;
  }

  100% {
    transform: translateX(0);
    opacity: 1;
  }
}

#ChatContentCard {
  min-height: 80px;
  width: 50%;
  /* 应用动画 */
  animation: slideInFromLeft 0.3s ease-in-out forwards;
  border-radius: 30px
}

#chatContentText {
  width: 99%;
  overflow-wrap: break-word;

}


.el-header,
.el-footer {
  background-color: #B3C0D1;
  color: #333;
  text-align: center;
  line-height: 60px;
}

.el-aside {
  background-color: #D3DCE6;
  color: #333;
  text-align: center;
  line-height: 200px;
}

.el-main {
  background-color: #E9EEF3;
  color: #333;
  text-align: center;
  line-height: 160px;
}

body>.el-container {
  margin-bottom: 40px;
}

.el-container:nth-child(5) .el-aside,
.el-container:nth-child(6) .el-aside {
  line-height: 260px;
}

.el-container:nth-child(7) .el-aside {
  line-height: 320px;
}


#myChatContentCard{
  display: flex;
  align-items: center;
  margin-bottom: 10px;
  margin-left: 50%;

  min-height: 80px;
  width: 50%;
  /* 应用动画 */
  animation: slideInFromRight 0.3s ease-in-out forwards;
  border-radius: 30px;

  background-color: rgb(149, 236, 105);
              margin-top: 20px; 
              box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04) 

}

@keyframes slideInFromRight {
  0% {
    transform: translateX(100%);
    opacity: 0;
  }

  100% {
    transform: translateX(0);
    opacity: 1;
  }
}


</style>

注意: 这个项目中如果script需要进行修改,由于我这里完成了一个登陆系统,所以采用了对Cookie的使用,而如果只是体验的话,只需要把Cookie去掉将其改为游客+随机字符串去替代即可。

前端启动

npm run serve


四、后端代码

WebSocket配置:

1.WebSocketConfig.java

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new ChatWebSocketHandler(), "/chat").setAllowedOrigins("*");
    }
}

 2.ChatWebSocketHandler.java

@Slf4j
public class ChatWebSocketHandler extends TextWebSocketHandler {

    private static final Set<WebSocketSession> sessions = Collections.synchronizedSet(new HashSet<>());

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        sessions.add(session);
        broadcast("欢迎新的小伙伴加入");
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        broadcast(message.getPayload());
    }

    private void broadcast(String message) {
        log.info("服务器广播数据:"+message);
        sessions.forEach(session -> {
            try {
                session.sendMessage(new TextMessage(message));
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        sessions.remove(session);

    }
}

 后端启动:

 


相关推荐

  1. TCP<span style='color:red;'>聊天</span>

    TCP聊天

    2024-07-10 21:38:03      52 阅读
  2. TCP<span style='color:red;'>聊天</span>

    TCP聊天

    2024-07-10 21:38:03      48 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-10 21:38:03       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-10 21:38:03       71 阅读
  3. 在Django里面运行非项目文件

    2024-07-10 21:38:03       58 阅读
  4. Python语言-面向对象

    2024-07-10 21:38:03       69 阅读

热门阅读

  1. postman接口测试工具

    2024-07-10 21:38:03       25 阅读
  2. python使用tkinter添加下载进度UI

    2024-07-10 21:38:03       25 阅读
  3. 计算机网络-HTTP常见面试题

    2024-07-10 21:38:03       22 阅读
  4. c++实战-多子棋

    2024-07-10 21:38:03       28 阅读
  5. 访问者模式在金融业务中的应用及其框架实现

    2024-07-10 21:38:03       20 阅读
  6. PyTorch清理CPU缓存

    2024-07-10 21:38:03       19 阅读
  7. qt 自定义信号和槽举例

    2024-07-10 21:38:03       21 阅读