springboot整合websocket,超简单入门

news2024/11/28 1:31:25

springBoot整合webSocket,超简单入门

webSocket简洁

WebSocket 是一种基于 TCP 协议的全双工通信协议,它允许客户端和服务器之间建立持久的、双向的通信连接。相比传统的 HTTP 请求 - 响应模式,WebSocket 提供了实时、低延迟的数据传输能力。通过 WebSocket,客户端和服务器可以在任意时间点互相发送消息,实现实时更新和即时通信的功能。WebSocket 协议经过了多个浏览器和服务器的支持,成为了现代 Web 应用中常用的通信协议之一。它广泛应用于聊天应用、实时数据更新、多人游戏等场景,为 Web 应用提供了更好的用户体验和更高效的数据传输方式。

1、导包

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

2、写配置类

@Configuration
public class WebSocketConfig {
    /**
     * 	注入ServerEndpointExporter,
     * 	这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
    
}

3、创建ServerEndpoint 端点

服务端 WebSocket 端点的开发也有 2 种方式。第 1 种是实现规范所提供的各种接口,通过接口定义的回调方法来处理新的连接、客户端消息、连接断开等等事件。另一种方式是使用注解,类似于 Spring 中的 Controller,通过在方法上使用不同的注解来监听不同的 WebSocket 事件,灵活性比较高,推荐使用。

@Component
@Slf4j
@ServerEndpoint("/websocket/{userId}")  // 接口路径 ws://localhost:8080/websocket/userId;
public class WebSocket {

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

    // concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
    // 虽然@Component默认是单例模式的,但springboot还是会为每个websocket连接初始化一个bean,所以可以用一个静态set保存起来。
    //  注:底下WebSocket是当前类名
    private static final CopyOnWriteArraySet<WebSocket> webSockets = new CopyOnWriteArraySet<>();
    // 用来存在线连接用户信息
    private static final ConcurrentHashMap<String, Session> sessionPool = new ConcurrentHashMap<>();

    /**
     * 链接成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "userId") String userId) {
        try {
            this.session = session;
            this.userId = userId;
            webSockets.add(this);
            sessionPool.put(userId, session);
            log.info("【websocket消息】有新的连接,总数为:" + webSockets.size());
        } catch (Exception e) {
            log.error("onOpen 报错", e);
        }
    }

    /**
     * 链接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        try {
            webSockets.remove(this);
            sessionPool.remove(this.userId);
            log.info("【websocket消息】连接断开,总数为:" + webSockets.size());
        } catch (Exception e) {
            log.error("onOpen 报错", e);
        }
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message
     */
    @OnMessage
    public void onMessage(String message) {
        log.info("【websocket消息】收到客户端消息:" + message);
    }

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

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

    // 此为广播消息
    public void sendAllMessage(String message) {
        log.info("【websocket消息】广播消息:" + message);
        for (WebSocket webSocket : webSockets) {
            try {
                if (webSocket.session.isOpen()) {
                    webSocket.session.getAsyncRemote().sendText(message);
                }
            } catch (Exception e) {
                log.error("sendAllMessage 报错", e);
            }
        }
    }

    // 此为单点消息
    public void sendOneMessage(String userId, String message) {
        Session session = sessionPool.get(userId);
        if (session != null && session.isOpen()) {
            try {
                log.info("【websocket消息】 单点消息: 发给用户【{}】:【{}】",userId,message);
                session.getAsyncRemote().sendText(message);
            } catch (Exception e) {
                log.error("sendOneMessage 报错", e);
            }
        }
    }

    // 此为单点消息(多人)
    public void sendMoreMessage(String[] userIds, String message) {
        for (String userId : userIds) {
            Session session = sessionPool.get(userId);
            if (session != null && session.isOpen()) {
                try {
                    log.info("【websocket消息】 单点消息(多人): 发给用户【{}】:【{}】",userId,message);
                    session.getAsyncRemote().sendText(message);
                } catch (Exception e) {
                    log.error("sendMoreMessage 报错", e);
                }
            }
        }

    }
}

4、写controller用于模仿数据刷新

@RestController
@Slf4j
@RequestMapping("web")
public class WebSocketTestController {

    @Resource
    private WebSocket webSocket;

    // 模仿其他的服务调用webSocket进行数据刷新
    @PostMapping("/test")
    public Results test(@RequestBody TestDto dto) {
        log.info("test 入参 dto:{}",dto);
        try {
            // 数据返回
            JSONObject obj = new JSONObject();
            obj.put("audience",Math.random() * 100);
            obj.put("msg",dto.getMsg());
            // 全体发送 自己去测
//        webSocket.sendAllMessage(obj.toJSONString());
            if (StringUtils.isNotBlank(dto.getUserId())){
                // 单个用户发送 (userId为用户id)
                webSocket.sendOneMessage(dto.getUserId(), obj.toJSONString());
            }
            if (dto.getUserIds() != null && dto.getUserIds().length > 0){
                // 多个用户发送 (userIds为多个用户id)
                webSocket.sendMoreMessage(dto.getUserIds(), obj.toJSONString());
            }
            return Results.success();
        } catch (Exception e) {
            log.error("test 报错",e);
            return Results.failed();
        }
    }
}
// 偷个懒
@Data
class TestDto{
    private String userId;
    private String[] userIds;
    private String msg;
}

