SpringCloud整合WebSocket实现用户监控

@

前言

一、建项目

1. 在父项目ams-cloud下建立maven子项目ams-websocket

SpringCloud整合WebSocket实现用户监控

2.pom文件添加常用依赖,另外添加redis依赖等,我这里直接引用common模块


            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-config

            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery

            com.alibaba.cloud
            spring-cloud-starter-alibaba-sentinel

            org.springframework.boot
            spring-boot-starter-web

            org.springframework.boot
            spring-boot-starter-websocket

            com.ams
            ams-common
            ${ams.version}

3.添加bootstrap.yml文件

server:
  port: 21000

spring:
  application:
    name: ams-websocket
  cloud:
    nacos:
      # 注册中心
      discovery:
        server-addr: http://192.168.132.129:8848
      # 配置中心
      config:
        server-addr: ${spring.cloud.nacos.discovery.server-addr}
        file-extension: yaml
        shared-configs[0]:
          data-id: ams-common.yaml
          refresh: true

logging:
  level:
    spring.: DEBUG

4.创建application

@EnableDiscoveryClient
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@ComponentScan("com.ams")
public class WebsocketApp {
    public static void main(String[] args) {
        SpringApplication.run(WebsocketApp.class,args);
    }
}

二、添加config类、拦截器类、处理器类等

1.添加config类


@Configuration
@EnableWebSocket
public class WebsocketConfig implements WebSocketConfigurer {

    @Autowired
    private RedisUtils redisUtils;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        // 注册websocket组件 添加处理器和拦截器
        // websocket是websocket服务器的请求路径可以自己定义
        registry.addHandler(new WebsocketHandler(redisUtils),"/websocket")
                //指定自定义拦截器
                .addInterceptors(new WebsocketInterceptor(redisUtils))
                //允许跨域
                .setAllowedOrigins("*");

        //在某些低版本的浏览器中不支持websocket可以用sock-js替代
        registry.addHandler(new WebsocketHandler(redisUtils),"/sock-js")
                // 指定自定义拦截器
                .addInterceptors(new WebsocketInterceptor(redisUtils))
                // 允许跨域
                .setAllowedOrigins("*")
                // 开启sockJs支持
                .withSockJS();

    }

}

2.添加拦截器类

@Slf4j
public class WebsocketInterceptor extends HttpSessionHandshakeInterceptor  {

    private final RedisUtils redisUtils;
    public WebsocketInterceptor(RedisUtils redisUtils){
        this.redisUtils=redisUtils;
    }

    /** 管理握手过程,存入用户信息 */
    @Override
    public boolean beforeHandshake(ServerHttpRequest request,
                                   ServerHttpResponse response,
                                   WebSocketHandler handler,
                                   Map map) throws Exception {
        String header_key = "Sec-WebSocket-Protocol";
        HttpHeaders headers = request.getHeaders();
        String token = headers.getFirst(header_key);
        log.info("token = [{}]", token);
        HttpHeaders responseHeaders = response.getHeaders();
        UserAuthDTO userAuthDTO = getUserInfo(token);
        if(userAuthDTO == null){
            log.error("socket连接失败 ---> token过期 ---> [{}]", token);
            response.setStatusCode(HttpStatus.NETWORK_AUTHENTICATION_REQUIRED);
            return false;
        }
        map.put("userAuthDTO",userAuthDTO);
        responseHeaders.add(header_key,token);
        return super.beforeHandshake(request, response, handler, map);

    }

    /** 通过redis读取用户信息 **/
    public UserAuthDTO getUserInfo(String token) {
        String key = token;
        if(StrUtil.isEmpty(key)){
            return null;
        }
        UserAuthDTO userAuthDTO = (UserAuthDTO) redisUtils.get(key);
        if(userAuthDTO==null){
            log.error("redis用户信息空 ---> 登录过期/token不正确");
            return null;
        }
        return userAuthDTO;
    }
}

