使用SpringBoot + WebSocket实现单人聊天

Springboot + websocket 实现 一对一 单人聊天 websocket 简单聊天 阅读详情

前言

最近在做一个聊天功能,具体需求:类似微信,在一个好友列表中,点击某个好友就可以建立与该好友的聊天连接,向该好友发送消息,对方能够实时显示出来,进行真正意义上的聊天。
在做之前,不管在界面布局,还是功能实现方面都下了一点功夫,最终还是一点点实现了,现在就记录一下。

在编码之前得先了解一下WebSocket

  1. 什么是WebSocket?
  • WebSocket,即Web浏览器与Web服务器之间全双工通信标准;是HTML5中的协议,支持持久连续,http协议不支持持久性连接。Http1.0和HTTP1.1都不支持持久性的链接,HTTP1.1中的keep-alive,将多个http请求合并为1个
  • 一旦确立WebSocket通信连接,不论服务器还是客户端,任意一方都可直接向对方发送报文
  1. WebSocket特点?
  • 推送功能:支持由服务器向客户端推送数据的推送功能,这样,服务器可直接发送数据,而不必等待客户端的请求
  • 减少通信量:只要建立起WebSocket,就可以一直保持连接状态

头部字段多了下面2个属性:

Upgrade:webSocket
Connection:Upgrade

1、实现效果

点击左侧好友列表时,会建立websocket连接,把当前发消息的用户发送给websocket服务器

输入消息

2、前端实现

<!-- Chat.vue页面 -->
<template>
  <div id="chat">
    <!-- 聊天消息管理 -->
    <el-container style="height: 620px; border: 1px solid #eee">
      <el-aside width="250px">
        <user-list
          :friendList="this.friendList"
          @set-contact="getcontact"
          ref="friends"
          :activeIndex="activeIndex"
        ></user-list>
      </el-aside>
      <el-container>
        <el-header style="text-align: right; font-size: 12px">
          <span>
            <h2>{{this.username}}</h2>
          </span>
        </el-header>
        <el-main style="height:400px;" class="msg-main">
          <chat-msg ref="msg" :user="this.username" id="msg-box"></chat-msg>
        </el-main>
        <div class="m-text">
          <textarea
            placeholder="按 Ctrl + Enter 发送"
            ref="sendMsg"
            v-model="contentText"
            @keyup.enter="sendText()"
          ></textarea>
          <div class="btn" :class="{['btn-active']:contentText}" @click="sendText()">发送</div>
        </div>
      </el-container>
    </el-container>
  </div>
</template>