5、测试

使用测试网站:WebSocket在线测试工具 (wstool.js.org)

创建三个用户

在这里插入图片描述

开启连接

在这里插入图片描述

查看日志

在这里插入图片描述

使用postman用于测试

在这里插入图片描述

5.1、测试只要123收到消息

发送:

{
    "userId":"123",
    "userIds":[
    ],
    "msg":"are you ok ?"
}

在这里插入图片描述

5.2、测试456、789收到消息

发送:

{
    "userId":"",
    "userIds":[
        "456",
        "789"
    ],
    "msg":"6666"
}

在这里插入图片描述

查看日志

在这里插入图片描述

感谢:springboot整合webSocket

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1659384.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【JavaEE】博客系统(前端页面设计)

文章目录 一、预期效果二、实现博客列表页 一、预期效果 二、实现博客列表页 实现导航栏 编辑 blog_list.html, 创建导航栏的 html 代码. 导航栏里面包含 logo, 标题, 以及一些按钮(跳转链接). 为了实现左右排列, 在 logo 和 按钮 之间加一个 spacer 作为占位器. <!-- 导航…

FPGA采集卡,可实现CVBS/HDMI/SDI三种信号转换

可实现CVBS/HDMI/SDI三种信号转换&#xff0c; 客户应用:电视台&#xff0c;舞台&#xff0c;会议室 主要性能: 1:标准CVBS信号输入,标准HDMI信号输入,标准SDI信号输入,输入信号自适应. 2:3G/HD/SDSDI信号输出可选 2:1080P/10801/720P/4801/5761常用分辩率可选 1080PSF/720P30/…

SSC369G 双4K高性价比AI IPC方案

一、方案描述 SSC369G 双4K高性价比AI IPC方案采用主芯片SSC369G&#xff0c;内核为CA55四核最高主频为1.5Ghz处理器。SOC内置集成一个64位的四核RISC处理器&#xff0c;先进的图像信号处理器&#xff08;ISP&#xff09;&#xff0c;高性能的H.265/H.264/MJPEG视频编解码器&a…

LeetCode-2960. 统计已测试设备【数组 模拟】

LeetCode-2960. 统计已测试设备【数组 模拟】 题目描述&#xff1a;解题思路一&#xff1a;模拟解题思路二&#xff1a; 一次遍历&#xff0c;简洁写法解题思路三&#xff1a;0 题目描述&#xff1a; 给你一个长度为 n 、下标从 0 开始的整数数组 batteryPercentages &#xf…

多模态大模型通过外接数据方案实现电力智能巡检(设计方案)

大模型相关目录 大模型&#xff0c;包括部署微调prompt/Agent应用开发、知识库增强、数据库增强、知识图谱增强、自然语言处理、多模态等大模型应用开发内容 从0起步&#xff0c;扬帆起航。 大模型应用向开发路径&#xff1a;AI代理工作流大模型应用开发实用开源项目汇总大模…

深度主动学习(Deep Active Learning)——基于pytorch和ALipy工具包实现双向GRU模型

前言 在ALipy的官网说ALipy只支持sklearn和tensorflow模型&#xff0c;模型对象应符合 scikit-learn api。 但是alipy提供了ToolBox的工具箱&#xff0c;里面包装了多种查询策略&#xff0c;计算指标等工具&#xff0c;几乎具有Alipy的全部功能&#xff0c;虽然不能使用ALipy提…

BLIP2预研笔记

0. 前言 文章是公司内部分享学习写的预研报告&#xff0c;里面有小部分文段是直接从网上借鉴的&#xff0c;侵删 1. 任务和方法历史进化&#xff1a; 在大模型等类似的预训练模型的方式&#xff08;以包含“预训练阶段”等n阶段训练方式为特色&#xff09;为主流之前&#xf…

太牛了!360大佬编写的《应急响应指导手册》火了!(PDF限时3天领取)

免责声明&#xff1a; 请使用者遵守《中华人民共和国网络安全法》&#xff0c;由于传播、利用本账号所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;公众号及作者不为此承担任何责任。 简介 这份《应急响应指导手册》&#xf…

【NPS】微软NPS配置802.1x,验证域账号,动态分配VLAN(NPS篇)

