当前位置: 代码网 > it编程>编程语言>Java > SpringBoot集成websocket作为客户端和服务端的代码案例

SpringBoot集成websocket作为客户端和服务端的代码案例

2024年08月06日 Java 我要评论
Springboot整合websocket作为服务端和客户端案例

websocket介绍:

websocket是一种在单个tcp连接上进行全双工通信的协议,允许服务端和客户端之间进行实时、双向的数据传输。

  • 长连接:websocket建立连接后,只要不关闭,会一直保持连接状态,使得服务器可以主动向客户端推送数据。
  • 双向通信:与http请求-响应模式不同,websocket支持双向通信,即客户端和服务端都可以发送或接收数据。

使用场景:

在需要实时交互的场景中使用,例如聊天应用,实时数据推送,内容流式输出等。可实现实时向客户端进行数据推送。

1、springboot集成websocket作为服务端

在前后端分离的项目中,前端作为websocket的客户端,后端服务作为websocket的服务端。

实现步骤:

  1. 添加websocket整合包

    <dependency>
        <groupid>org.springframework.boot</groupid>
        <artifactid>spring-boot-starter-websocket</artifactid>
    </dependency>
    
  2. 编写websocket配置类,暴露websocket

    @configuration
    public class websocketconfig {
    
        @bean
        public serverendpointexporter serverendpointexporter() {
            return new serverendpointexporter();
        }
    
    }
    
  3. 编写websocket服务监听程序及处理逻辑

    package com.houdehong.wsserver.controller;
    
    import lombok.extern.slf4j.slf4j;
    import org.springframework.stereotype.component;
    import javax.websocket.*;
    import javax.websocket.server.pathparam;
    import javax.websocket.server.serverendpoint;
    import java.io.ioexception;
    import java.util.concurrent.concurrenthashmap;
    
    /**
     * @author houdehong
     * @date 2024/3/21 14:16
     * @description
     **/
    @component
    @serverendpoint("/api/ws/{sid}")
    @slf4j
    public class websocketserver {
    
        private string sid;
    
        private static final concurrenthashmap<string, session> session_map = new concurrenthashmap<>();
    
        /**
         * 连接成功
         */
        @onopen
        public void onopen(session session, @pathparam("sid") string sid) {
            this.sid = sid;
            session_map.put(sid, session);
            log.info("有新连接:sid:{},sessionid:{},当前连接数:{}", sid, session.getid(), session_map.size());
        }
    
        /**
         * 连接关闭
         */
        @onclose
        public void onclose(session session) {
            session_map.remove(this.sid);
            log.info("连接关闭,sid:{},session id:{}!当前连接数:{}", this.sid, session.getid(), session_map.size());
        }
    
        /**
         * 收到消息
         */
        @onmessage
        public void onmessage(string message, session session) {
            log.info("收到消息:{},内容:{}", sid, message);
            if("ping".equals(message)){
                try {
                    session.getbasicremote().sendtext("pong");
                } catch (ioexception e) {
                    log.error("onmessage 推送消息失败:{},内容:{}", sid, message);
                }
            }else{
                // 排除自己
               // sendmeasuredatainfoexcludeself(message, sid);
                // 发给所有客户端包括自己
                sendmeasuredatainfo(message);
            }
        }
    
    
        /**
         * 连接错误
         */
        @onerror
        public void onerror(session session, throwable error) {
            log.error("{} 发生错误", session.getid(), error);
        }
    
        /**
         * 群发消息
         */
        public void sendmeasuredatainfo(string message) {
            for (string sid : session_map.keyset()) {
                session session = session_map.get(sid);
                try {
                    session.getbasicremote().sendtext(message);
                } catch (ioexception e) {
                    log.error("推送消息失败:{},内容:{}", sid, message);
                }
                log.info("推送消息:{},内容:{}", sid, message);
            }
        }
    
        /**
         * 群发消息,排除消息发起者
         * @param message
         * @param sidself
         */
        private void sendmeasuredatainfoexcludeself(string message, string sidself){
            for(string sid : session_map.keyset()){
                if(sidself.equals(sid)){
                    continue;
                }
                session session = session_map.get(sid);
                try {
                    session.getbasicremote().sendtext(message);
                } catch (ioexception e) {
                    log.error("sendmeasuredatainfoexcludeself 推送消息失败:{},内容:{}", sid, message);
                }
                log.info("sendmeasuredatainfoexcludeself 推送消息:{},内容:{}", sid, message);
            }
        }
    }
    
    
  4. 测试

    至此,springboot整合websocket作为服务就搭建完成了,我们可以随便百度打开一个在线的websocket测试工具,请求一下试试,请求地址是ws://ip:port/api/ws/{sid}, 其中sid可以随便指定一个字符串,这里的sid主要是用来区分客户端,实际场景下可以在前端生成全局唯一的标识。

    图片:
    在这里插入图片描述控制台打印信息:
    在这里插入图片描述

2、springboot集成websocket作为客户端

有时,我们需要调用第三方的websocket服务,然后将接收到的数据处理之后,或持久化到数据库,或是需要解析数据重新封装为前端需要的数据结构,这个时候我们就需要作为客户端来进行使用。

实现步骤:

  1. 添加springboot服务作为客户端的依赖

    <dependency>
        <groupid>org.java-websocket</groupid>
        <artifactid>java-websocket</artifactid>
        <version>1.3.8</version>
    </dependency>
    
  2. 继承websocketclient,重写方法,加入自己的逻辑

    @slf4j
    public class mywebsocketclient extends websocketclient {
    
        public mywebsocketclient(uri serveruri) {
            super(serveruri);
        }
    
        @override
        public void onopen(serverhandshake arg0) {
            log.info("------ websocketclient onopen ------");
        }
    
        @override
        public void onclose(int arg0, string arg1, boolean arg2) {
            log.info("------ websocket onclose ------{}",arg1);
        }
    
        @override
        public void onerror(exception arg0) {
            log.error("------ websocket onerror ------{}",arg0);
        }
    
        @override
        public void onmessage(string response) {
            log.info("-------- 接收到服务端数据: " + response + "--------");
        }
    
    }
    
  3. 获取websocketclient实例

    在这里我写的wsserverurl即为上面websocket作为服务端的地址

    @component
    public class websocketclientconfigurer {
    
        private final string wsserverurl = "ws://127.0.0.1:8081/api/ws/123wer";
    
        @bean
        public websocketclient websocketclient() {
            try {
                mywebsocketclient websocketclient =
                        new mywebsocketclient(new uri(wsserverurl));
                websocketclient.connect();
                return websocketclient;
            } catch (urisyntaxexception e) {
                e.printstacktrace();
            }
            return null;
        }
    
    }
    
  4. 为了好演示我加了一个controller来进行调用

    @restcontroller
    @requestmapping("ws-client")
    public class websocketclient {
    
        @resource
        private mywebsocketclient websocketclient;
    
        @getmapping("send/{message}")
        public void sendrequest(@pathvariable string message){
            websocketclient.send(message);
        }
    }
    

3. 测试

至此,我们已经搭好了一个websocket的服务器和一个websocket的客户端,我们可以同时把这两个服务跑起来,做一个调用。
注意:需要先启动服务端,再启动客户端,客户端会无法创建连接,报空指针异常。
服务端启动:
在这里插入图片描述客户端启动:
在这里插入图片描述现在我们向客户端的controller请求一个消息:
你可以用postman或者其他api工具,我现在图简单直接在浏览器发起:

在这里插入图片描述客户端控制台日志:

在这里插入图片描述服务端控制台日志:
在这里插入图片描述ok,大功告成。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com