Springboot整合WebSocket

目录

 

1.WebSocket 简介

2.WebSocket 实战


 

1.WebSocket 简介

WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。


bbefc8c835344d69939d06856acdb9cd.png

 WebSocket特点:
1.建立在 TCP 协议之上,服务器端的实现比较容易。
2.与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此3.握手时不容易屏蔽,能通过各种HTTP 代理服务器。
4.数据格式比较轻量,性能开销小,通信高效。
5.可以发送文本,也可以发送二进制数据。
6.没有同源限制,客户端可以与任意服务器通信。
7.协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。


HTTP缺点:通过反复的轮训去查看资源是否有更新,对网络和资源有很大的消耗
websocket可以反向通知,双向通讯
 

2.WebSocket 实战

导入依赖

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

配置类

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

WebSocketServer类

@Component
@ServerEndpoint("/websocket/{userId}")
public class WebSocketServer {
    /**
     * 日志工具
     */
    protected static final Logger logger= LoggerFactory.getLogger(WebSocketServer.class);
    /**
     * 与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    private Session session;
    /**
     * 用户id
     */
    private String userId;
    /**
     * 用来存放每个客户端对应的MyWebSocket对象
     */
    private static CopyOnWriteArraySet<WebSocketServer> webSockets = new CopyOnWriteArraySet<>();
    /**
     * 用来存在线连接用户信息
     */
    private static ConcurrentHashMap<String, Session> sessionPool = new ConcurrentHashMap<String, Session>();