3.添加处理器类

@Slf4j
public class WebsocketHandler extends AbstractWebSocketHandler  {

    //定义全局变量用于保存所有用户的会话
    /** 系统管理员 **/
    public static final Map SYSUSER_SOCKETS = new HashMap<>();

    private static RedisUtils redisUtils;
    public WebsocketHandler(RedisUtils redisUtils){
        WebsocketHandler.redisUtils = redisUtils;
    }

    /**
     * webSocket连接创建后调用
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        Map attrMap = session.getAttributes();
        UserAuthDTO userAuthDTO = (UserAuthDTO) attrMap.get("userAuthDTO");
        SYSUSER_SOCKETS.put(userAuthDTO.getUserId().toString(),session);
        log.info("管理员[{}]连接成功,当前在线人数[{}]", userAuthDTO.getUsername(), SYSUSER_SOCKETS.size());
    }

    /**
     * 接收到消息会调用
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        try {
            log.info("收到客户端消息[{}]", message);
            if(session.isOpen()){
                session.sendMessage(message);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 连接关闭会调用
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        log.info("客户端关闭连接....");
        Map attrMap = session.getAttributes();
        // 删除缓存
        deleteSocket(attrMap);
        // 关闭连接
        session.close();
        log.info("已关闭socket连接");
    }

    /**
     * 删除socket缓存
     */
    public static void deleteSocket(Map attr) {
        UserAuthDTO userAuthDTO = (UserAuthDTO) attr.get("userAuthDTO");
        if (!SYSUSER_SOCKETS.isEmpty()) {
            SYSUSER_SOCKETS.remove(userAuthDTO.getUserId().toString());
            log.info("管理员[{}]关闭连接了,当前在线人数[{}]", userAuthDTO.getUsername(), SYSUSER_SOCKETS.size());
        }
    }

    /**
     * 连接出错会调用
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        log.error("socket连接出错...");
        exception.printStackTrace();
        Map attrMap = session.getAttributes();
        //删除缓存
        deleteSocket(attrMap);
        // 关闭连接
        session.close();
        log.error("已关闭socket连接");
    }
}

三、添加controller

1.controller如下:

@RestController
@RequestMapping("/websocket")
@Slf4j
@RequiredArgsConstructor
public class WebsocketController {

    /** 获取在线管理用户 */
    @GetMapping(value = "getLoginSysUser")
    public R> getLoginSysUser(){
        Map userMap = WebsocketHandler.SYSUSER_SOCKETS;
        List list = new ArrayList<>();
        userMap.forEach((k,v)->{
            Map attrMap = v.getAttributes();
            UserAuthDTO userAuthDTO = (UserAuthDTO) attrMap.get("userAuthDTO");
            list.add(userAuthDTO);
        });
        return R.ok(list);
    }

}

2.运行结果
2022-03-04 16:58:56.822  INFO 15272 --- [nio-21000-exec-2] c.c.f.m.w.config.WebsocketInterceptor    : token = [83868c09-a744-4a7a-a16e-24dc3d7e8cdc]
2022-03-04 16:58:59.335  INFO 15272 --- [nio-21000-exec-2] c.c.f.m.w.handler.WebsocketHandler       : 管理员[admin]连接成功,当前在线人数[1]

随心所往,看见未来。Follow your heart,see night!

欢迎点赞、关注、留言,一起学习、交流!

