草庐IT

RuoYi-Cloud-Plus集成 WebSocket

夏笙 2023-04-10 原文

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

  1. 添加websocket 依赖
 <!--添加websockert依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-websocket</artifactId><exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </exclusion>
    </exclusions>
  1. 添加配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
    public class WebSocketConfig {

        @Bean
        public 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对象。
    @JsonBackReference
    private static Map<String, WebSocketService> webSocketMap = new ConcurrentHashMap<>();

    /**
     * 与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    private Session session;
    /**
     * 接收userName
     */
    private String userName = "";

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public 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));
    }


    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(@PathParam("userName") String userName) {
        if (webSocketMap.containsKey(userName)) {
            webSocketMap.remove(userName);
        }
        System.err.println("----------------------------------------------------------------------------");
        System.err.println(userName + "用户退出,当前在线人数为:" + webSocketMap.size());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        System.err.println("收到用户消息:" + userName + ",报文:" + message);
        //可以群发消息
        //消息保存到数据库、redis
        if (message != null) System.err.println("");
    }

    /**
     * 连接失败调用方法
     * @param session
     * @param error
     */
    @OnError
    public 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();
        }
    }



    /**
     * 向指定客户端发送消息
     * <p>
     * // * @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<String, WebSocketService> getWebSocketMap() {
        return webSocketMap;
    }

    public static void setWebSocketMap(Map<String, WebSocketService> 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/xx
  filters:
    - StripPrefix=1

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

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

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

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

  1. 在 SecurityConfiguration implements WebMvcConfigurer 文件下面增加 放过
/**
* 校验是否从网关转发
*/
@Bean
    public 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 OK

An 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的拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注解拦截器
        registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**");
    }

    /**
     * 校验是否从网关转发
     */
    @Bean
    public SaServletFilter getSaServletFilter() {
        return new SaServletFilter()
            .addInclude("/**")
            .addExclude("/actuator/**")
            .addExclude("/socket/**")
            .setAuth(obj -> SaIdUtil.checkCurrentRequestToken())
            .setError(e -> SaResult.error("认证失败,无法访问系统资源").setCode(HttpStatus.UNAUTHORIZED));
    }

}

