【Springboot系列】总结websocket的几种实现方式,建议收藏

1、前言

websocket在java中有多种实现方式,一直没有做一个整理,今天整理下三种最常用的实现方式以及一些注意点

2、javax 实现方式

之前已经单独记录了这种方式

【SpringBoot系列】springboot websocket全套模板,省去搭建的烦恼,还有福利拿哦-CSDN博客

这种好处在于接口简单,只需要几个注解即可

支持路径参数:@ServerEndpoint("/tracking/{groupName}")

参数获取:通过map访问key进行获取

Map<String, List<String>> params = session.getRequestParameterMap();
List<String> strings = params.get("groupName");

连接方式:ws:localhost:8080/tracking/123?group=1

@ServerEndpoint("/url") 该注解用于注释服务端的类,被该注解注释的类,将会被标注为webSocket的服务类,参数value为访问的路径
@OnOpen 被该注解注释的方法,将在客户端与服务端建立连接时执行
@OnMessage 被该注解注释的方法,将在服务端收到消息时执行
@OnClose 被该注解注释的方法,将在链接关闭时执行
@OnError 被该注解注释的方法,将在链接发生错误时执行

特点:ws 容器为tomcat,受限于tomcat,性能有一定问题,在常规开发中对性能没那么高要求的情况下,没有问题

3、spring-boot-starter-websocket

3.1 实现方式

依赖

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

实现具体路径handler

package com.example.wstest;

import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;
import java.util.Map;

/**
 * @author 种鑫
 * @date 2024/6/17 13:41
 */
@Component
public class WsHandler extends AbstractWebSocketHandler {
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        URI uri = session.getUri();
//        UrlQuery of = UrlQuery.of(uri.toString(), Charset.defaultCharset());
        UriComponents builder = UriComponentsBuilder.fromUri(uri).build();
        String path = builder.getPath();
        MultiValueMap<String, String> queryParams = builder.getQueryParams();
        Map<String, Object> attributes = session.getAttributes();
        System.out.println("新连接");
    }


    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        System.out.println("text msg");
    }

    @Override
    protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
        super.handleBinaryMessage(session, message);
        System.out.println("Binary msg");
    }

    @Override
    protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception {
        super.handlePongMessage(session, message);
        System.out.println("连接错误");
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        super.handleTransportError(session, exception);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        super.afterConnectionClosed(session, status);
        System.out.println("连接关闭");
    }
}

配置handler生效

@Configuration
@EnableWebSocket
public class WsConfig implements WebSocketConfigurer {
    @Resource
    WsHandler wsHandler;
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(wsHandler,"/spce/{id}").setAllowedOrigins("*");
    }
}

 3.2 使用方式

获取参数需要自己构建

访问方式:ws:localhost:8080/spce/111?abc=123

3.3 原理解析

依赖Springboot web,底层同样是使用tomcat支撑Websocket

org.springframework.web.socket.config.annotation.AbstractWebSocketHandlerRegistration#getMappings

	protected final M getMappings() {
		M mappings = createMappings();
		if (this.sockJsServiceRegistration != null) {
			SockJsService sockJsService = this.sockJsServiceRegistration.getSockJsService();
			this.handlerMap.forEach((wsHandler, paths) -> {
				for (String path : paths) {
					String pathPattern = (path.endsWith("/") ? path + "**" : path + "/**");
					addSockJsServiceMapping(mappings, sockJsService, wsHandler, pathPattern);
				}
			});
		}
		else {
			HandshakeHandler handshakeHandler = getOrCreateHandshakeHandler();
			HandshakeInterceptor[] interceptors = getInterceptors();
			this.handlerMap.forEach((wsHandler, paths) -> {
				for (String path : paths) {
					addWebSocketHandlerMapping(mappings, wsHandler, handshakeHandler, interceptors, path);
				}
			});
		}

		return mappings;
	}

可以看到对于不是/结尾的路径前后都加了匹配

4、Netty  Websocket

依赖

 <dependency>
     <groupId>io.netty</groupId>
     <artifactId>netty-all</artifactId>
     <version>4.1.69.Final</version>
 </dependency>

构建服务器



@Slf4j
@Configuration
public class WsServer implements CommandLineRunner {

    private static final Integer PORT = 8888;

    @Override
    public void run(String... args) throws Exception {
        new WebSocketConfig().start();
    }