<script>
import UserList from "../../components/chat/friendList";
import ChatMsg from "../../components/chat/message";
import InputText from "../../components/chat/text";
export default {
  data() {
    return {
      //好友列表
      friendList: [],
      activeIndex: null,
      //当前聊天好友
      activeFriend: [],
      friends: "",
      ws: null,
      count: 0,
      userId: this.$store.state.userInfo.uid, // 当前用户ID
      username: this.$store.state.userInfo.username, // 当前用户昵称
      avatar: this.$store.state.userInfo.uavatar, // 当前用户头像
      msgList: [], // 聊天记录的数组
      contentText: "" // input输入的值
    };
  },
  components: {
    UserList,
    ChatMsg,
    InputText
  },
  mounted() {
    this.getFridends(this.userId);
  },
  destroyed() {
    // 离开页面时关闭websocket连接
    this.ws.onclose(undefined);
  },
  methods: {
    select(value) {
      this.activeIndex = this.friendList.indexOf(value);
    },
    getcontact(list) {
      console.log(this.$store.state.userInfo);
      this.activeFriend = list;
      //保存当前聊天好友
      this.friends = list.ffriendName;
      this.activeIndex = this.friendList.indexOf(this.friends);
      this.getFridendInfo(this.friends);
      this.initWebSocket(this.username);
      this.getFridendMsg(this.friends);
    },
    // 发送聊天信息
    sendText() {
      let _this = this;
      _this.$refs["sendMsg"].focus();
      if (!_this.contentText) {
        return;
      }
      let params = {
        mfromuser: _this.username,
        mtouser: _this.activeFriend[0].uusername,
        mfromavatar: _this.activeFriend[0].uavatar,
        mtoavatar: _this.avatar,
        mmsg: _this.contentText,
        mtype: 1
      };
      _this.ws.send(JSON.stringify(params)); //调用WebSocket send()发送信息的方法
      _this.contentText = "";
      setTimeout(() => {
        _this.scrollToBottom();
      }, 200);
    },
    // 进入页面创建websocket连接
    initWebSocket(id) {
      let _this = this;
      // 判断页面有没有存在websocket连接
      if (window.WebSocket) {
        var serverHot = window.location.hostname;
        // 填写本地IP地址,此处的 :8021端口号要与后端配置的一致!
        var url = "ws://" + serverHot + ":8021" + "/websocket/" + id; 
        // `ws://127.0.0.1/9101/websocket/10086/老王`
        let ws = new WebSocket(url);
        _this.ws = ws;
        ws.onopen = function(e) {
          console.log("服务器连接成功: " + url);
        };
        ws.onclose = function(e) {
          console.log("服务器连接关闭: " + url);
        };
        ws.onerror = function() {
          console.log("服务器连接出错: " + url);
        };
        ws.onmessage = function(e) {
          //接收服务器返回的数据
          console.log(e);
          let resData = e.data.split("|");
          console.log(resData);
          //更新消息
          if (resData[0] == _this.username) {
            _this.getFridendMsg(_this.friends);
          } else {
            _this.$message.error("发送消息失败,当前用户不存在");
          }
        };
      }
    },
    //获取好友列表
    async getFridends(id) {
      console.log(id);
      const { data: res } = await this.$http.get(
        "api/business/chat/getfriends/" + id
      );
      if (res.success) {
        // console.log(res);
        this.friendList = res.data;
      } else {
        this.$message.error("获取好友列表失败:" + res.data.errorMsg);
      }
    },
    //获取好友消息列表
    async getFridendMsg(name) {
      const { data: res } = await this.$http.get(
        "api/business/chat/getFriendMsg/" + name
      );
      if (res.success) {
        // console.log(res);
        this.msgList = res.data;
        //把好友聊天记录传给消息组件
        this.$refs.msg.getMsgList(this.msgList);
      } else {
        this.$message.error("获取好友消息失败:" + res.data.errorMsg);
      }
    },
    //获取好友信息
    async getFridendInfo(name) {
      const { data: res } = await this.$http.get(
        "api//system/user/getFriendInfo/" + name
      );
      if (res.success) {
        console.log(res);
        //好友信息
        this.activeFriend = res.data;
      } else {
        this.$message.error("获取好友信息失败:" + res.data.errorMsg);
      }
    },
    // 滚动条到底部
    scrollToBottom() {
      this.$nextTick(() => {
        var container = this.$el.querySelector(".msg-main");
        // console.log(container);
        // console.log(container.scrollTop);
        container.scrollTop = container.scrollHeight;
      });
    }
  }
};
</script>
<style scoped lang="less">
#chat {
  overflow: hidden;
}
.el-header {
  background-color: #b3c0d1;
  color: #333;
  line-height: 60px;
}

