首页 > 其他分享 >在SpringBoot中使用WebSocket

在SpringBoot中使用WebSocket

时间:2023-08-28 10:35:18浏览次数:31  
标签:WebSocket uid param String session 使用 message 客户端 SpringBoot

一、概述

  最近在SpringBoot中用到了WebSocket的功能,在此记录一下使用步骤。SpringBoot使用WebSocket还是比较简单的,只需要4步就行了。如下

二、使用步骤

  第一步:

    在pom.xml文件中导入坐标

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

  第二步:

    在入口类上加上@EnableWebSocket注解,表明项目中要使用WebSocket功能

@SpringBootApplication
@EnableWebSocket
public class DemoApplication {

  第三步:

    新建一个WebSocket配置类

/**
 * WebSocket配置类
 */
@Configuration
public class WSConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

  第四步:

    新建WebSocketServer类使用具体的WebSocket功能,此类负责消息的接收以及转发功能

/**
 * WebSocketServer服务端
 */
@Slf4j
@Component
@ServerEndpoint("/websocket/{uid}")
public class WebSocketServer {
    /**
     * 静态变量,用来记录当前在线连接数,线程安全的类。
     */
    private static AtomicInteger onlineSessionClientCount = new AtomicInteger(0);
    /**
     * 存放所有在线的客户端
     */
    private static Map<String, Session> onlineSessionClientMap = new ConcurrentHashMap<>();

    /**
     * 连接uid和连接会话
     */
    private String uid;
    private Session session;


    /**
     * 连接建立成功调用的方法。由前端<code>new WebSocket</code>触发
     *
     * @param uid     每次页面建立连接时传入到服务端的id,比如用户id等。可以自定义。
     * @param session 与某个客户端的连接会话,需要通过它来给客户端发送消息
     */
    @OnOpen
    public void onOpen(@PathParam("uid") String uid, Session session) {
        /**
         * session.getId():当前session会话会自动生成一个id,从0开始累加的。
         */
        log.info("连接建立中 ==> session_id = {}, sid = {}", session.getId(), uid);
        //加入 Map中。将页面的uid和session绑定或者session.getId()与session
        //onlineSessionIdClientMap.put(session.getId(), session);
        onlineSessionClientMap.put(uid, session);
        //在线数加1
        onlineSessionClientCount.incrementAndGet();
        this.uid = uid;
        this.session = session;
//        sendToOne(uid, "连接成功");
        log.info("连接建立成功,当前在线数为:{} ==> 开始监听新连接:session_id = {}, sid = {},。", onlineSessionClientCount, session.getId(), uid);
    }

    /**
     * 连接关闭调用的方法。由前端<code>socket.close()</code>触发
     *
     * @param uid
     * @param session
     */
    @OnClose
    public void onClose(@PathParam("uid") String uid, Session session) {
        //onlineSessionIdClientMap.remove(session.getId());
        // 从 Map中移除
        onlineSessionClientMap.remove(uid);

        //在线数减1
        onlineSessionClientCount.decrementAndGet();
        log.info("连接关闭成功,当前在线数为:{} ==> 关闭该连接信息:session_id = {}, sid = {},。", onlineSessionClientCount, session.getId(), uid);
    }

    /**
     * 收到客户端消息后调用的方法。由前端<code>socket.send</code>触发
     * * 当服务端执行toSession.getAsyncRemote().sendText(xxx)后,前端的socket.onmessage得到监听。
     *
     * @param message
     * @param session
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        /**
         * html界面传递来得数据格式,可以自定义.
         * {"sid":"user-1","message":"hello websocket"}
         */
        log.info("接收到消息-----------------"+message);
        //A发送消息给B,服务端收到A的消息后,从A的消息体中拿到B的uid及携带的手机号。查找B是否在线,如果B在线,则使用B的session发消息给B自己
        Message msgObj = JsonUtils.getObject(message, Message.class);
        String toSid = msgObj.getUid();
        String msg = msgObj.getMessage();
        String phone = msgObj.getPhone();
        //A给B发送消息,A要知道B的信息,发送消息的时候把B的信息携带过来
        log.info("服务端收到客户端消息 ==> fromSid = {}, toSid = {}, message = {}", uid, toSid, message);
        sendToOne(phone, message);
    }

    /**
     * 发生错误调用的方法
     *
     * @param session
     * @param error
     */
    @OnError
    public void one rror(Session session, Throwable error) {
        log.error("WebSocket发生错误,错误信息为:" + error.getMessage());
        error.printStackTrace();
    }

    /**
     * 群发消息
     *
     * @param message 消息
     */
    private void sendToAll(String message) {
        // 遍历在线map集合
        onlineSessionClientMap.forEach((onlineSid, toSession) -> {
            // 排除掉自己
            if (!uid.equalsIgnoreCase(onlineSid)) {
                log.info("服务端给客户端群发消息 ==> sid = {}, toSid = {}, message = {}", uid, onlineSid, message);
                toSession.getAsyncRemote().sendText(message);
            }
        });
    }

