基于 springboot websocket 的群聊实现

2021-02-02 01:08:37 +08:00
 Aidenboss

基于 springboot websocket 的群聊实现

功能列表

依赖

redis 配置

redis 默认使用 localhost:6379 。如果需要修改 host:port,可以修改 application.yml
redis 仅仅用于存储用户 username / password

源码分析

Auth 过程
String username = ((ServletServerHttpRequest) request)
  .getServletRequest().getParameter(USERNAME);
String password = ((ServletServerHttpRequest) request)
  .getServletRequest().getParameter(PASSWORD);
User user = userService.register(username, password);
// 将 user 设置到 attributes 中
attributes.put(USER, user);
return true;
连接创建
// 1. 添加 session
sessionService.add(session);
// 2. 按 username + sessionId 生成 redis key,并进行订阅,这样做可以支持多设备同一个帐号登录
MessageListener messageListener = (message, pattern) -> {
  log.info("Redis sub receive: [{}]", new String(message.getBody()));
  try {
    session.sendMessage(new TextMessage(message.getBody()));
  } catch (IOException e) {
    log.error("", e);
  }
};
redisMessageListenerContainer.addMessageListener(messageListener,
  new ChannelTopic(String.format("sub:%s:%s", SessionUtil.getUsernameFromSession(session), session.getId())));
// 由于 session 会断开,需要保存下来,以待 removeListener
messageListenerMap.put(session, messageListener);
监听消息
// 获取所有在线的 session,然后通过 redis pub 功能转发消息
sessionService.getSessions()
  .forEach(session -> subPubService.pub(session, textMessage));
心跳检查
// 核心逻辑是一个定时任务,通过延时队列 poll 实现。
// 其中 HeartbeatSessionTask 封装了 session 和对应的过期时间
this.executorService.submit(() -> {
  while (true) {
    try {
      HeartbeatSessionTask task;
      while ((task = queue.poll()) != null) {
        task.getSession().close();
        log.warn("[{}] is dead, so close", SessionUtil.getUsernameFromSession(task.session));
      }
    } catch (Exception e) {
      log.error("", e);
    }
    Thread.sleep(TimeUnit.SECONDS.toMillis(1));
  }
});

使用

服务端启动

启动后,会监听 localhost:8080 端口
其中,websocket url 为 ws:localhost:8080/ws
获取在线用户数接口为 http://localhost:8080/session/page

shell 测试

使用 wscat 测试

wscat -c 'ws://localhost:8080/ws?username=aiden&password=123'
前端测试

由于有简单的帐号体系,链接时需要制定 username / password,若 username 不存在,则直接注册成功;否则会判断 username / password 是否匹配
如 ws://localhost:8080/ws?username=aiden&password=123 才能进行连接 图示:

1660 次点击
所在节点    Java
4 条回复
wuvvu
2021-02-02 09:52:53 +08:00
支持支持
agentFitzzzzz
2021-02-02 11:30:29 +08:00
不错
razertory
2021-02-02 19:09:26 +08:00
Aidenboss
2021-02-02 19:51:18 +08:00
@razertory 感觉定位不太一样

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/750470

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX