SpringBoot和Vue2集成WebSocket,实现聊天室功能

这篇具有很好参考价值的文章主要介绍了SpringBoot和Vue2集成WebSocket,实现聊天室功能。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

SpringBoot和Vue2集成WebSocket,实现聊天室功能

1.加入依赖
2.后端建立socket服务端
3.前端建立客户端

后端

<!-- websocket -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
		<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.76</version>
        </dependency>
// 配置开启WebSocket
@Configuration
public class WebSocketConfig {

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

}
/**
 * @author websocket服务
 */
@ServerEndpoint(value = "/imserver/{userId}")
@Component
public class WebSocketServer {


    private static UserService userService;

    private static RedisTemplate redisTemplate;

    public static void setUserService(ApplicationContext context){
        userService = context.getBean(UserServiceImpl.class);
        redisTemplate = (RedisTemplate) context.getBean("redisTemplate");
    }


    private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);
    /**
     * 记录当前在线连接数
     */
    public static final Map<String, Session> sessionMap = new ConcurrentHashMap<>();
    /**
     * 连接建立成功调用的方法
     */
    // 当前用户
    private UserVo userVo;
    // 连接上服务端触发的方法
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        if (StringUtils.hasText(userId)){
            // 加入新用户
            if (sessionMap.containsKey(userId)){
                sessionMap.remove(userId);
            }
            sessionMap.put(userId, session);
            this.userVo = userService.findById(Long.valueOf(userId));
            // 统计所有在线用户
            List<UserVo> list = new LinkedList<>();
            sessionMap.forEach((userId1,session1) -> {
                UserVo userVo = userService.findById(Long.valueOf(userId1));
                list.add(userVo);
            });
            try {
                // 发送给所有在线的用户,更新在线人数
                sendAllMessage(JSON.toJSONString(list));
            } catch (Exception e) {
                e.printStackTrace();
            }
            log.info("有新用户加入,userId={}, 当前在线人数为:{}", userId, sessionMap.size());
        }

    }
    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session, @PathParam("userId") String userId) {
        sessionMap.remove(userId);
        // 统计所有在线用户
        List<UserVo> list = new LinkedList<>();
        sessionMap.forEach((userId1,session1) -> {
            UserVo userVo = userService.findById(Long.valueOf(userId1));
            list.add(userVo);
        });
        sendAllMessage(JSON.toJSONString(list));
        log.info("有一连接关闭,移除userId={}的用户session, 当前在线人数为:{}", userId, sessionMap.size());
    }
    /**
     * 收到客户端消息后调用的方法
     * 后台收到客户端发送过来的消息
     * onMessage 是一个消息的中转站
     * 接受 浏览器端 socket.send 发送过来的 json数据
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session, @PathParam("userId") String userId) {
        userVo = userService.findById(Long.valueOf(userId));
        log.info("服务端收到用户username={},id={}的消息:{}", userVo.getNickname(),userId, message);
        // 解析消息
        JSONObject jsonObject1 = JSON.parseObject(message);
        String toUserId = jsonObject1.getString("toUserId");
        String text = jsonObject1.getString("text");
        // 判断是给指定人发,还是群发
        if (StringUtils.hasText(toUserId)){
            // {"to": "admin", "text": "聊天文本"}
            Session toSession = sessionMap.get(toUserId); // 根据 to用户名来获取 session,再通过session发送消息文本
            if (toSession != null) {
                // 服务器端 再把消息组装一下,组装后的消息包含发送人和发送的文本内容
                // {"from": "zhang", "text": "hello"}
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("fromUser",userVo);
                jsonObject.put("toUser",userService.findById(Long.valueOf(toUserId)));
                jsonObject.put("text",text);
                this.sendMessage(jsonObject.toJSONString(), toSession);
                log.info("发送给用户userId={},消息:{}", toUserId, jsonObject.toJSONString());
            } else {
                log.info("发送失败,未找到用户username={}的session", toUserId);
            }
        }else{
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("fromUser",userVo);
            jsonObject.put("text",text);
            this.sendAllMessage(jsonObject.toJSONString());
            // 将消息存入redis
            redisTemplate.opsForList().rightPush("messageList",jsonObject.toJSONString());
            redisTemplate.expire("messageList",60*60, TimeUnit.SECONDS); // 过期时间

            log.info("发送给所有用户,消息:{}", toUserId, jsonObject.toJSONString());

        }
    }
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }
    /**
     * 服务端发送消息给客户端
     */
    private void sendMessage(String message, Session toSession) {
        try {
            log.info("服务端给客户端[{}]发送消息{}", toSession.getId(), message);
            toSession.getBasicRemote().sendText(message);
        } catch (Exception e) {
            log.error("服务端发送消息给客户端失败", e);
        }
    }
    /**
     * 服务端发送消息给所有客户端
     */
    private void sendAllMessage(String message) {
        try {
            for (Session session : sessionMap.values()) {
                log.info("服务端给客户端[{}]发送消息{}", session.getId(), message);
                session.getBasicRemote().sendText(message);

            }
        } catch (Exception e) {
            log.error("服务端发送消息给客户端失败", e);
        }
    }
}

