SpringBoot+Vue搭建一个WebSocket的实时聊天室

简介: SpringBoot+Vue搭建一个WebSocket的实时聊天室

首先搭建一个SpringBoot项目,其中各个文件:

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>love.xiaohh</groupId>
    <artifactId>websocket-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>websocket-demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

love.xiaohh.websocket.WebsocketApplication,其中注册一个bean,使WebSocket的Endpoint生效

package love.xiaohh.websocket;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@EnableWebSocket // 开启websocket的注解,告诉Spring我们要使用WebSocket
@SpringBootApplication
public class WebsocketApplication {
    public static void main(String[] args) {
        SpringApplication.run(WebsocketApplication.class, args);
    }
    /**
     * 注册一个 ServerEndpointExporter,这样可以让注册到容器当中的WebSocket的Endpoint生效
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

love.xiaohh.websocket.controllers.ws.WebSocketController,这是主角,也是websocket的控制器,有点像Controller

package love.xiaohh.websocket.controllers.ws;
import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
/**
 * <p>
 * WebSocket的控制器
 * </p>
 * @author tanghai
 * @version 1.0
 * @date 2021-09-14 星期二 11:02:09
 */
@Component
@ServerEndpoint("/default/websocket")
public class WebSocketController {
    /**
     * 当前在线的总人数
     */
    private static final AtomicLong ONLINE_COUNT = new AtomicLong(0L);
    /**
     * 所有在线的人数的
     */
    private static final Map<String, Session> ALL_ONLINE_INFO = new HashMap<String, Session>();
    /**
     * websocket被打开的方法
     *
     * @param session 会话
     */
    @OnOpen
    public void open(Session session) {
        // 获取sessionId,让后将session存入到Map中
        final String id = session.getId();
        ALL_ONLINE_INFO.put(id, session);
        // 在线人数自加1并发送给所有的客户端
        final long onlineCount = ONLINE_COUNT.incrementAndGet();
        this.sendMessage(0, onlineCount + "");
    }
    /**
     * websocket被退出
     *
     * @param session 会话
     */
    @OnClose
    public void close(Session session) {
        // 将session从缓存当中移除
        final String id = session.getId();
        ALL_ONLINE_INFO.remove(id);
        // 在线人数自减1并发送给所有的客户端
        final long onlineCount = ONLINE_COUNT.decrementAndGet();
        this.sendMessage(0, onlineCount + "");
    }
    /**
     * 当收到客户端发送过来的消息时触发
     *
     * @param message 客户端发送过来的消息
     * @param session 客户端的session会话
     */
    @OnMessage
    public void message(String message, Session session) throws IOException {
        // 将消息发送到所有的客户端
        this.sendMessage(1, message);
    }
    /**
     * 发送消息给所有用户
     *
     * @param type    消息类型;0=更新在线人数,1=发送的消息
     * @param message 消息实体
     */
    private void sendMessage(int type, String message) {
        // 拼接成JSON,让后前端可以解析
        String targetMessage = "{\"type\":" + type + ",\"message\":\"" + message + "\"}";
        // 遍历并发给所有的客户端
        ALL_ONLINE_INFO.values().forEach(session -> {
            try {
                session.getBasicRemote().sendText(targetMessage);
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }
}

后端的代码大功告成,然后我们搭建一个前端的Vue项目,搭建过程可参见Vue项目的搭建教程,搭建好后需要安装一个element-ui:

npm i element-ui -S

修改几个文件:

index.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>websocket-demo-ui</title>
    <style type="text/css">
      body,#app {
        margin: 0;
        border: 0;
        padding: 0;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

src/main.js:

import Vue from 'vue'
import App from './App'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import router from './router'
// 引入并使用elementui
Vue.use(ElementUI)
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

src/App.vue:

<template>
  <router-view/>
</template>
<script>
export default {
  name: 'App'
}
</script>
<style>
</style>

src/router/index.js:

import Vue from 'vue'
import Router from 'vue-router'
import ChatRoom from '@/components/ChatRoom'
Vue.use(Router)
export default new Router({
  routes: [
    {
      // 根路径默认到聊天室
      path: '/',
      name: 'ChatRoom',
      component: ChatRoom
    }
  ]
})

src/components/ChatRoom.vue:

<template>
  <div id="wrapper">
    <el-row style="height: 10%">
      <el-col :span="12"><h1>小海海的聊天室</h1></el-col>
      <el-col :span="12" style="text-align: right;margin: auto 20px auto 0;">当前在线人数: {{ onlineCount }}</el-col>
    </el-row>
    <el-row style="height: 80%">
      <el-col :span="24">
        <chat-item v-for="(message, index) in chatList" :customerMessage="message" :key="index"/>
      </el-col>
    </el-row>
    <el-row>
      <el-col :span="18">
        <el-input v-model="customerMessage" @keydown.enter="sendMessage" placeholder="消息内容..."></el-input>
      </el-col>
      <el-col :span="6">
        <el-button type="primary" @click="sendMessage" plain>发送</el-button>
      </el-col>
    </el-row>
  </div>
</template>
<script>
import ChatItem from './ChatItem'
export default {
  name: 'ChatRoom',
  data() {
    return {
      socketInfo: {
        path: 'ws://127.0.0.1:8080/default/websocket',
        socket: null
      },
      onlineCount: 0,
      chatList: [],
      customerMessage: ''
    }
  },
  mounted() {
    // 初始化 WebSocket
    this.init()
  },
  destroyed() {
    this.socketInfo.socket.close();
  },
  methods: {
    /**
     * 初始化WebSocket
     */
    init() {
      if (typeof (WebSocket) === 'undefined') {
        alert('您的浏览器不支持WebSocket')
      } else {
        const socket = new WebSocket(this.socketInfo.path)
        // 发送消息的事件
        socket.onmessage = this.getMessage
        // socket被打卡的事件
        socket.onopen = this.socketOpen
        this.socketInfo.socket = socket
      }
    },
    socketOpen() {
      this.chatList.push('您已经进入聊天室,可以开始聊天了!')
    },
    /**
     * 发送消息给服务端
     */
    sendMessage() {
      if (this.customerMessage === '') alert('发送消息不能为空')
      this.socketInfo.socket.send(this.customerMessage)
      this.customerMessage = ''
    },
    /**
     * 收到服务器发过来的消息
     * @param message 消息对象
     */
    getMessage(message) {
      // 将接收到的消息转换为json格式
      const messageJson = JSON.parse(message.data)
      if (messageJson.type === 0) {
        this.onlineCount = messageJson.message
      } else if (messageJson.type === 1) {
        this.chatList.push(messageJson.message)
      }
    }
  },
  components: {
    ChatItem
  }
}
</script>
<style scoped>
</style>

src/components/ChatItem.vue:

<template>
<div>
  <p>{{customerMessage}}</p>
  <hr/>
</div>
</template>
<script>
export default {
  name: 'ChatItem',
  props: {
    customerMessage: String
  }
}
</script>
<style scoped>
</style>

然后我们启动这两个程序:

# 打包maven项目
mvn clean package -Dmaven.test.skip
# 在打包好的好的target目录中启动Java程序
java -jar websocket-demo-0.0.1-SNAPSHOT.jar
# 在vue项目的根路径下下载所有依赖:
npm install

然后访问http://127.0.0.1

多开几个:

尝试发送消息发现同步接收:

现在你就可以叫上你们的小伙伴们一起聊天了!如果不行那么欢迎来到代码仓库克隆代码运行哦

相关文章
|
24天前
|
开发框架 前端开发 网络协议
Spring Boot结合Netty和WebSocket,实现后台向前端实时推送信息
【10月更文挑战第18天】 在现代互联网应用中,实时通信变得越来越重要。WebSocket作为一种在单个TCP连接上进行全双工通信的协议,为客户端和服务器之间的实时数据传输提供了一种高效的解决方案。Netty作为一个高性能、事件驱动的NIO框架,它基于Java NIO实现了异步和事件驱动的网络应用程序。Spring Boot是一个基于Spring框架的微服务开发框架,它提供了许多开箱即用的功能和简化配置的机制。本文将详细介绍如何使用Spring Boot集成Netty和WebSocket,实现后台向前端推送信息的功能。
246 1
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
143 1
|
17天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,创建并配置 Spring Boot 项目,实现后端 API;然后,使用 Ant Design Pro Vue 创建前端项目,配置动态路由和菜单。通过具体案例,展示了如何快速搭建高效、易维护的项目框架。
95 62
|
15天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,帮助开发者提高开发效率和应用的可维护性。
33 2
|
18天前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
29天前
|
前端开发 Java C++
RSocket vs WebSocket:Spring Boot 3.3 中的两大实时通信利器
本文介绍了在 Spring Boot 3.3 中使用 RSocket 和 WebSocket 实现实时通信的方法。RSocket 是一种高效的网络通信协议,支持多种通信模式,适用于微服务和流式数据传输。WebSocket 则是一种标准协议,支持全双工通信,适合实时数据更新场景。文章通过一个完整的示例,展示了如何配置项目、实现前后端交互和消息传递,并提供了详细的代码示例。通过这些技术,可以大幅提升系统的响应速度和处理效率。
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用
【10月更文挑战第8天】本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,通过 Spring Initializr 创建并配置 Spring Boot 项目,实现后端 API 和安全配置。接着,使用 Ant Design Pro Vue 脚手架创建前端项目,配置动态路由和菜单,并创建相应的页面组件。最后,通过具体实践心得,分享了版本兼容性、安全性、性能调优等注意事项,帮助读者快速搭建高效且易维护的应用框架。
40 3
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用
【10月更文挑战第7天】本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,通过 Spring Initializr 创建 Spring Boot 项目并配置 Spring Security。接着,实现后端 API 以提供菜单数据。在前端部分,使用 Ant Design Pro Vue 脚手架创建项目,并配置动态路由和菜单。最后,启动前后端服务,实现高效、美观且功能强大的应用框架。
40 2
|
13天前
|
JavaScript NoSQL Java
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
29 0
|
1月前
|
JavaScript 前端开发 数据可视化
【SpringBoot+Vue项目实战开发】2020实时更新。。。。。。
【SpringBoot+Vue项目实战开发】2020实时更新。。。。。。
47 0