    public void start() {
        // 创建EventLoopGroup
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup(Runtime.getRuntime().availableProcessors() * 2);
        try {

            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            pipeline.addLast(new HttpServerCodec());
                            // 最大数据长度
                            pipeline.addLast(new HttpObjectAggregator(65536));
                            // 添加接收websocket请求的url匹配路径
                            pipeline.addLast(new WebSocketServerProtocolHandler("/websocket"));
                            // 10秒内收不到消息强制断开连接
                            // pipeline.addLast(new ReadTimeoutHandler(10, TimeUnit.SECONDS));
                            pipeline.addLast(new WebSocketHandler());
                        }
                    });

            ChannelFuture future = serverBootstrap.bind(PORT).sync();
            log.info("websocket server started, port={}", PORT);
            // 处理 channel 的关闭,sync 方法作用是同步等待 channel 关闭
            // 阻塞
            future.channel().closeFuture().sync();
        } catch (Exception e) {
            log.error("websocket server exception", e);
            throw new RuntimeException(e);
        } finally {
            log.info("websocket server close");
            // 关闭EventLoopGroup
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

 5、总结

对于常规使用,压力不大的情况下使用javax方式,很方便也很简单

对于一些游戏服务器来说建议使用Netty这种方式,可以掌控,同时可以轻松切换socket服务器

注:2,3 两种方式在注入时候会有问题,建议使用static变量,手动注入类

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

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

相关文章

安卓TextView控件实现下划线

效果展示 这里需要使用到LayerDrawable&#xff0c;对应于<layer-list>标签。在drawable目录下新建一个text_underline.xml文件&#xff0c;text_underline.xml的代码如下&#xff1a; <?xml version"1.0" encoding"utf-8"?> <layer-lis…

算法安全自评估报告如何填写?(附模板)

之前&#xff0c;众森企服给大家讲过办理互联网信息服务算法备案有三部分组成&#xff1a;主体备案、算法备案和产品备案。 主体备案主要审查的就是一家主体公司是否有算法相应的规章制度&#xff0c;里面最主要的就是算法安全管理制度。 算法备案主要审查的就是算法本身的情…

便携式手持气象仪:低功耗设计

TH-LSZ05便携式手持气象仪是一款轻便、操作简便的气象监测工具&#xff0c;集成了风向、风速、大气压、温度、湿度五项气象要素的测量功能。这些设备通常设计为体积小、重量轻&#xff0c;以便于用户随时携带并使用。通过使用手持气象仪&#xff0c;用户可以实时获取关键的气象…

清华停招土木,新增地球科学引热议

早在今年2月26日&#xff0c;多个自媒体平台上有人发布消息称“清华大学停止土木工程等专业招生”&#xff0c;引发广泛关注。 在清华大学的官网可以看到下图的公告。 可以看到&#xff0c;清华大学停招土木工程等专业&#xff0c;新增地球系统科学等专业。这一举措引起全网热…

LaTeX 的使用

文章目录 TeX 编辑器文档类型中文编译文档结构preamble 导言区&#xff08;不能放正文内容&#xff09;document body 正文区 正文内容目录段落列表无序列表有序列表 图片表格交叉引用段落图片表格 转义符 数学公式数学符号行内公式行间公式有公式计数器无公式计数器 公式包含文…

SpringBoot(基础概述和学习方向)

目录 一、为什么学习 SpringBoot ? 二、适用的人群 三、" SpringBoot " 学习安排 &#xff08;1&#xff09;分为基础学习和高级学习。&#xff08;本篇博客自学内容来自B站黑马&#xff09; 1、基础学习 2、进阶学习 &#xff08;2&#xff09;后期的学习方…

教育界杂志教育界杂志社教育界编辑部2024年第13期目录

教育视界 “三全育人”视角下九年一贯制学校德育体系构建与探索 练成; 2-4 儿童审美视角下小学文言文教学的实践研究 张瑾; 5-7 打造初中美术创作教学的“四度空间” 叶才红; 8-10 探索之窗《教育界》投稿&#xff1a;cn7kantougao163.com “屋顶农场”项目迭代…

【Python】从0开始的Django基础

Django框架基础 unit01一、Django基础1.1 什么是Django?1.2 安装与卸载1.2.1 Python与Django的版本1.2.2 安装1.2.3 查看Django版本1.2.4 卸载 二、Django项目2.1 概述2.2 创建项目2.3 启动项目2.4 项目的目录结构2.5 配置 三、URL 调度器3.2 定义URL路由3.2 定义首页的路由3.…

ROS系统中解析通过CAN协议传输的超声波传感器数据

CAN Bus接口设置&#xff1a;确保你的ROS系统可以通过CAN Bus接口与外部设备通信。这可能需要CAN卡或CAN适配器&#xff0c;以及相应的驱动程序和库。 CAN消息接收&#xff1a;配置ROS节点来监听特定的CAN ID&#xff0c;这通常是超声波传感器的标识符。 数据解析&#xff1a…

记录一下 Chrome浏览器打印时崩溃问题

问题描述&#xff1a; 为了查看页面内存占用情况&#xff0c;按F2,打开Memory chrome浏览器点击“打印”按钮&#xff0c;或Ctrl P 时出现如下页面 一直以为是页面问题&#xff0c;每次打印的时候遇到这种 崩溃现象 就是重新刷新页面 但今天刚开一个页面&#xff0c;内存 …

接口测试的几种方法

其实无论用那种测试方法&#xff0c;接口测试的原理是通过测试程序模拟客户端向服务器发送请求报文&#xff0c;服务器接收请求报文后对相应的报文做出处理然后再把应答报文发送给客户端&#xff0c;客户端接收应答报文这一个过程。 方法一、用LoadRunner实现接口测试 大家都…

【Kaggle量化比赛】Top讨论

问: 惊人的单模型得分,请问您使用了多少个特征来获得如此高的得分?我也在使用LGB模型。 答 235个特征(180个基本特征+滚动特征) 问: 您是在使用Polars进行特征工程还是仅依赖于Pandas+Numba/多进程?即使进行了Numba优化,我也发现当滚动特征过多时,推理速度会非常慢。在…

Gitlab SSH无法连接但是HTTP可以连接

项目场景&#xff1a; Gitlab在docker中布置好之后测试&#xff0c;发现SSH无法连接但是HTTP可以连接 提示&#xff1a;这是一个无效的源路径 问题描述 http可以识别为git项目&#xff0c;而ssh无法识别成git项目。 原因分析&#xff1a; 三种猜想 端口号被占用 尝试查看…

【活动回顾】ABeam News | ABeam德硕中国受邀参加浦东新区商务委员会企业座谈会,携手共谋发展

政企协同促发展 近日&#xff0c;应浦东新区商务委员会邀请&#xff0c;ABeam中国参与咨询与调查企业座谈会。 深化政企合作、促进联系交流&#xff0c;浦东新区商务委员副主任曹磊与会出席&#xff0c;并与参会企业代表深入交流&#xff0c;了解企业发展情况和需求&#xff0…

25. 一个双高斯照相物镜的设计

导论&#xff1a; 双高斯照相物镜的设计思想&#xff0c;当β-1时&#xff0c;由于其对称&#xff0c;彗差、畸变和倍率色差自动校正为0&#xff0c;利用中间两块厚透镜可以校正场曲&#xff0c;选取合适的光阑位置可以校正像散&#xff0c;在厚透镜中加胶合面使每个半部校正位…

震撼科技界的GPT-4o发布首日即遭“越狱破防”

前言 本文主要解读分析OpenAI最新推出的大型模型GPT-4o可能存在的越狱风险。 5 月14 日凌晨的科技圈再一次被OpenAI轰动&#xff0c;其发布的最新大模型GPT-4o&#xff0c;能力横跨语音、文本和视觉&#xff0c;这一成果无疑再次巩固了OpenAI在人工智能领域的领先地位。 然而…

【Android】基于webView打造富文本编辑器(H5)

目录 前言一、实现效果二、具体实现1. 导入网页资源2. 页面设计3. 功能调用4. 完整代码 总结 前言 HTML5是构建Web内容的一种语言描述方式。HTML5是Web中核心语言HTML的规范&#xff0c;用户使用任何手段进行网页浏览时看到的内容原本都是HTML格式的&#xff0c;在浏览器中通过…

Python Django 实现教师、学生双端登录管理系统

文章目录 Python Django 实现教师、学生双端登录管理系统引言Django框架简介环境准备模型设计用户认证视图和模板URL路由前端设计测试和部署获取开源项目参考 Python Django 实现教师、学生双端登录管理系统 引言 在当今的教育环境中&#xff0c;数字化管理系统已成为必不可少…

3.华为trunk和access接口配置

目的&#xff1a;PC1 连通三层交换机LSW1 LSW1配置 [Huawei]vlan batch 10 [Huawei]interface Vlanif 10 [Huawei-Vlanif10]ip address 10.10.10.10 24 [Huawei]int g0/0/1 [Huawei-GigabitEthernet0/0/1]port link-type trunk [Huawei-GigabitEthernet0/0/1]port trunk allow…

大数据分析-二手车用户数据可视化分析

项目背景 在当今的大数据时代&#xff0c;数据可视化扮演着至关重要的角色。随着信息的爆炸式增长&#xff0c;我们面临着前所未有的数据挑战。这些数据可能来自社交媒体、商业交易、科学研究、医疗记录等各个领域&#xff0c;它们庞大而复杂&#xff0c;难以通过传统的数据处…