.el-aside {
  color: #fff;
  background-color: #2e3238;
}
.m-list {
  li {
    padding: 12px 15px;
    border-bottom: 1px solid #292c33;
    cursor: pointer;
    transition: background-color 0.1s;

    &:hover {
      background-color: rgba(255, 255, 255, 0.03);
    }
    &.active {
      background-color: rgba(255, 255, 255, 0.1);
    }
  }
  .avatar,
  .name {
    vertical-align: middle;
  }
  .avatar {
    border-radius: 2px;
  }
  .name {
    display: inline-block;
    margin: 0 0 0 15px;
  }
}
.m-message {
  padding: 10px 15px;
  li {
    margin-bottom: 15px;
  }
  .time {
    margin: 7px 0;
    text-align: center;

    > span {
      display: inline-block;
      padding: 3px 20px;
      font-size: 12px;
      color: #fff;
      border-radius: 2px;
      background-color: #dcdcdc;
    }
  }
  .avatar {
    float: left;
    margin: 0 15px 0 0;
    border-radius: 3px;
  }
  .text {
    display: inline-block;
    position: relative;
    padding: 3px 17px;
    max-width: ~"calc(100% - 40px)";
    min-height: 30px;
    line-height: 2.5;
    font-size: 12px;
    text-align: left;
    word-break: break-all;
    background-color: #fafafa;
    border-radius: 4px;

    &:before {
      content: " ";
      position: absolute;
      top: 9px;
      right: 100%;
      border: 6px solid transparent;
      border-right-color: #fafafa;
    }
  }

  .self {
    text-align: right;

    .avatar {
      float: right;
      margin: 0 0 0 10px;
    }
    .text {
      background-color: #b2e281;

      &:before {
        right: inherit;
        left: 100%;
        border-right-color: transparent;
        border-left-color: #b2e281;
      }
    }
  }
}
.m-text {
  display: flex;
  height: 90px;
  border-top: solid 1px #ddd;
  textarea {
    padding-left: 10px;
    height: 100%;
    width: 100%;
    border: none;
    outline: none;
    font-family: "Micrsofot Yahei";
    resize: none;
  }
  .btn {
    height: 2.3rem;
    min-width: 4rem;
    background: #e0e0e0;
    padding: 0.5rem;
    font-size: 0.88rem;
    color: white;
    text-align: center;
    border-radius: 0.2rem;
    margin-left: 0.5rem;
    transition: 0.5s;
  }
  .btn-active {
    background: #409eff;
  }
}
</style>
<!-- friendList.vue -->
<template>
  <div class="m-list">
    <ul v-for="(friend, i) in friendList">
      <li @click="setContact(i)" :class="{'active':currentIndex===i}">
        <img class="avatar" width="50" height="50" />
        <p class="name">{{friend.ffriendName}}</p>
      </li>
    </ul>
  </div>
</template>
<script>
export default {
  data() {
    return {
      currentIndex: this.activeIndex
    };
  },
  props: ["friendList", "activeIndex"],
  methods: {
    setContact(index) {
      this.currentIndex = index;
      console.log(this.currentIndex);
      //与父组件进行通信。把当前点击好友的用户信息传给父组件
      this.$emit("set-contact", this.friendList[index]);
    }
  }
};
</script>
<style lang="less" scoped>
.m-list {
  li {
    padding: 12px 15px;
    border-bottom: 1px solid #292c33;
    cursor: pointer;
    transition: background-color 0.1s;

    &:hover {
      background-color: rgba(255, 255, 255, 0.03);
    }
    &.active {
      background-color: rgba(255, 255, 255, 0.1);
    }
  }
  .avatar,
  .name {
    vertical-align: middle;
  }
  .avatar {
    border-radius: 2px;
  }
  .name {
    display: inline-block;
    margin: 0 0 0 15px;
  }
}
</style>
<!-- message.vue -->
<template>
  <div class="m-message">
    <ul v-for="item in msgList">
      <li>
        <p class="time">
          <span>{{item.mcreateTime | time}}</span>
        </p>
        <div class="main" :class="{self:item.mfromUser===username}">
          <div class="title">{{item.mfromUser}}</div>
          <img class="avatar" width="40" height="40" />
          <div class="text">{{item.mmsg}}</div>
        </div>
      </li>
    </ul>
  </div>
