RuoYi-Cloud-Plus集成 WebSocket
创始人
2024-02-29 18:26:32
0

学习地址:https://blog.csdn.net/qq_43898141/article/details/123744468

  1. 添加websocket 依赖
 org.springframework.bootspring-boot-starter-websocketorg.springframework.bootspring-boot-starter-web
  1. 添加配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;@Configurationpublic class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}}
  1. webSocket 代码
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.ruoyi.common.core.config.systemConfig;
import com.ruoyi.common.core.utils.SpringUtils;
import com.ruoyi.common.redis.service.RedisService;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;@ServerEndpoint(value = "/websocket/{userName}")
@Component
public class WebSocketService implements Serializable {//concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。@JsonBackReferenceprivate static Map webSocketMap = new ConcurrentHashMap<>();/*** 与某个客户端的连接会话,需要通过它来给客户端发送数据*/private Session session;/*** 接收userName*/private String userName = "";/*** 连接建立成功调用的方法*/@OnOpenpublic void onOpen(Session session, @PathParam("userName") String userName) {this.session = session;this.userName = userName;webSocketMap.put(userName, this);System.err.println("----------------------------------------------------------------------------");System.err.println("用户连接:" + userName + ":" + userName + ",当前在线人数为:" + webSocketMap.size());sendMessage("来自后台的反馈:连接成功");webSocketMap.forEach((k, v) -> System.err.println(k));}/*** 连接关闭调用的方法*/@OnClosepublic void onClose(@PathParam("userName") String userName) {if (webSocketMap.containsKey(userName)) {webSocketMap.remove(userName);}System.err.println("----------------------------------------------------------------------------");System.err.println(userName + "用户退出,当前在线人数为:" + webSocketMap.size());}/*** 收到客户端消息后调用的方法** @param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message, Session session) {System.err.println("收到用户消息:" + userName + ",报文:" + message);//可以群发消息//消息保存到数据库、redisif (message != null) System.err.println("");}/*** 连接失败调用方法* @param session* @param error*/@OnErrorpublic void onError(Session session, Throwable error) {System.err.println("用户错误:" + this.userName + ",原因:" + error.getMessage());error.printStackTrace();}/*** 连接服务器成功后主动推送*/public void sendMessage(String message) {try {session.getBasicRemote().sendText(message);} catch (IOException e) {e.printStackTrace();}}/*** 向指定客户端发送消息* 

* // * @param userName* //* @param message*/public static void sendMessage(String userName, String message) {try {WebSocketService webSocketService = webSocketMap.get(userName);if (webSocketService != null) {webSocketService.getSession().getBasicRemote().sendText(message);}} catch (IOException e) {e.printStackTrace();throw new RuntimeException(e.getMessage());}}//下面方法根据自己情况 删 留public Session getSession() {return session;}public void setSession(Session session) {this.session = session;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public static Map getWebSocketMap() {return webSocketMap;}public static void setWebSocketMap(Map webSocketMap) {WebSocketService.webSocketMap = webSocketMap;}public static void put(String key, WebSocketService data) {webSocketMap.put(key, data);}public static WebSocketService get(String key) {return webSocketMap.get(key);}public static void del(String key) {webSocketMap.remove(key);}

  1. 网管配置服务转发
# websocket模块#服务名称
- id: ruoyi-chat-websocket#转发的服务uri: lb:ws://ruoyi-chat#转发设置predicates:- Path=/websocket/**#请求地址后一位,如:/socket/xxx/xx  去掉socket = /xxx/xxfilters:- StripPrefix=1

![image.png](https://img-blog.csdnimg.cn/img_convert/32acef73a1abfd227ed77ccc0f6817d8.png#averageHue=#26201f&clientId=u9d4ea33d-393b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=266&id=uc07774d6&margin=[object Object]&name=image.png&originHeight=333&originWidth=579&originalType=binary&ratio=1&rotation=0&showTitle=false&size=23273&status=done&style=none&taskId=ua2626c24-d217-46c1-b822-031da7c8718&title=&width=463.2)

  1. 重要: 如果你的webSocket 没有Token 也没有任何认证的话 需要开放白名单。

![image.png](https://img-blog.csdnimg.cn/img_convert/d447914b835fc231714e479c4aa77f90.png#averageHue=#242120&clientId=u9d4ea33d-393b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=445&id=u9c548f9b&margin=[object Object]&name=image.png&originHeight=556&originWidth=741&originalType=binary&ratio=1&rotation=0&showTitle=false&size=30682&status=done&style=none&taskId=ue6b799a9-d27e-4b9c-a1b6-9a1b16332bd&title=&width=592.8)

 # 不校验白名单ignore:whites:- /code- /auth/logout- /auth/login- /auth/smsLogin- /auth/xcxLogin- /auth/mobileLogin- /websocket/**
  1. **开始测试 **http://www.jsons.cn/websocket/

![image.png](https://img-blog.csdnimg.cn/img_convert/0a64a7836884b0e985cdbf033b527dd2.png#averageHue=#fdfaf9&clientId=u9d4ea33d-393b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=251&id=u4344464a&margin=[object Object]&name=image.png&originHeight=314&originWidth=1539&originalType=binary&ratio=1&rotation=0&showTitle=false&size=26400&status=done&style=none&taskId=u8afb276b-00ce-43b5-9bfa-4d7072a7bd8&title=&width=1231.2)

  1. 如果出现连接成功 立马断开的问题 排查思路如下
    1. 排查网关里面的转发url 是否使用的ws=> lb:ws://ruoyi-chat
    2. 是否开启了白名单

如果以上都可以了 还是不行,那就是因为他的子模块默认也是需要Token 权限的 我在解决了两天的情况下发现 需要加上以下配置

  1. 在 SecurityConfiguration implements WebMvcConfigurer 文件下面增加 放过
/**
* 校验是否从网关转发
*/
@Beanpublic SaServletFilter getSaServletFilter() {return new SaServletFilter().addInclude("/**").addExclude("/actuator/**").addExclude("/socket/**").setAuth(obj -> SaIdUtil.checkCurrentRequestToken()).setError(e -> SaResult.error("认证失败,无法访问系统资源").setCode(HttpStatus.UNAUTHORIZED));
}

出现的错误提示

WebSocketClientHandshakeException Create breakpoint : Invalid handshake response getStatus: 200 OKAn exception has been observed post termination, use DEBUG level to see the full stack:io.netty . handler . codec . http . websocketx . webSocketClientHandshakeExcept ion: Connection prematurely closed BEFORE opening handshake is complete.

结论:

在子模块中也是需要鉴权的Token 的如果只在网管放开白名单 在子模块也是不行的 所以直接在这个地方加上

import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.id.SaIdUtil;
import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
import cn.dev33.satoken.util.SaResult;
import com.yawei.common.core.constant.HttpStatus;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** 权限安全配置** @author Suiquantong*/
@AutoConfiguration
public class SecurityConfiguration implements WebMvcConfigurer {/*** 注册sa-token的拦截器*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注解拦截器registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**");}/*** 校验是否从网关转发*/@Beanpublic SaServletFilter getSaServletFilter() {return new SaServletFilter().addInclude("/**").addExclude("/actuator/**").addExclude("/socket/**").setAuth(obj -> SaIdUtil.checkCurrentRequestToken()).setError(e -> SaResult.error("认证失败,无法访问系统资源").setCode(HttpStatus.UNAUTHORIZED));}}

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【Ctfer训练计划】——(三... 作者名:Demo不是emo  主页面链接:主页传送门 创作初心ÿ...