// WebSocket服务类无法进行bean的注入,所以要自己调用ApplicationContext获取bean再注入

@SpringBootApplication
public class BlogApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(BlogApplication.class, args);
        WebSocketServer.setUserService(applicationContext);
    }
}

前端

<template>
  <div class="socket">
    <el-row>
      <el-col :span="6" class="online">
          <h3 style="background:linear-gradient(to left,#cae9ff,#c7d8ff);text-align:center;padding:5px;">在线用户</h3>
          <el-scrollbar style="height:280px">
          <div v-for="user in onlineUser" :key="user.id" style="padding:5px" class="onlineUser">
            <el-avatar shape="square" size="medium" :src="user.avatar"></el-avatar>
            <span style="margin-left:8px">{{user.account}}</span>
          </div>
          </el-scrollbar>
      </el-col>
      <el-col :span="17" class="container">
          <h3 style="background:linear-gradient(to left,#cae9ff,#c7d8ff);text-align:center;padding:5px;">当前用户(<span style="color:#66b1ff">{{user.account}}</span>)</h3>
          <el-scrollbar style="height:420px" ref="scroll">
          <div class="content">
            <div class="message" v-for="item,index in messageList" :key="index" style="margin-top:5px;margin-left:5px;position:relative" :style="{justifyContent: item.fromUser.id == user.id ? 'flex-end' : 'flex-start'}">
              <el-avatar shape="square" size="medium" :src="item.fromUser.avatar" :style="{order:user.id == item.fromUser.id ? '1':'0'}"></el-avatar>
              <span style="margin-left:8px;" class="text">{{item.text}}</span>
            </div>
          </div>
          </el-scrollbar>
          <div style="margin-top: 15px;" class="write">
            <el-input placeholder="请输入内容" maxlength="100" clearable v-model="text" class="input-with-select">
              <el-button slot="append" type="primary" @click="sendMessage">发送</el-button>
            </el-input>
          </div>
      </el-col>
    </el-row>
  </div>
</template>

<script>
  import config from '@/utils/config'
  import {getCacheMessage} from '@/api/socket'
  import {mapState} from 'vuex'
  export default {
    name:'lm',
    data(){
      return {
        text:'',
        onlineUser:[],
        messageList:[],
        socket:'',
        baseUrl:config.socketUrl     
      }
    },
    computed:{
      ...mapState(['user'])
    },
    methods:{
      // 连接socket
      onOpen(){
        if (typeof WebSocket == 'undefined'){
          console.log('你的浏览器不支持webSocket')
          return;
        }
        const url = this.baseUrl+this.user.id
        
        this.socket = new WebSocket(url);

        this.socket.onopen = ()=>{
          console.log('websocket打开了,'+this.user.id+'连接成功')
        }
        this.socket.onmessage = (data)=>{
          var message = JSON.parse(data.data)
          if(message.hasOwnProperty("text")){
            this.messageList.push(message)
            this.text = ''
            let scroll = this.$refs['scroll'].$refs['wrap']
            this.$nextTick(() =>{
              scroll.scrollTop = scroll.scrollHeight
            })
          }else{
            // 统计在线人数
            this.onlineUser = message
            
          }
        }
        this.socket.onclose = function(){
          console.log('断开连接成功')
        }
      },
      sendMessage(){
        const message = {
          text:this.text,
          userId:this.user.id
        }
        if(this.text == ''||this.text == null){
          this.$message.warning('请输入内容')
        }else{
          this.socket.send(JSON.stringify(message))
        }
      },
      // 初始化,缓存的消息
      getCacheMessage(){
        getCacheMessage().then(
          res => {
            const data = res.data
            for(var i in data){
              this.messageList.push(JSON.parse(data[i]))
            }
          }
        )
      }
    },
    mounted(){
      this.getCacheMessage()
      this.onOpen()
    },
    beforeDestroy(){
      this.socket.close() // 关闭socket
    }

  }
</script>

<style scoped>
  .socket{
    width: 1200px;
    height: 600px;
    padding:26px;
    background-color: #fff;
    border-radius: 5px;
  }
  .socket .online{
    background-color: #f5f5f5;
    height: 300px;
    border-radius: 5px;
    overflow: hidden;
  }
  .socket .online .onlineUser{
    display: flex;
    justify-content: flex-start;
    align-items: flex-start;  
  }
  .socket .container{
    position: relative;
    margin-left: 26px;
    background-color: #f5f5f5;
    height: 500px;
    border-radius: 5px;
  }
  .socket .el-button--primary{
    background-color: #66b1ff;
    color: #fff;
  }
  .socket .container .content{
    min-height: 400px;
    border: 1px solid #d6d6d6;
    border-radius: 4px;
  }
  .socket .container .content .message{
    display: flex;
    align-content: flex-start;
  }
  .socket .write{
    position:absolute;
    bottom: 10px;
    width: 500px;
    right: 50%;
    transform: translateX(50%);
  }

  .socket .text{
    min-height: 24px;
    line-height: 20px;
    padding: 8px;
    font-size: 16px;
    background-color: #fff;
    border-radius: 5px;
    max-width: 280px;
    overflow-wrap:break-word;
    word-wrap:break-word;
    word-break: bread-all;
    white-space:pre-wrap;
    overflow: hidden;
  }
