首页 > 编程语言 >java服务端如何接入WebSocket?

java服务端如何接入WebSocket?

时间:2023-05-30 15:33:00浏览次数:53  
标签:WebSocket String java userId session websocket message public 服务端

日常工作中,我们都是使用http请求,来进行前后交互,那么我们也会有使用websocket来进行前后交互的时候,那么它俩有什么区别呢?

http和websocket区别

  1. WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息
  2. HTTP是单向的
  3. WebSocket是需要浏览器和服务器握手进行建立连接的
  4. 而http是浏览器发起向服务器的连接,服务器预先并不知道这个连接

根据它的特点就可以知道,如果场景中需要服务端向客户端推送消息,那么使用http就是不行的。所以今天就用spring boot 来接入 WebSocket。

代码实现

1、首先,我们需要在pom文件内引入它的jar包依赖,如下:

<!--websocket作为服务端-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

这个时候我们就可以直接利用该第三方的API直接代码实现了。

新增websocket配置类

因为项目中有http请求,也有websocket请求,那么该怎么去区分请求连接的类型呢?这个时候我们需要增加一个websocket的配置类,来进行拦截websocket的请求。

@Configuration
public class WebSocketConfig {

    /**
     * 注入ServerEndpointExporter,
     * 这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
     */

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

注意:不要忘记添加 @Configuration 注解,这个类,会自动拦截websocket请求。

完整代码

@Component
@Slf4j
@ServerEndpoint("/websocket/{userId}")
public class WebSocketHandler {
    // 接口路径 ws://127.0.0.1:9000/websocket/userId;
    private Session session;

    //concurrent包的线程安全Set,用来存放每个客户端对应的WebSocket对象。
    private static CopyOnWriteArraySet<WebSocketHandler> webSocketUtils = new CopyOnWriteArraySet<>();
    // 用来存在线连接数
    private static Map<String, Session> sessionPool = new HashMap<>();

    /**
     * 链接成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "userId") String userId) {
        try {
            this.session = session;
            webSocketUtils.add(this);
            sessionPool.put(userId, session);
            sendOneMessage(userId, "连接成功");
            //加入队列
            QueueUtils.addMap(userId);

            log.info("【websocket消息】有新的连接,总数为:" + webSocketUtils.size());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 链接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        try {
            webSocketUtils.remove(this);
            log.info("【websocket消息】连接断开,总数为:" + webSocketUtils.size());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message
     * @param
     */
    @OnMessage
    public void onMessage(@PathParam(value = "userId") String userId, String message) {

        log.info("【websocket消息】收到客户端消息:" + message);
        if (!StringUtils.isEmpty(userId) && !StringUtils.isEmpty(message) && message.equals("ping")) {
            sendOneMessage(userId, "pong");
        } else {
            //1、轮询用户数最少的服务器IP
            String serverIP = QueueUtils.getServer();
            log.info("serverIP为:" + serverIP);
            //2、调用大模型
            WebSocketClient client = JavaClient.getClient(userId, serverIP);
            if (client != null) {
                JSONObject object = new JSONObject();
                object.put("", message);
                String[][] strings = {{"aaa"}};
                object.put("history", strings);
                object.put("knowledge_base_id", "/home/nemo/aigc/langchain-ChatGLM/vector_store/knowledge_FAISS_20230516_133609");
                //3、发送问题
                client.send(object.toString());

            }
        }
    }

    /**
     * 发送错误时的处理
     *
     * @param session
     * @param error
     */
    @OnError
    public void one rror(Session session, Throwable error) {

        log.error("用户错误,原因:" + error.getMessage());
        error.printStackTrace();
    }