    /**
     * 链接成功调用的方法
     */
    @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);
            logger.info("有新的客户连接,总数为:" + webSockets.size());
        } catch (Exception e) {
        }
    }

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

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

    /**
     * 发送错误时的处理
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        logger.info("用户错误,原因:" + error.getMessage());
        error.printStackTrace();
    }

    /**
     * 此为广播消息
     */
    public void sendAllMessage(String message) {
        logger.info("【websocket消息】广播消息:" + message);
        for (WebSocketServer webSocket : webSockets) {
            try {
                if (webSocket.session.isOpen()) {
                    webSocket.session.getAsyncRemote().sendText(message);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 此为单点消息
     */
    public void sendOneMessage(String userId, String message) {
        Session session = sessionPool.get(userId);
        if (session != null && session.isOpen()) {
            try {
                logger.info("【websocket消息】 单点消息:" + message);
                session.getAsyncRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

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

    }
}

服务端发送消息实例

    @GetMapping("/hello")
    public void hello(){
        JSONObject jsonObject=new JSONObject();
        jsonObject.put("key","hello");
        webSocketServer.sendAllMessage(JSONObject.toJSONString(jsonObject));
    }

客户端

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + Vue</title>
  </head>

  <body>
  <p>【socket开启者的ID信息】:<div><input id="userId" name="userId" type="text" value="10"></div>
    <div><input id="contentText" name="contentText" type="text" value="hello websocket"></div>
  <p>【操作】:<button><a onclick="openSocket()">发送消息</a></button>
  </body>

  <script>
    let socket;
    function openSocket() {
      const socketUrl = "ws://localhost:8080/websocket/"+$("#userId").val();
      socket = new WebSocket(socketUrl);
      //打开事件
      socket.onopen = function() {
        console.log("websocket已打开");
        socket.send('{"toUserId":"'+$("#userId").val()+'","contentText":"'+$("#contentText").val()+'"}');
        console.log('{"toUserId":"'+$("#userId").val()+'","contentText":"'+$("#contentText").val()+'"}');
      };
      //获得消息事件
      socket.onmessage = function(msg) {
        console.log(msg.data);
        //发现消息进入,开始处理前端触发逻辑
      };
      //关闭事件
      socket.onclose = function() {
        console.log("websocket已关闭");
      };
      //发生了错误事件
      socket.onerror = function() {
        console.log("websocket发生了错误");
      }

    }
  </script>
</html>

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于html+css的图展示98

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

C++入门

文章目录 &#x1f600;1. 命名空间&#x1f604;1.1 命名空间定义&#x1f604;1.2 命名空间使用 &#x1f60a;2. 输入和输出&#x1f609;3. 缺省参数&#x1fae0;3.1 缺省参数概念&#x1fae0;3.2 缺省参数分类 &#x1f62c;4. 函数重载&#x1f644;4.1 函数重载概念&a…

TypeScript9-声明文件

本篇文章来讲 TypeScript 的声明文件。 当我们在使用第三方库的时候&#xff0c;很多第三方库不是用 TS 写的&#xff0c;它们是通过原生的 JavaScript 或者是浏览器 / 或者是 node 提供的 run time 对象。如果我们直接使用 TS 肯定就会报编译不通过。 1. 声明语句 假设一个…

浅析变电站无人值守管理的模式与特点

安科瑞虞佳豪 近年来&#xff0c;随着电网的发展&#xff0c;变电站实行无人值班管理模式已成为电网的发展方向。自1998年始&#xff0c;辉县市就开始了变电站综合自动化改造&#xff0c;截止目前全局所属24座变电站&#xff08;其中35kV19座、110kV5座&#xff09;已全部实现…

API自动化测试【postman生成报告】

PostMan生成测试报告有两种&#xff1a; 1、控制台的模式 2、HTML的测试报告 使用到一个工具newman Node.js是前端的一个组件&#xff0c;主要可以使用它来开发异步的程序。 一、控制台的模式 1、安装node.js 双击node.js进行安装&#xff0c;安装成功后在控制台输入node …

Java集合基础

4 集合基础 集合提供一种存储空间可变的存储模型,存储的数据容量可以改变ArrayLis<>: 可调整大小的数组实现<>:是一种特殊的数据类型,泛型可储存重复元素怎么使用呢 在出现E的地方我们使用引用数据类型替换即可举例:ArrayList<String>、ArrayList<Stu…

财务共享时代企业数智化应用能帮我们做些什么?

随着企业规模的不断扩大和业务范围的逐步扩展&#xff0c;财务工作的难度和复杂度也在不断提高&#xff0c;传统的手工录入和处理方式呈现出流程长、效率低、易出错等问题。为了提升财务工作的效率和准确性&#xff0c;越来越多的企业开始利用数智化应用打造企业内部的财务数智…

绝对不能错过的7个零基础免费的ChatGPT镜像网站

还在为打不开openai官网烦心&#xff1f;本文帮你实现ChatGPTMidJourney自由(&#xffe3;∇&#xffe3;)/ &#x1f4d2;收集了一些截至目前(2023年5月25日午12:00)可以免费访问&#xff0c;并且零基础也能正常使用的镜像网站&#xff0c;后续将持续维护更新(&#xff61;&a…

平安银行广州分行立足地域文化,增强差异化权益服务软实力

立足地域文化&#xff0c;拓展差异化权益服务 瓦屋纸窗之下&#xff0c;一盏清茶&#xff0c;三五好友&#xff0c;怡然自若。中国人对茶的喜爱由来已久&#xff0c;茶文化已成为中华传统文化中一张亮丽的名片&#xff0c;而广东茶文化则是中国四大茶文化系列之一。平安银行广州…

抖音seo优化源代码搭建+抖音小程序私有化开源部署

抖音seo优化源码&#xff0c;抖音seo矩阵系统搭建&#xff0c;抖音账号矩阵系统开发&#xff0c;企业在做账号矩阵过程中&#xff0c;最头疼的莫过于私域线索转化&#xff0c;作为开发者都知道&#xff0c;目前市面上我们了解的矩阵系统除了挂载POI信息外&#xff0c;无法挂载留…

unity四叉树和视锥体剔除

这个最好还是看代码&#xff0c;项目有注释放在这里&#xff1a; GetbadEarlyup/Quadtree-cone-scene: 这是一个unity四叉树场景视锥体剔除的Demo (github.com)https://github.com/GetbadEarlyup/Quadtree-cone-scene国内地址&#xff1a; Quadtree-cone-scene: unity四叉树和…

VESD静电监控系统:提高静电防护效果与管理效率

随着科学技术不断发展&#xff0c;现代的工业对静电防护的要求越来越高。因为静电的存在可能会对产品质量、工作环境、甚至是人身产生威胁。静电监控系统是一项高效的管理工具&#xff0c;能够有效地控制和监测静电产生的情况&#xff0c;提高静电防护效果和管理效率。 VESD静电…

U盘超级加密3000试用版与正式版的区别有哪些?

U盘超级加密3000是一款专业的U盘加密软件&#xff0c;它可以为U盘、移动硬盘、内存卡等移动存储设备加密。软件拥有正式版和试用版&#xff0c;那么这两个版本有什么区别呢&#xff1f;下面我们就一起来了解一下。 U盘超级加密3000试用版和正式版的区别 打开软件时的区别 试用…

基于SSM的酒店客房管理系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 酒店管理系统是一款高…

VMware重新安装VMwareTool字体为灰色情况+ubuntu时间设置

文章目录 前言&#xff1a;1. 重新安装VMwareTool字体为灰色2. VMware下ubuntu的时间设置 前言&#xff1a; 之前退出VMware关闭的时候没有等待虚拟机的状态保存&#xff0c;强制关机了。这就导致后面使用的时候&#xff0c;共享目录无法显示情况。对于上面的情况我的博客里面…

ASP-IIS中间件文件解析与写权限

ASP-IIS中间件文件解析与写权限 IIS文件解析 IIS 6 解析漏洞 1、该版本默认会将*.asp;.jpg 此种格式的文件名&#xff0c;当成Asp解析 2、该版本默认会将*.asp/目录下的所有文件当成Asp解析。 如&#xff1a;logo.asp;.jpg xx.asp/logo.jpgIIS 7.x 解析漏洞 在一个文件路…

SSM编程---Day 02

目录 一、核心配置文件 二、junit介绍 三、自定义java注解 四、自定义注解 五、添加log4j的支持 六、sql映射文件的介绍 一、核心配置文件 1、核心配置文件中需要注意顺序 2、根节点 <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN"…

打家劫舍 III——力扣337

文章目录 题目描述法一&#xff1a;动态规划 题目描述 法一&#xff1a;动态规划 问题简化&#xff1a;一棵二叉树&#xff0c;树上的每个点都有对应的权值&#xff0c;每个点有两种状态&#xff08;选中和不选中&#xff09;&#xff0c;问在不能同时选中有父子关系的点的情况…

js正则校验特殊的不可见字符

背景 表单的输入框&#xff0c;用户可能从Excel或者其他地方直接复制粘贴&#xff0c;这时候提交到后端会导致获取的用户输入中包含一些特殊的不可见字符&#xff0c;比如tab键或者制表符等&#xff0c;这时需要在前端对用户输入做一些检验&#xff0c;检查是否存在不可见字符…

【PHP】问题已解决:宝塔面板搭建php网站无法上传图片或是文件(保姆级图文)

目录 问题情况原因和解决方法总结 『PHP』分享PHP环境配置到项目实战个人学习笔记。 欢迎关注 『PHP』 系列&#xff0c;持续更新中 欢迎关注 『PHP』 系列&#xff0c;持续更新中 问题情况 宝塔面板搭建php网站无法上传图片或是文件。 原因和解决方法 检查你的php里是否安装…