    /**
     * 指定发送消息
     *
     * @param toUid
     * @param message
     */
    private void sendToOne(String toUid, String message) {
        /*
         * 判断发送者是否在线
         */
        Session toSession = onlineSessionClientMap.get(toUid);
        if (toSession == null) {
            log.error("服务端给客户端发送消息 ==> toSid = {} 不存在, message = {}", toUid, message);
            return;
        }
        // 异步发送
        log.info("服务端给客户端发送消息 ==> toSid = {}, message = {}", toUid, message);
        toSession.getAsyncRemote().sendText(message);
    }

}

  五、具体的使用步骤

    1.先启动SpringBoot,会自动装载并启动WebSocketServer

    2.onOpen方法达标websocket打开了,onMessage方法中可以接受各个客户端发发送的消息,onClose方法监听客户端关闭,onError方法监听错误消息

    3.客户端通过如下来访问websocket

ws://主机名称:端口/websocket/{uid}来访问(连接websocket)

    这里的端口指的是yml中配置的端口,/websocket/{uid}指的就是WebSocketServer类注解上配置的路径,uid可以是任意值,但最好是用户的唯一标识

  好了,完结,撒花

  

标签:WebSocket,uid,param,String,session,使用,message,客户端,SpringBoot
From: https://www.cnblogs.com/tony-yang-flutter/p/17661570.html

相关文章

  • 使用MySQL命令行新建用户并授予权限的方法
    MySQL命令行能否实现新建用户呢?答案无疑是肯定的。而且在使用使用MySQL命令行新建用户后,还可以为用户授予权限。首先要声明一下:一般情况下,修改MySQL密码,授权,是需要有mysql里的root权限的。注:本操作是在WIN命令提示符下,phpMyAdmin同样适用。用户:phplamp用户数据库:phplampDB1.......
  • HarmonyOS/OpenHarmony(Stage模型)卡片开发应用上下文Context使用场景二
    3.创建其他应用或其他Module的Context基类Context提供创建其他应用或其他Module的Context的方法为createModuleContext(moduleName:string),创建其他应用或者其他Module的Context,从而通过该Context获取相应的资源信息(例如获取其他Module的获取应用开发路径信息)。调用createModuleCon......
  • 不要使用sun.misc.BASE64Encoder
    一直以来Base64的加密解密都是使用sun.misc包下的BASE64Encoder及BASE64Decoder的 这次换了JDK后发现提示找不到该类,网上有办法说重新配置jre就行了,但事实上不是这么简单的,在我测试后发现,这是要看配置的jre的类型是executionenvironment(执行环境),还是alternatejre(替代jre)这两种方......
  • 使用uniapp进入小程序获取链接参数
    两种解决方法第一种:onload里面传参option,直接把option赋值给定义的对象或字段,如下onLoad(option){ //获取小程序进入场景和参数 this.tenendId=option.tenant_id console.log(this.tenendId); },第二种方法:直接在onload里面用getLaunchOptionsS......
  • 使用 Vitest 进行组件测试
    原文:试试使用Vitest进行组件测试,确实很香。参考:Vitest:https://cn.vitest.dev/guide/ui.html什么是Vitest?自从尤大的构建工具Vite获得了巨大的人气,现在有了一个由它驱动的极快的单元测试框架。Vitest。Vitest与Jest兼容,具有开箱即用的ESM、Typescript和JSX支持,并且......
  • 粘贴板工具Ditto(存储粘贴板历史,可以使用快捷键调用,减少重复操作)相关配置
    官方地址:https://ditto-cp.sourceforge.io/一般下载便携版即zip压缩包的版本即可配置:1.更改界面语言右键-options-language-下拉选择Chinesesimple2.快捷键设置-点击"键盘快捷键"选项卡 激活使用默认的ctrl+`即可重点:最后十个项目的快捷键第一个可以不设,因为使......
  • 基于SpringBoot的保险合同管理系统的设计与实现
    现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本可盈保险合同管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达到事......
  • 基于springboot校园失物招领系统
    身处网络时代,随着网络系统体系发展的不断成熟和完善,人们的生活也随之发生了很大的变化,身边经常有同学丢失了东西或者衣服而烦恼,为了找到自己心爱的物品疲于奔命,还不一定能找到,为了满足学生失物招领的要求,校园失物招领系统被开发研究了出来。本文主要描述了该校园失物招领系统的具体......
  • 基于springboot江理工文档管理系统的设计与实现
    课题目的意义江理工学院中的电子文档越来越多,如何有效管理这些电子文档成为了学校的一大难题。学校文档管理存在三个难点:一是文档的共享;二是效率的提升;三是安全性。基于文档管理的这些问题,设计江理工文档管理系统,帮助江理工学院各部门集中管理文档,加强文档访问的控制,提高文档资源......
  • 基于springboot智慧图书管理系统设计与实现
    如今社会上各行各业,都在用属于自己专用的软件来进行工作,互联网发展到这个时候,人们已经发现离不开了互联网。互联网的发展,离不开一些新的技术,而新技术的产生往往是为了解决现有问题而产生的。针对于图书借阅信息管理方面的不规范,容错率低,管理人员处理数据费工费时,采用新开发的智慧图......