SpringCloud整合WebSocket实现用户监控

打印 上一主题 下一主题

主题 905|帖子 905|积分 2719

@
目录


  1. [/code][size=5]一、建项目[/size]
  2. [size=3]1. 在父项目ams-cloud下建立maven子项目ams-websocket[/size]
  3. [img]https://img-blog.csdnimg.cn/e57204e3c5f64ce386ce31e0ffc60544.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAZm9seWg=,size_20,color_FFFFFF,t_70,g_se,x_16[/img]
  4. [size=3]2.pom文件添加常用依赖,另外添加redis依赖等,我这里直接引用common模块[/size]
  5. [code]    <dependencies>
  6.         <dependency>
  7.             <groupId>com.alibaba.cloud</groupId>
  8.             <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  9.         </dependency>
  10.         <dependency>
  11.             <groupId>com.alibaba.cloud</groupId>
  12.             <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  13.         </dependency>
  14.         <dependency>
  15.             <groupId>com.alibaba.cloud</groupId>
  16.             <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  17.         </dependency>
  18.         <dependency>
  19.             <groupId>org.springframework.boot</groupId>
  20.             <artifactId>spring-boot-starter-web</artifactId>
  21.         </dependency>
  22.         <dependency>
  23.             <groupId>org.springframework.boot</groupId>
  24.             <artifactId>spring-boot-starter-websocket</artifactId>
  25.         </dependency>
  26.         <dependency>
  27.             <groupId>com.ams</groupId>
  28.             <artifactId>ams-common</artifactId>
  29.             <version>${ams.version}</version>
  30.         </dependency>
  31.     </dependencies>
复制代码
3.添加bootstrap.yml文件
  1. server:
  2.   port: 21000
  3. spring:
  4.   application:
  5.     name: ams-websocket
  6.   cloud:
  7.     nacos:
  8.       # 注册中心
  9.       discovery:
  10.         server-addr: http://192.168.132.129:8848
  11.       # 配置中心
  12.       config:
  13.         server-addr: ${spring.cloud.nacos.discovery.server-addr}
  14.         file-extension: yaml
  15.         shared-configs[0]:
  16.           data-id: ams-common.yaml
  17.           refresh: true
  18.          
  19. logging:
  20.   level:
  21.     spring.: DEBUG
复制代码
4.创建application
  1. @EnableDiscoveryClient
  2. @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
  3. @ComponentScan("com.ams")
  4. public class WebsocketApp {
  5.     public static void main(String[] args) {
  6.         SpringApplication.run(WebsocketApp.class,args);
  7.     }
  8. }
复制代码
二、添加config类、拦截器类、处理器类等

1.添加config类
  1. @Configuration
  2. @EnableWebSocket
  3. public class WebsocketConfig implements WebSocketConfigurer {
  4.     @Autowired
  5.     private RedisUtils redisUtils;
  6.     @Override
  7.     public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
  8.         // 注册websocket组件 添加处理器和拦截器
  9.         // websocket是websocket服务器的请求路径可以自己定义
  10.         registry.addHandler(new WebsocketHandler(redisUtils),"/websocket")
  11.                 //指定自定义拦截器
  12.                 .addInterceptors(new WebsocketInterceptor(redisUtils))
  13.                 //允许跨域
  14.                 .setAllowedOrigins("*");
  15.         //在某些低版本的浏览器中不支持websocket可以用sock-js替代
  16.         registry.addHandler(new WebsocketHandler(redisUtils),"/sock-js")
  17.                 // 指定自定义拦截器
  18.                 .addInterceptors(new WebsocketInterceptor(redisUtils))
  19.                 // 允许跨域
  20.                 .setAllowedOrigins("*")
  21.                 // 开启sockJs支持
  22.                 .withSockJS();
  23.     }
  24. }
复制代码
2.添加拦截器类
  1. @Slf4j
  2. public class WebsocketInterceptor extends HttpSessionHandshakeInterceptor  {
  3.     private final RedisUtils redisUtils;
  4.     public WebsocketInterceptor(RedisUtils redisUtils){
  5.         this.redisUtils=redisUtils;
  6.     }
  7.    
  8.         /** 管理握手过程,存入用户信息 */
  9.     @Override
  10.     public boolean beforeHandshake(ServerHttpRequest request,
  11.                                    ServerHttpResponse response,
  12.                                    WebSocketHandler handler,
  13.                                    Map<String, Object> map) throws Exception {
  14.         String header_key = "Sec-WebSocket-Protocol";
  15.         HttpHeaders headers = request.getHeaders();
  16.         String token = headers.getFirst(header_key);
  17.         log.info("token = [{}]", token);
  18.         HttpHeaders responseHeaders = response.getHeaders();
  19.         UserAuthDTO userAuthDTO = getUserInfo(token);
  20.         if(userAuthDTO == null){
  21.             log.error("socket连接失败 ---> token过期 ---> [{}]", token);
  22.             response.setStatusCode(HttpStatus.NETWORK_AUTHENTICATION_REQUIRED);
  23.             return false;
  24.         }
  25.         map.put("userAuthDTO",userAuthDTO);
  26.         responseHeaders.add(header_key,token);
  27.         return super.beforeHandshake(request, response, handler, map);
  28.     }
  29.     /** 通过redis读取用户信息 **/
  30.     public UserAuthDTO getUserInfo(String token) {
  31.         String key = token;
  32.         if(StrUtil.isEmpty(key)){
  33.             return null;
  34.         }
  35.         UserAuthDTO userAuthDTO = (UserAuthDTO) redisUtils.get(key);
  36.         if(userAuthDTO==null){
  37.             log.error("redis用户信息空 ---> 登录过期/token不正确");
  38.             return null;
  39.         }
  40.         return userAuthDTO;
  41.     }
  42. }