有关RuoYi-Cloud-Plus集成 WebSocket的更多相关文章

  1. ruby-on-rails - 如何使辅助方法在 Rails 集成测试中可用? - 2

    我在app/helpers/sessions_helper.rb中有一个帮助程序文件,其中包含一个方法my_preference,它返回当前登录用户的首选项。我想在集成测试中访问该方法。例如,这样我就可以在测试中使用getuser_path(my_preference)。在其他帖子中,我读到这可以通过在测试文件中包含requiresessions_helper来实现,但我仍然收到错误NameError:undefinedlocalvariableormethod'my_preference'.我做错了什么?require'test_helper'require'sessions_hel

  2. ruby-on-rails - 我如何将 Hoptoad 与 DelayedJob 和 DaemonSpawn 集成? - 2

    我一直很高兴地使用DelayedJob习惯用法:foo.send_later(:bar)这会调用DelayedJob进程中对象foo的方法bar。我一直在使用DaemonSpawn在我的服务器上启动DelayedJob进程。但是...如果foo抛出异常,Hoptoad不会捕获它。这是任何这些包中的错误...还是我需要更改某些配置...或者我是否需要在DS或DJ中插入一些异常处理来调用Hoptoad通知程序?回应下面的第一条评论。classDelayedJobWorker 最佳答案 尝试monkeypatchingDelayed::W

  3. jenkins部署1--jenkins+gitee持续集成 - 2

    前置步骤我们都操作完了,这篇开始介绍jenkins的集成。话不多说,看操作1、登录进入jenkins后会让你选择安装插件,选择第一个默认的就行。安装完成后设置账号密码,重新登录。2、配置JDK和Git都需要执行路径,所以需要先把执行路径找到,先进入服务器的docker容器,2.1JDK的路径root@69eef9ee86cf:/usr/bin#echo$JAVA_HOME/usr/local/openjdk-82.2Git的路径root@69eef9ee86cf:/#whichgit/usr/bin/git3、先配置JDK和Git。点击:ManageJenkins>>GlobalToolCon

  4. ruby - Faye WebSocket,关闭处理程序被触发后重新连接到套接字 - 2

    我有一个super简单的脚本,它几乎包含了FayeWebSocketGitHub页面上用于处理关闭连接的内容:ws=Faye::WebSocket::Client.new(url,nil,:headers=>headers)ws.on:opendo|event|p[:open]#sendpingcommand#sendtestcommand#ws.send({command:'test'}.to_json)endws.on:messagedo|event|#hereistheentrypointfordatacomingfromtheserver.pJSON.parse(event.d

  5. 三分钟集成 TapTap 防沉迷 SDK(Unity 版) - 2

    三分钟集成Tap防沉迷SDK(Unity版)一、SDK介绍基于国家对上线所有游戏必须增加防沉迷功能的政策下,TapTap推出防沉迷SDK,供游戏开发者进行接入;允许未成年用户在周五、六、日以及法定节假日晚上8:00-9:00进行游戏,防沉谜时间段进入游戏会弹窗进行提示!开发环境要求:Unity2019.4或更高版本iOS10或更高版本Android5.0(APIlevel21)或更高版本🔗Unity集成Demo参考链接🔗UnityTapSDK功能体验APK下载链接二、集成前准备1.创建应用进入开发者后台,按照提示开始创建应用;2.开通服务在使用TDS实名认证和防沉迷服务之前,需要在上面创建的应

  6. C/C++好用的websocket库 - 2

    IntrductionLibwebsocketsisasimple-to-use,MIT-license,pureClibraryprovidingclientandserverforhttp/1,http/2,websockets,MQTTandotherprotocolsinasecurity-minded,lightweight,configurable,scalableandflexibleway.It’seasytobuildandcross-buildviacmakeandissuitablefortasksfromembeddedRTOSthroughmasscloudservi

  7. ruby-on-rails - RailsTutorial - 第 8.4.3 章 - 在集成测试中添加用户后未清除测试数据库 - 2

    我被这个难住了。到目前为止教程中的一切都进行得很顺利,但是当我将这段代码添加到我的/spec/requests/users_spec.rb文件中时,事情开始变得糟糕:describe"success"doit"shouldmakeanewuser"dolambdadovisitsignup_pathfill_in"Name",:with=>"ExampleUser"fill_in"Email",:with=>"ryan@example.com"fill_in"Password",:with=>"foobar"fill_in"Confirmation",:with=>"foobar"cl

  8. ruby-on-rails - 将 Angular JS 与 Rails 集成 - 2

    我需要一些指导来了解如何将Angular整合到rails中。选择Rails的原因:我喜欢他们偏执的做事方式。还有迁移,gem真的很酷。使用angular的原因:我正在研究和寻找最适合SPA的框架。Backbone似乎太抽象了。我不得不在Angular和Ember之间做出选择。我首先开始阅读Angular,它对我来说很有意义。所以我从来没有去读过关于ember的文章。使用Angular和Rails的原因:我研究并尝试使用小型框架,例如grape、slim(是的,我也使用php)。但我觉得需要坚持项目的长期范围。我个人喜欢用Rails的方式做事。这就是我需要帮助的地方,我在Rails4中有

  9. ruby - 在 Maven 集成中运行 Ruby 单元测试 - 2

    有没有人有在Maven中运行用Ruby编写的单元测试的经验。任何输入,如要使用的库/maven插件,将不胜感激!我们已经在使用Maven+hudson+Junit。但是我们正在引入Ruby单元测试,找不到任何同样好的组合。 最佳答案 我建议让Maven使用ExecMavenPlugin启动rake测试(exec:exec目标)并使用ci_reportergem生成单元测试结果的XML文件,Hudson、Bamboo等可以读取该文件,以与JUnit测试相同的格式显示测试结果。如果您不需要使用mvntest运行Ruby测试,您也可以只使

  10. ruby-on-rails - Websocket-rails 不适用于 Nginx 和 Unicorn 的生产环境 - 2

    我有带有gemwebsocket-rails0.7的Rails3.2应用程序。在开发机上,一切正常在生产环境中,我使用Nginx/1.6作为代理服务器,Unicorn作为http服务器。Thin用于独立模式(在https://github.com/websocket-rails/websocket-rails/wiki/Standalone-Server-Mode之后)。nginx配置:location/websocket{proxy_passhttp://localhost:3001/websocket;proxy_http_version1.1;proxy_set_headerUp

随机推荐