</template>
<script>
export default {
  data() {
    return {
      msgList: this.userList,
      username: this.user
    };
  },
  props: ["user", "userList"],
  methods: {
    getMsgList(list) {
      console.log(list);
      this.msgList = list;
    },
  },
  filters: {
    // 将日期过滤为 yy-mm-dd hh:mm:ss
    time(date) {
      if (typeof date === "string") {
        date = new Date(date); //把定义的时间赋值进来进行下面的转换
        let year = date.getFullYear();
        let month = date.getMonth() + 1;
        let day = date.getDate();
        let hour = date.getHours();
        let minute = date.getMinutes();
        let second = date.getSeconds();
        return (
          year +
          "-" +
          month +
          "-" +
          day +
          " " +
          hour +
          ":" +
          minute +
          ":" +
          second
        );
      }
    }
  }
};
</script>
<style lang="less" scoped>
.m-message {
  padding: 10px 15px;
  // overflow-y: scroll;
  li {
    margin-bottom: 15px;
  }
  .time {
    margin: 7px 0;
    text-align: center;

    > span {
      display: inline-block;
      padding: 3px 20px;
      font-size: 12px;
      color: #fff;
      border-radius: 2px;
      background-color: #dcdcdc;
    }
  }
  .avatar {
    float: left;
    margin: 0 15px 0 0;
    border-radius: 3px;
  }
  .text {
    display: inline-block;
    position: relative;
    padding: 3px 17px;
    max-width: ~"calc(100% - 40px)";
    min-height: 30px;
    line-height: 2.5;
    font-size: 12px;
    text-align: left;
    word-break: break-all;
    background-color: #fafafa;
    border-radius: 4px;

    &:before {
      content: " ";
      position: absolute;
      top: 9px;
      right: 100%;
      border: 6px solid transparent;
      border-right-color: #fafafa;
    }
  }

  .self {
    text-align: right;

    .avatar {
      float: right;
      margin: 0 0 0 10px;
    }
    .text {
      background-color: #b2e281;

      &:before {
        right: inherit;
        left: 100%;
        border-right-color: transparent;
        border-left-color: #b2e281;
      }
    }
  }
}
</style>

3、后端实现

添加依赖

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
// WebSocketController.java
@Controller
@ServerEndpoint(value = "/websocket/{user}")
@Api(tags = "业务模块-websocket连接接口")
public class WebSocketController {

    // 这里使用静态,让 service 属于类
    private static ChatMsgService chatMsgService;
    // 注入的时候,给类的 service 注入
    @Resource
    public void setChatService(ChatMsgService chatService) {
        WebSocketController.chatMsgService = chatService;
    }

    // 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;
    // concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
    private static ConcurrentHashMap<String, WebSocketController> webSocketSet = new ConcurrentHashMap<String, WebSocketController>();
    // 与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session WebSocketSession;
    // 记录当前发消息的用户
    private String user = "";


    /**
     * 连接建立成功调用的方法
     *
     * session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    @OnOpen
    public void onOpen(@PathParam(value = "user") String param, Session WebSocketsession) {
        user = param;
		// System.out.println(user);
        this.WebSocketSession = WebSocketsession;
        webSocketSet.put(param, this);// 加入map中
        addOnlineCount();     // 在线数加1
        // System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
    }


    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        if (!user.equals("")) {
            webSocketSet.remove(user); // 从set中删除
            subOnlineCount();     // 在线数减1
            // System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
        }
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param chatmsg 客户端发送过来的消息
     * @param session 可选的参数
     */
    @OnMessage
    public void onMessage(String chatmsg, Session session)  throws SystemException{
        JSONObject jsonObject = JSONObject.parseObject(chatmsg);
        //给指定的人发消息
        sendToUser(jsonObject.toJavaObject(ChatMsgVO.class));
        //sendAll(message);
    }