复制代码
3.添加处理器类
  1. @Slf4j
  2. public class WebsocketHandler extends AbstractWebSocketHandler  {
  3.     //定义全局变量用于保存所有用户的会话
  4.     /** 系统管理员 **/
  5.     public static final Map<String, WebSocketSession> SYSUSER_SOCKETS = new HashMap<>();
  6.     private static RedisUtils redisUtils;
  7.     public WebsocketHandler(RedisUtils redisUtils){
  8.         WebsocketHandler.redisUtils = redisUtils;
  9.     }
  10.     /**
  11.      * webSocket连接创建后调用
  12.      */
  13.     @Override
  14.     public void afterConnectionEstablished(WebSocketSession session) throws Exception {
  15.         Map<String, Object> attrMap = session.getAttributes();
  16.         UserAuthDTO userAuthDTO = (UserAuthDTO) attrMap.get("userAuthDTO");
  17.         SYSUSER_SOCKETS.put(userAuthDTO.getUserId().toString(),session);
  18.         log.info("管理员[{}]连接成功,当前在线人数[{}]", userAuthDTO.getUsername(), SYSUSER_SOCKETS.size());
  19.     }
  20.     /**
  21.      * 接收到消息会调用
  22.      */
  23.     @Override
  24.     protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
  25.         try {
  26.                        log.info("收到客户端消息[{}]", message);
  27.             if(session.isOpen()){
  28.                 session.sendMessage(message);
  29.             }
  30.         } catch (Exception e) {
  31.             e.printStackTrace();
  32.         }
  33.     }
  34.     /**
  35.      * 连接关闭会调用
  36.      */
  37.     @Override
  38.     public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
  39.         log.info("客户端关闭连接....");
  40.         Map<String, Object> attrMap = session.getAttributes();
  41.         // 删除缓存
  42.         deleteSocket(attrMap);
  43.         // 关闭连接
  44.         session.close();
  45.         log.info("已关闭socket连接");
  46.     }
  47.     /**
  48.      * 删除socket缓存
  49.      */
  50.     public static void deleteSocket(Map<String, Object> attr) {
  51.         UserAuthDTO userAuthDTO = (UserAuthDTO) attr.get("userAuthDTO");
  52.         if (!SYSUSER_SOCKETS.isEmpty()) {
  53.             SYSUSER_SOCKETS.remove(userAuthDTO.getUserId().toString());
  54.             log.info("管理员[{}]关闭连接了,当前在线人数[{}]", userAuthDTO.getUsername(), SYSUSER_SOCKETS.size());
  55.         }
  56.     }
  57.     /**
  58.      * 连接出错会调用
  59.      */
  60.     @Override
  61.     public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
  62.         log.error("socket连接出错...");
  63.         exception.printStackTrace();
  64.         Map<String, Object> attrMap = session.getAttributes();
  65.         //删除缓存
  66.         deleteSocket(attrMap);
  67.         // 关闭连接
  68.         session.close();
  69.         log.error("已关闭socket连接");
  70.     }
  71. }
复制代码
三、添加controller

1.controller如下:
  1. @RestController
  2. @RequestMapping("/websocket")
  3. @Slf4j
  4. @RequiredArgsConstructor
  5. public class WebsocketController {
  6.     /** 获取在线管理用户 */
  7.     @GetMapping(value = "getLoginSysUser")
  8.     public R<List<UserAuthDTO>> getLoginSysUser(){
  9.         Map<String, WebSocketSession> userMap = WebsocketHandler.SYSUSER_SOCKETS;
  10.         List<UserAuthDTO> list = new ArrayList<>();
  11.         userMap.forEach((k,v)->{
  12.             Map<String, Object> attrMap = v.getAttributes();
  13.             UserAuthDTO userAuthDTO = (UserAuthDTO) attrMap.get("userAuthDTO");
  14.             list.add(userAuthDTO);
  15.         });
  16.         return R.ok(list);
  17.     }
  18.    
  19. }
复制代码
2.运行结果
  1. 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]
  2. 2022-03-04 16:58:59.335  INFO 15272 --- [nio-21000-exec-2] c.c.f.m.w.handler.WebsocketHandler       : 管理员[admin]连接成功,当前在线人数[1]
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

刘俊凯

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表