注:本文档中的ruoyi框架为前后不分离版本,nginx配置与前后分离版有所不同。

一、导pom,版本需与springboot版本一致

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
    <version>2.5.15</version>
</dependency>

 如果是新建module,则需要在ruoyi-admin的pom.xml中导入新建的module,否则注解不生效

<dependency>
    <groupId>com.ruoyi</groupId>
    <!-- 新module的名称 -->
    <artifactId>ruoyi-websocket</artifactId>
</dependency>

二、注册websocket

@Configuration
@EnableWebSocket
public class SpringWebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        System.out.println("注册websocket");
        //固定连接路径则使用/ws,如/ws后还有参数,则追加/*通配符
        registry.addHandler(new MyWebSocketHandler(), "/ws/*")//设置连接路径和处理器
                .setAllowedOrigins("*") //允许跨域访问
                .addInterceptors(new MyWebSocketInterceptor());//设置拦截器
    }
}

三、创建拦截器 MyWebSocketInterceptor

public class MyWebSocketInterceptor implements HandshakeInterceptor {
    @Override
    public boolean beforeHandshake(ServerHttpRequest servletRequest, ServerHttpResponse servletResponse, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
        System.out.println("websocket前置拦截");

        //如果用到Sec-WebSocket-Protocol,可以采用getHeaders().get(key)的方法获取
        if (servletRequest.getHeaders().get("Sec-WebSocket-Protocol") == null) {
            System.out.println("无Sec-WebSocket-Protocol,进行拦截!");
            return false;
        }
        String protocol = servletRequest.getHeaders().get("Sec-WebSocket-Protocol").get(0);

        //如果uri的路径中带有参数,可获取到uri字符串,采用截取的方式处理,最后存入attributes
        String path = servletRequest.getURI().getPath();
        String id = path.substring(path.lastIndexOf('/') + 1);
        attributes.put("id", id);
        System.out.println("设备id:" + id);

        return true;
    }

    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
        System.out.println("websocket后置拦截");
    }
}

四、创建处理器 MyWebSocketHandler

public class MyWebSocketHandler implements WebSocketHandler {

    //建立新的 socket 连接后回调的方法
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("新连接");
        //从session中获取存放的参数
        session.getAttributes().get("id");
    }

    // 接收客户端发送的 Socket
    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        // 连接发送的消息
        String msg = message.getPayload().toString();
        // 通过session向连接发送消息
        session.sendMessage(new TextMessage("发送消息"));
    }

    //连接出错时,回调的方法
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        System.out.println("收到的错误信息:" + exception);
    }

    //连接关闭时,回调的方法
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        System.out.println("断开连接");
    }


    // WebSocketHandler 是否处理部分消息 默认返回false即可
    @Override
    public boolean supportsPartialMessages() {
        return false;
    }

}

五、本地启动项目

六、本地环境测试,或者使用在线测试  http://www.websocket-test.com/ 

<!DOCTYPE HTML>
<html>
<head>
    <title>My WebSocket</title>
</head>

<body>
<input id="text" type="text" />
<button onclick="send()">Send</button>
<button onclick="closeWebSocket()">Close</button>
<div id="message"></div>


</body>

<script type="text/javascript">

    let ws = null;
    //判断当前浏览器是否支持WebSocket
    if ('WebSocket' in window) {
        //【非必须】 在ws后面添加了些内容
        var str = 'abc';
        //【非必须】 Sec-WebSocket-Protocol的内容
        var protocol = ['Sec-WebSocket-Protocol的内容']
        ws = new WebSocket("ws://127.0.0.1:14000/ws/" + str, protocol);
    }
    else {
        alert('当前浏览器 Not support websocket')
    }

    //连接发生错误的回调方法
    ws.onerror = function () {
        setMessageInnerHTML("error");
    };

    //连接成功建立的回调方法
    ws.onopen = function(event) {
        setMessageInnerHTML("success");
    }
    //接收到消息的回调方法
    ws.onmessage = function(message) {
        if (typeof(message.data) == 'string') {
            setMessageInnerHTML(message.data);
        }
    }
    //ws连接断开的回调方法
    ws.onclose = function(e) {
        setMessageInnerHTML("close");
    }

    //将消息显示在网页上
    function setMessageInnerHTML(innerHTML) {
        document.getElementById('message').innerHTML +=  innerHTML + '<br/>';
    }

    //关闭连接
    function closeWebSocket() {
        ws.close();
    }


    //发送消息
    function send(msg) {
        if(!msg){
            msg = document.getElementById('text').value;
            document.getElementById('message').innerHTML += "send:" + msg + '<br/>';
            ws.send(msg);
        }
    }
</script>
</html>

 成功连接!

 

七、生产环境需配置nginx (本配置为wss版,需监听443,ws版监听80端口即可)

server {
    listen  443 ssl; 
    #监听的域名地址
    server_name        xxxx.com;
    ssl_certificate      cert/xxxx.com.pem;
    ssl_certificate_key  cert/xxxx.com.key;
    ssl_prefer_server_ciphers  on;
    ssl_protocols                   TLSv1 TLSv1.1 TLSv1.2;
    ssl_session_cache               shared:SSL:10m;
    ssl_session_timeout             10m;
    ssl_ciphers ALL:!kEDH!ADH:RC4+RSA:+HIGH:+EXP;

    #监听的路径,对应第二步中的连接路径
    location /ws/ {
      proxy_pass        http://127.0.0.1:14000;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
    }

    # 不添加,则会导致后台管理页面无法登录
    location / {  
      #这里是反向代理的地址,我用的是tomcat默认的8080端口
      proxy_pass http://localhost:14000/login;  
      proxy_set_header Host $host;  
      proxy_set_header X-Real-IP $remote_addr;  
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_connect_timeout 1; 
      proxy_send_timeout 200; 
      proxy_read_timeout 200;
    }  
  }

Logo

快速构建 Web 应用程序

更多推荐