Original: https://www.cnblogs.com/folyh/p/16513280.html
Author: folyh
Title: SpringCloud整合WebSocket实现用户监控

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/608380/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • JPA作持久层操作

    JPA(Hibernate是jpa的实现) jpa是对实体类操作,从而通过封装好的接口直接设置数据库的表结构。虽然jpa可以直接通过编写java代码来操作数据库表结构,避免了sql…

    Java 2023年6月13日
    069
  • JDK成长记10:Thread的基本原理和常见应用场景,你都知道么?

    相信你经过集合篇的成长,已经对JDK源码的学习轻车熟路了。接下来你将一起和我进入后半篇的学习。让我们开始吧! 在接下来10分钟,你将学习到thread 的源码原理、线程的状态变化、…

    Java 2023年6月5日
    082
  • java学习笔记day1

    一个 Java 程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作。下面简要介绍下类、对象、方法和实例变量的概念。 对象:对象是类的一个实例,有状态和行为。例如…

    Java 2023年6月5日
    068
  • 多线程_基础

    一.一个Java程序最少开几个线程? 3个:主线程;gc线程;异常处理线程 二.线程的生命周期以及状态? 阻塞的分类: 等待阻塞:执行wait(),需要notify()/notif…

    Java 2023年6月7日
    077
  • 入门clash 及 proxy 坑点

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Java 2023年6月7日
    073
  • 负载均衡

    前言 本文基于Dubbo2.6.x版本,中文注释版源码已上传github:xiaoguyu/dubbo 负载均衡,英文名称为Load Balance,其含义就是指将负载(工作任务)…

    Java 2023年6月16日
    082
  • springboot 中文索引

    http://springboot.fun/ posted on2020-06-23 16:05 tigerloveapple 阅读(155 ) 评论() 编辑 Original:…

    Java 2023年5月30日
    069
  • 根据表结构自动生成JavaBean,史上最强最专业的表结构转JavaBean的工具(第3版)

    这几天下班回家打鸡血赶进度,把第三版测试完成发布出来了! 欢迎访问TableGo官网:http://www.tablego.cn 同样对第2版的代码进行了维护和优化,对界面进行了完…

    Java 2023年6月9日
    079
  • java基础-集合

    以下为本人的学习笔记 1.集合框架概述 1.1集合框架 的作用 在实际开发中,我们经常会对一组相同类型的数据进行统一管理操作。到目前为止,我们可以使用数组结构,链表结构,二叉树来实…

    Java 2023年6月15日
    088
  • 常用Linux命令之文件相关命令(一)

    一、文件显示命令 1、cat命令: cat命令连接文件并打印到标准输出设备上,经常用来显示文件的内容,相当于DOS下的type命令 cat命令的一般格式: cat [选项] 文件名…

    Java 2023年6月8日
    0126
  • Eclipse启动Tomcat后无法访问项目

    Eclipse中的Tomcat可以正常启动,不过发布项目之后,无法访问,包括http://localhost:8080/的小猫页面也无法访问到,报404错误。这是因为Eclipse…

    Java 2023年6月8日
    067
  • Spring核心知识概述

    目录:1. IOC理论2. IOC创建对象的方式3. Spring配置4. 依赖注入5. Bean的自动装配6. 使用注解开发7. 使用纯java配置Spring8. Spring…

    Java 2023年6月5日
    070
  • 第一章:绪论相关知识点

    1.2 基本概念和术语 1.2.1 数据、数据元素、数据项和数据对象 数据 (Data) :是客观事物的符号表示,是所有能输入到计算机中并被计算机程序处理的符号的总称。包括数值型的…

    Java 2023年6月8日
    069
  • Nginx作为静态资源web服务-跨站访问

    一、跨域访问 1、什么是跨域? 参看我的另一篇博客(https://www.cnblogs.com/chrdai/p/11280895.html) 2、为什么浏览器禁止跨域访问? …

    Java 2023年5月30日
    068
  • CentOS7 怎么解决连网问题

    CentOS7 怎么解决连网问题 VmWare安装centos7无法上网怎么办?下面为大家分享了解决方法,供大家参考,具体内容如下 1.关闭防火墙 systemctl stop f…

    Java 2023年6月9日
    075
  • 【Java面试手册-基础篇】能否在Java中终止main方法?

    答案是肯定的,可以使用 System.exit() 方法终结 main() 方法。 示例代码如下: package com.magic.main; public class Mai…

    Java 2023年6月8日
    062
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球