    /**
     * 给指定的人发送消息
     *
     * @param chatMsg 消息对象
     */
    public void sendToUser(ChatMsgVO chatMsg)  throws SystemException{
        String fromUser = chatMsg.getMFromUser();
        String mMsg = chatMsg.getMMsg();
        System.out.println(fromUser);
        mMsg= EmojiFilter.filterEmoji(mMsg);//过滤输入法输入的表情
        chatMsgService.InsertChatMsg(chatMsg);
        try {
            if (webSocketSet.get(fromUser) != null) {
                webSocketSet.get(fromUser).sendMessage(chatMsg.getMFromUser()+"|"+mMsg);
            }else{
                webSocketSet.get(chatMsg.getMFromUser()).sendMessage("0"+"|"+"当前用户不在线");
            }
        } catch (IOException e) {
            throw new SystemException(SystemCodeEnum.PARAMETER_ERROR,e.getMessage());
        }
    }

    /**
     * 给所有人发消息
     *
     * @param message
     */
    private void sendAll(String message) {
        String sendMessage = message.split("[|]")[1];
        //遍历HashMap
        for (String key : webSocketSet.keySet()) {
            try {
                //判断接收用户是否是当前发消息的用户
                if (!user.equals(key)) {
                    webSocketSet.get(key).sendMessage(sendMessage);
                    System.out.println("key = " + key);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 发生错误时调用
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    /**
     * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
     *
     * @param message
     * @throws IOException
     */
    public void sendMessage(String message) throws IOException {
        this.WebSocketSession.getBasicRemote().sendText(message);
        //this.session.getAsyncRemote().sendText(message);
    }
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }
    public static synchronized void addOnlineCount() {
        WebSocketController.onlineCount++;
    }
    public static synchronized void subOnlineCount() {
        WebSocketController.onlineCount--;
    }
}

//ChatController.java
@RestController
@RequestMapping("business/chat")
public class ChatMsgController {
    @Resource
    private ApiUserService apiUserService;

    @Resource
    private ChatMsgService chatMsgService;
    
    @Resource
    private ChatFriendsService chatFriendsService;

    @ApiOperation(value = "获取好友聊天记录", notes = "根据当前用户查询好友聊天记录")
    @GetMapping("/getFriendMsg/{username}")
    public ResponseBean<List<ChatMsg>> getFriendMsg(@PathVariable String username) throws SystemException {
        UserInfoVO userInfoVO = apiUserService.info();
        List<ChatMsg> chatMsgs = chatMsgService.getFriendMsg(userInfoVO.getUsername(), username);
        return ResponseBean.success(chatMsgs);
    }

    @ApiOperation(value = "获取用户好友", notes = "根据用户id查询用户好友")
    @GetMapping("/getfriends/{id}")
    public ResponseBean<List<ChatFriends>> getFriends(@PathVariable Long id) throws SystemException {
        List<ChatFriends> chatFriendsList = chatFriendsService.getFriends(id);
        return ResponseBean.success(chatFriendsList);
    } 

}

springboot+websocket聊天室(多人聊天,单人聊天) springboot集成websocket实现聊天室功能(可多人聊天和单独聊天) 立即下载

相关推荐

spring boot整合WebSocket实现多人聊天室的实例

spring boot整合WebSocket + stomp 协议实现多人聊天室的实例

175. Spring Boot WebSocket:单聊

【视频&交流平台】 à SpringBoot视频 http://study.163.com/course/introduction.htm?courseId=1004329008 à SpringCloud视频 http://study.163.com/course/introduction.htm?courseId=1004638001 à Spring Boot源码 https:/

悟纤学院 2万+

使用Go基于WebSocket开发的web聊天应用。单聊,群聊。文字,图片,语音,视频消息,屏幕共享,剪切板图片

go语言开发项目go语言开发项目go语言开发项目go语言开发项目go语言开发项目 go语言开发项目go语言开发项目go语言开发项目go语言开发项目go语言开发项目 go语言开发项目go语言开发项目go语言开发项目go语言开发项目go语言开发项目 go语言开发项目go语言开发项目go语言开发项目go语言开发项目go语言开发项目 go语言开发项目go语言开发项目go语言开发项目go语言开发项目go语言开发项目 go语言开发项目go语言开发项目go语言开发项目go语言开发项目go语言开发项目 go语言开发项目go语言开发项目go语言开发项目go语言开发项目go语言开发项目 go语言开发项目go语言开发项目go语言开发项目go语言开发项目go语言开发项目 go语言开发项目go语言开发项目go语言开发项目go语言开发项目go语言开发项目 go语言开发项目go语言开发项目go语言开发项目go语言开发项目go语言开发项目 go语言开发项目go语言开发项目go语言开发项目go语言开发项目go语言开发项目

SpringBoot+WebSocket实现简单的一对一web聊天

前言 最近项目中要实现客服系统,其实网上有很多的服务商提供这种接口,但最终决定使用SpringBoot+WebSocket的方式实现。 下面我的项目的结构是使用SpringBoot+Nginx实现的前后端分离的,但是这个不重要,这里只是提出来。 SpringBoot和Nginx我就不在这里多说了,网上有很多教程。过几天我也会专门写几篇文章记录一下。 1. 后台代码 在pom.xml中添加sprin...

Crazy_young_man的博客 6377

双有源桥DC-DC变换器:原理、软开关与移相控制深度解析

隔离型DC-DC变换器是电力电子系统的核心部件,通过高频变压器实现电气隔离与电压匹配,保障系统安全与灵活适配。其工作原理基于功率半导体器件的开关动作,通过调制策略控制能量传输。该技术的核心价值在于实现高效、高功率密度的电能转换,并支持双向能量流动,这对于提升系统整体能效和运行灵活性至关重要。在新能源储能、电动汽车V2G及数据中心供电等场景中,双向能量流成为刚性需求,推动了如双有源桥等先进拓扑的应用。本文聚焦于双有源桥这一实现高效双向隔离变换的“明星”方案,深入剖析其利用移相控制实现软开关的机理。通过分析谐振

weixin_34195142的博客 378

景观格局指数计算方法及代表的生态学意义(待补充)

景观指数 斑块密度(PD) 斑块密度(PD)表现某种斑块在景观中的密度,可反映出景观整体的异质性与破碎度[17],公式为PD=NP/A(1)式中NP———斑块数量,个A———景观或斑块的总面积,hm2PD———斑块密度,个/hm2 最大斑块指数(LPI) 最大斑块指数(LPI)用于确定景观中的优势斑块类型,间接反映人类活动干扰的方向和大小,公式为LPI=amaxA×100%(0≤LPI≤100%)(2)式中amax———景观或某一种斑块类型中最大斑块的面积,hm2LPI———最大斑块指数,% 凝聚

soderayer的博客 13万+

springboot整合websocket实现简单聊天功能

springboot整合websocket,并使用stomp协议方式客户端进行通信,实现简单的群聊功能

小蜜蜂1010的博客 2400

启动盘安装Win10完整指南:U盘制作、BIOS设置与分区排错

系统重装是解决电脑卡顿、系统崩溃、病毒残留等问题的基础操作,而U盘启动盘则是目前最主流的安装介质。其核心原理在于通过Rufus等工具,将原版ISO镜像写入U盘,并依据主板固件类型(UEFI或Legacy)选择对应的GPT或MBR分区表,确保引导程序能正确加载。掌握这些底层概念,不仅能提升安装成功率,还能避免因引导模式不匹配导致的黑屏、无法启动等问题。在实际应用中,无论是老旧电脑升级、硬盘更换,还是需要纯净的系统环境,制作一个可靠的启动盘都是必备技能。本文从备份数据、下载官方镜像讲起,逐步演示U盘制作、启动快

weixin_32667955的博客 339

springboot webSocket实现群聊/单聊

springboot webSocket实现群聊/单聊 webSocket简介: WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。 代码: 1.maven依赖: <dependency> <groupId>org.spring

Helloworld_pang的博客 869

Multisim仿真入门:单相半波可控整流电路从搭建到波形分析(附避坑指南)

本文为电力电子技术初学者提供了一份详细的Multisim仿真指南,手把手教你从零搭建单相半波可控整流电路。通过对比纯电阻、阻感负载及加入续流二极管后的波形变化,直观理解晶闸管触发、电感续流等核心原理,并附有实用的参数设置与常见问题避坑指南,帮助你将抽象理论转化为可视化的工程实践。

weixin_29208077的博客 343

Rstudio安装org.Hs.eg.db

自己也是个小白,初次安装org.Hs.eg.db碰到好多问题,步骤总结如下: 第一,instal.packages()安装,不行则换 BiocManager::install() 第二,如BiocManager不成,说明不是最新版本,可按提示安装最新版 BiocManager::install(version = '3.13') #由于R版本较新,按照提示中的相关信息,安装最新版本的 第三,再次安装 BiocManager::install("org.Hs.eg.db") 第四,之后每个人.

ZH_DDong的博客 2万+

SpringBoot + WebSocket 实现单人在线聊天

本内容根据江南一点雨松哥的 SpringBoot 付费视频所做的学习笔记,想具体详细了解内容的,请关注微信公众号:江南一点雨。 实现单人在线聊天与之前实现聊天室的区别,在于单人在线聊天必须存在用户的概念。我们可以使用 SpringSecurity 非常方便的实现这一需求。为了方便,我们在之前的聊天室代码中进行添加功能。 我们需要引入 SpringSecurity 依赖,并简单配置 SecurityConfig。关于 SpringSecurity 不过多介绍。 <dependency> .

一天无聊 1594

关于SVPWM七段式五段式调制后的相电压和线电压波形——大疆DJI技术笔试

1.SVPWM七段式/五段式调制的相电压和线电压波形 脉宽调制(PWM)在并网变流技术中得到了广泛的应用。与正弦脉宽调制(SPWM)的控制方法相比,SVPWM方法具有直流侧电压利用率高,电压谐波小,易于数字化实现等显著的优点,从而使SVPWM在实际的应用中越来越普遍。TMS320F28335是32位浮点的DSP控制器,具有150MHz的高速处理能力,18路PWM输出,与前几代数字信号控制器相比,性能平均提高了50%。其中具体的SVPWM理论实现的原理,请参考我的博客永磁同步电机的矢量控制策略(七)一一一SV

昔时扬尘处 2万+

Springboot+websocket 实现多人聊天室/单人聊天 Demo

Springboot+websocket 实现多人聊天室/单人聊天 Demo 去发现同类优质开源项目:https://gitcode.com/ 本项目是一个使用Springboot和websocket技术实现的多人聊天室与单人聊天室的示例。以下是对该项目的详细介绍: 项目简介 本项目采用了Springboot框架与websocket技术,实现了一个简单易用的聊天室功能。项目包括多人聊天室与单人聊天...

gitblog_06763的博客 766

网格自适应实战 | 攻克超弹性体大变形不收敛难题

本文针对超弹性体(如橡胶)在大变形仿真中因网格严重扭曲导致计算不收敛的难题,提供了基于ANSYS网格自适应技术的实战解决方案。文章详细阐述了从问题诊断、模型准备到核心参数设置的完整流程,并介绍了结合混合U-P单元技术的进阶组合策略,有效攻克了材料压缩等场景下的仿真收敛问题。

week9的博客 515

7.DJI-PSDK:psdk负载应用固件升级(基于RTOS)

在单片机应用程序开发阶段,我们可以借助keil5和J-LINK来直接下载应用程序进行开发和调试, 但在产品交付之后,我们对应用程序做了改动和升级,是断然不可能采用这种方式的,我们应该将新版本的程序固件打包发给客户, 能够方便用户通过DJI Assistant2选择更新负载设备的固件,导入本地固件程序包,更新负载设备。使用STM32F4 开发的负载设备从Flash 中直接读取固件文件并运行负载设备程序,因此开发者需先烧录Bootloader 再烧录应用固件,烧录Bootloader 的步骤不再赘述。

哒宰的博客 673

springboot 使用 webSocket 实现多人聊天 + 单人聊天

# 后端 WebSocket服务端注解 事件类型 事件描述 @OnOpen onOpen 当打开连接后触发 @OnMessage onMessage 当接收客户端信息时触发 @OnClose onClose 当连接关闭时触发 @OnError onError 当通信异常时触发 # pom.xml <!-- spring Websocket --> ...

实习打字猿的博客 2917

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Spring Boot + WebSocket 聊天室(多人聊天,单人聊天)

本项目是一个基于Spring Boot和WebSocket技术实现的聊天室应用。通过集成WebSocket,实现了多人聊天和单人聊天的功能,为用户提供了一个实时通信的平台。 ## 功能特点 - **多人聊天**:支持多个用户同时在线聊天,实时接收和发送消息。 - **单人聊天**:用户可以选择与其他特定用户进行一对一的私密聊天。 - **实时通信**:利用WebSocket技术,确保消息的实时

gitblog_09780的博客 474

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Springbootwebsocket实现多人聊天室单人聊天Demo:构建即时通讯体验

Springbootwebsocket实现多人聊天室单人聊天Demo:构建即时通讯体验 去发现同类优质开源项目:https://gitcode.com/ 在如今信息爆炸的时代,即时通讯工具已成为人们日常生活和工作的重要组成部分。本文将向您介绍一个开源项目——Springbootwebsocket实现多人聊天室单人聊天Demo,该项目的核心功能是利用Springboot和websocket技术实现一...

gitblog_06731的博客 663

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

基于spingboot的websocket订阅、广播、多人聊天室示例

基于spingboot的websocket多人聊天系统。包括订阅,广播、点对点单人聊天,多人聊天室功能。

神尐破 769

java整合WebSocket

WebSocket介绍、与springboot整合、发布问题解决

Dust Heart的博客 2966

【十五】springboot整合WebSocket实现聊天室

springboot整合WebSocket实现聊天室

weixin_56995925的博客 2万+

springboot 网页聊天室

基于springboot的网页聊天室,采用websocket通信协议,可以进行多人聊天,单人聊天,群发功能。 1:输入昵称登录 2:聊天界面 下载完成后使用maven下载资源包,运行后使用127.0.0.1/login登录可进行聊天。下载地址:https://download.youkuaiyun.com/download/fly_rice/12019068 ...

fly_rice的博客 1125

Springboot+Vue实现在线聊天室项目-webSocket实现的消息转发

Springboot+Vue实现在线聊天室项目 该聊天室为大二上学期计算机网络大作业,并且是本人第一次使用vue实现前后端分离的项目,前端架构尚未熟悉可能会出现一些不妥之处,还请大佬们指出。(本文章写于项目整体完成上线之后,所以一些细节并未写出) 消息推送的实现 配置Controller类 @MessageMapping("/test") public void test(WebSocketMessage message){ message.setTimeStamp(new Date

ShuShengYey的博客 962

SpringBoot整合websocket实现在线客服聊天

websocket最伟大之处在于服务器和客户端可以在给定的时间范围内的任意时刻,相互推送信息。 浏览器和服务器只需要要做一个握手的动作,在建立连接之后,服务器可以主动传送数据给客户端,客户端也可以随时向服务器发送数据。 实现功能:springboot整合websocket实现一对一,多对多聊天系统。 依赖 <dependency> <groupId>com.alibaba</groupId> <

浅汐 7万+
上一篇: Docker中的Redis、RabbitMQ及Nacos的密码修改
下一篇: MySQL中的join查询
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值