    /**
     * 推消息给前端
     *
     * @param userId
     * @param message
     * @return
     */
    public static Runnable sendOneMessage(String userId, String message) {
        Session session = sessionPool.get(userId);
        if (session != null && session.isOpen()) {
            try {
                log.info("【推给前端消息】 :" + message);

                //高并发下,防止session占用期间,被其他线程调用
                synchronized (session) {
                    session.getBasicRemote().sendText(message);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}

测试

我们可以使用第三方websocket在线测试工具,http://www.jsons.cn/websocket/,连进行测试。

我们可以发送请求连接为:ws://127.0.0.1:9000/websocket/1

然后点击Websocket连接,即客户端可以收到服务端的回应:连接成功。

image.png

标签:WebSocket,String,java,userId,session,websocket,message,public,服务端
From: https://blog.51cto.com/51yeqiu/6379231

相关文章

  • JSON-RPC示例代码(Java实现)
    以下是一个使用Java实现的JSON-RPC示例代码。该示例使用了JSON-RPC2.0规范和Jackson库进行序列化和反序列化。在这个示例中,我们将创建一个服务器和一个客户端,演示如何进行远程过程调用。首先,确保您已经安装了Java开发环境(JDK)和Maven构建工具。接下来,我们将创建一个Maven项目,并......
  • Java8的新特性
    Lambda表达式Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样传递)。使用它可以写出更简洁,更灵活的的代码。作为一种观念更紧凑的代码风格,使Java的语言表达能力得到了提升。//Lambda表达式的使用举例@Testpublicvoidtest1(){ Runnab......
  • ES无法启动_OOM_Exception in thread "main" java.lang.RuntimeException: starting j
    1.报错显示[root@iZ7xv2ya5ap2bnetr231koZ~]#dockerlogsesExceptioninthread"main"java.lang.RuntimeException:startingjavafailedwith[1]output:##ThereisinsufficientmemoryfortheJavaRuntimeEnvironmenttocontinue.#Nativememorya......
  • java编程基础之抽象类
    抽象类观察以下代码有什么问题:Peoplepeople=newpeople("");people.print();结论:实例化people没有意义派派也是一个人,张三、李四等等也是一个人,但是我们在生活当中呢,人是一种分类,并不是单个个体,他是我们抽象出来的,不具体,所以说他没有现实世界当中对应一个人这样的一个人存在,这......
  • 2.6. Java内存管理与垃圾回收
    2.6.1.Java内存模型在Java中,内存被划分为以下几个区域:堆(Heap):存储对象实例和数组,是垃圾回收的主要区域。栈(Stack):存储局部变量和方法调用。每个线程有自己的栈。方法区(MethodArea):存储类信息,如类的结构、方法、字段等。本地方法栈(NativeMethodStack):存储本地方法(如JNI)的调用......
  • 3.4. Java集合框架(List、Set、Map等)
    Java集合框架是Java提供的一套用于存储和操作数据的接口和类。它包括以下几个主要部分:接口:集合框架定义了一系列接口,如Collection、List、Set、Map等。实现类:集合框架提供了一些实现这些接口的类,如ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap等。......
  • Java第五日
    1.多重循环1.代码  2.实战99乘法表 2.break1.语法结构 2.实战 3.continue语法1.语法结构2.实战  4.数组 1.数组定义数组是一个变量,存储相同数据类型的一组数据声明一个变量就是在内存空间划出一块合适的空间声明一个数组就是在内存空间划出一串......
  • Java第六日
    今日继续数组的学习 1.Arrays工具类的使用2.数据应用3.二维数组 1.Arrays工具类的使用Arrays的描述java.util.ArraysSort()升序查询实战录入五位同学的成绩,并进行升序排序然后输出结果 2.数据的应用1.求最大值已知数组存储5位学员成绩,求最大值给max先赋一个......
  • 智能社原生的力量——原生JavaScript开发高级
    智能社原生的力量——原生JavaScript开发高级download:3w51xuebccomSpringBoot3:打造高效的Java应用程序SpringBoot是一个由Pivotal团队开发的开源框架,它基于Spring框架,旨在使Spring应用程序的开发变得更加容易和快速。最新的SpringBoot版本是3.0.0,它带来了许多新特性和功能,让我......
  • Linux(Ubuntu)下设置开机自启shell脚本执行Java程序jar包
    Linux(Ubuntu)下设置开机自启shell脚本执行Java程序jar包 原创软件测试日常记录2023-01-1907:19:29博主文章分类:ubuntu©著作权文章标签ubuntujarlinuxJAVAjava文章分类运维阅读数122 经常需要在Linux服务器上设置开机启动jar包,首先编写一个启动jar包的脚本,这里以/......