</style>

springboot集成websocket实现聊天室的功能。如有不足之处,还望大家斧正。文章来源地址https://www.toymoban.com/news/detail-817554.html

到了这里,关于SpringBoot和Vue2集成WebSocket,实现聊天室功能的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于SpringBoot+Vue+WebSocket的在线聊天室

    WebSocket 是一种在 Web 应用程序中实现双向通信的协议。它提供了一种持久连接,允许客户端和服务器之间进行实时数据传输,而无需进行频繁的请求和响应。 相对于传统的 HTTP 请求-响应模式,WebSocket 在客户端和服务器之间建立起一条长久的双向通信通道。这意味着服务器可

    2024年01月16日
    浏览(33)
  • 【WebSocket】SpringBoot整合WebSocket实现聊天室(一)

    目录 一、准备 1、引入依赖 2、创建配置类 二、相关注解 首先我们需要在项目中引入依赖,有两种方式。第一种我们可以在创建Spring Boot项目时搜索WebSocket然后勾选依赖 第二种是我们可以直接在项目的pom.xml文件中插入以下依赖 我们需要进行如下配置 ServerEndpointExporter 是一个

    2024年02月13日
    浏览(21)
  • springboot+websocket实现简单的聊天室

    HTML HTML是创建和构造网页的标准标记语言。它使用一组标记标签描述网页上的内容结构。HTML文档由HTML元素的嵌套结构组成,每个元素由尖括号( )括起的标签表示。这些元素定义了网页的各个部分,如标题、段落、图像、链接、表单等。 JavaScript JavaScript是一种高级、解释性

    2024年01月21日
    浏览(32)
  • SpringBoot与webSocket实现在线聊天室——实现私聊+群聊+聊天记录保存

    引用参考:原文章地址:https://blog.csdn.net/qq_41463655/article/details/92410518 在此基础上实现对聊天记录的保存。 代码地址:链接:https://pan.baidu.com/s/1IJFZDa4S_DF08773sKJWeA 提取码:jkui 思路:新建一个实体类用于保存聊天记录,在消息发送时,设置对象的各个值然后保存到数据库中。

    2024年02月02日
    浏览(24)
  • 基于springboot与websocket实现简易聊天室

    创建一个简单聊天室的HTML和JavaScript代码,匹配相应的css样式,这个聊天室将使用WebSocket技术,允许用户实时发送和接收消息。 1.1 html和js代码 通过new WebSocket(url)建立一个新的websocket连接。websocket连接建立之后使用websocket.onopen,websocket.onclose,websocket.onerror等方法实时监测we

    2024年02月01日
    浏览(28)
  • Java+Vue实现聊天室(WebSocket进阶-聊天记录)

    WebSocket 是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。 WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服

    2024年02月11日
    浏览(20)
  • websocket+elementui+vue实现简易聊天室

    搭建服务端环境 安装socket.io 服务端基于node,js的express框架生成,所以写成模块,引入至app.js中 其中,io.sockets.emit用于向所有建立连接的客户端发送信息,socket.broadcast.emit用于向除发送方之外的客户端发送信息。 客户端基于vue和elementui 进入聊天页面后,先判断用户是否登录,

    2024年04月25日
    浏览(18)
  • 基于 SpringBoot+WebSocket 无DB实现在线聊天室(附源码)

    0.1 样例展示 0.2 源码地址 GitHub:https://github.com/ShiJieCloud/web-chat Gitee:https://gitee.com/suitbaby/web-chat GitCode:I’m Jie / web-chat · GitCode 1.1 HTTP 常用的 HTTP 协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求/响应模型。通信请求只能由客户端发起,服务端对请求做出

    2024年02月05日
    浏览(25)
  • WebSocket+Vue实现简易多人聊天室 以及 对异步调用的理解

    代码仓库:github   HTTP是不支持长连接的,WebSocket是一种通信协议,提供了在单一、长连接上进行全双工通信的方式。它被设计用于在Web浏览器和Web服务器之间实现,但也可以用于任何需要实时通信的应用程序。使用ws作为协议标识符,如果需要加密则使用wss作为协议标识符

    2024年01月17日
    浏览(33)
  • 【你的第一个socket应用】Vue3+Node实现一个WebSocket即时通讯聊天室

    这篇文章主要是用WebSocket技术实现一个 即时通讯聊天室 ,首先先要了解为什么使用WebSocket而不是普通的HTTP协议,如果使用HTTP协议它是下面这种情况: 我发送一条消息,发送一个发送消息的请求;* 一直轮询接收别人发送的消息,不管有没有发送都要定时去调用接口。这里明

    2023年04月20日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包