NPS简介 Network Policy Server&#xff08;NPS&#xff09;是微软Windows Server中的一个网络服务&#xff0c;它作为RADIUS服务器实现&#xff0c;用于集中管理网络接入请求。NPS处理对网络资源的认证、授权和审计请求&#xff0c;通常用于控制远程访问VPN和无线网络的接入。…

网络隔离状态下,如何可以安全高效地进行研发文件外发?

研发部门的数据传输通常需要保证数据的安全性、完整性和保密性&#xff0c;尤其是当涉及到公司的核心技术、产品设计、源代码等重要信息时。研发文件外发&#xff0c;即研发资料的外部传输&#xff0c;通常涉及到公司的核心技术和商业机密&#xff0c;因此需要采取严格的安全措…

【日常开发之FTP】Windows开启FTP、Java实现FTP文件上传下载

【日常开发之FTP】windows开启FTP、Java实现FTP文件上传下载 FTP前言FTP是什么&#xff1f;FTP两种模式 Windows开启FTPFTP windows 配置防火墙配置 Java部分Maven配置创建FTPClient 注意 FTP前言 FTP是什么&#xff1f; FTP是一个专门进行文件管理的操作服务&#xff0c;一般…

java后端15问!

前言 最近一位粉丝去面试一个中厂&#xff0c;Java后端。他说&#xff0c;好几道题答不上来&#xff0c;于是我帮忙整理了一波答案 G1收集器JVM内存划分对象进入老年代标志你在项目中用到的是哪种收集器&#xff0c;怎么调优的new对象的内存分布局部变量的内存分布Synchroniz…

【0day漏洞复现】中移铁通禹路由器信息泄露漏洞

0x01 阅读须知 “如棠安全的技术文章仅供参考&#xff0c;此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等&#xff08;包括但不限于&#xff09;进行检测或维护参考&#xff0c;未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供…

移动端自动化测试工具 Appium 之 main 启动

文章目录 一、背景二、生成xml文件2.1、创建xml方法2.2、执行主类MainTest2.3、自动生成的xml2.4、工程目录2.5、执行结果 三、命令行执行appium服务四、主方法启动类五、集成Jenkins六、总结 一、背景 Jenkins 做集成测试是不错的工具&#xff0c;那么UI自动化是否可以&#…

两种方法合并3dtiles(分别使用js/java)

目录 前言&#xff1a; 需合并的json目录 aa/tileset.json bb/tileset.json cc/tileset.json dd/tileset.json ee/tileset.json js源码&#xff1a; 运行命令&#xff1a; 生成结果&#xff1a; java源码&#xff1a; Matrix.java ThreeDTilesJoin2.java pom文件…

Rust 适合哪些场景?

目录 二、Rust 适合哪些场景&#xff1f; 三、Rust 社区的发展趋势如何&#xff1f; 四、Rust 快速搭建一个WebServer服务器 一、Rust是什么&#xff1f; Rust是一门赋予每个人构建可靠且高效软件能力的语言。 Rust 程序设计语言 一门帮助每个人构建可靠且高效软件的语言。…

2024年美国市场亚太游戏品牌数字广告洞察报告

来源&#xff1a;Sensor Tower 美国是全球最大的游戏市场之一&#xff0c;也是亚太游戏品牌出海的重要市场。2023年Q2至2024年Q1&#xff0c;美国市​场广告投放额排名前10的亚太游戏品牌&#xff0c;合计支出 超过7.5亿美元&#xff0c;环比上涨23%。 排名第一的米哈游(miHoY…

【将Maven源改为国内阿里云镜像源】

目录 一、如何配置Maven镜像源&#xff1f; 二、Idea中的Maven配置 ​三、项目与你本地仓库和中央仓库的联系 一、如何配置Maven镜像源&#xff1f; 1、打开你的Maven用户设置文件(settings.xml)。默认情况下&#xff0c;该文件存在于你的用户目录下的.m2文件夹中。如果你没…

内网安全-隧道技术SSHDNSICMPSMB上线通讯LinuxMac 简单总结

第126天&#xff1a;内网安全-隧道技术&SSH&DNS&ICMP&SMB&上线通讯Linux&Mac_内网安全-隧道技术_ssh_dns_icmp_smb_上线通讯linux_mac-CSDN博客 内网渗透—隧道技术_隧道技术csdn-CSDN博客 #SMB 隧道&通讯&上线 判断&#xff1a;445 通讯 上…

光伏设备制造5G智能工厂数字孪生可视化平台,推进行业数字化转型

光伏设备制造5G智能工厂数字孪生可视化平台&#xff0c;推进行业数字化转型。光伏设备制造5G智能工厂数字孪生可视化平台是光伏行业数字化转型的重要一环。通过数字孪生平台&#xff0c;光伏设备制造企业可以实现对生产过程的全面监控和智能管理&#xff0c;提高生产效率&#…