SpringBoot+WebSocket

SpringBoot+WebSocket

1.导入依赖:

-- Spring Boot 2.x 使用 javax.websocket-- Spring Boot 3.x 使用 jakarta.websocket<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions>
</dependency>
package com.js.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** websocket配置类中*/
@Configuration
public class WebSocketConfig {/***  第一个配置是因为使用springboot内置容器,自己开发时需要配置,如果有独立的容器需要将其注释掉,* 也就意味着,如果将项目打成WAR包,部署到服务器,使用Tomcat启动时,需要注释掉ServerEndpointExporter配置;* @return*/@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}/*** MyEndpointConfigure配置是因为我的需求需要,需要在websocket类中注入service层或者dao层的接口,* MyEndpointConfigure配置就是为了解决websocket无法注入的问题,如果没有需要可以不用配置* @return*/@Beanpublic MyEndpointConfigure newConfigure() {return new MyEndpointConfigure();}
}
package com.js.httpclenlient;
import com.hy.core.toolkit.util.CollectionUtil;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;/*** @author* @Description: WebSocket服务端代码,包含接收消息,推送消息等接口*/
@Component
@ServerEndpoint(value = "/socket/{archivecode}")
public class WebSocketServer {//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。private static AtomicInteger online = new AtomicInteger();//concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象的session。private static Map<Long, List<Session>> sessionPools = new HashMap<>();@Resourceprivate RemoteAccessClient remoteAccessClient;/*** 发送消息方法* @param sessions 客户端与socket建立的会话* @param message 消息* @throws IOException*/public void sendMessage(List<Session> sessions, String message) throws IOException{if(CollectionUtil.isNotEmpty(sessions)){sessions.stream().forEach(session-> {try {session.getBasicRemote().sendText(message);} catch (IOException e) {throw new RuntimeException(e);}});}}/*** 连接建立成功调用* @param session 客户端与socket建立的会话* @param archivecode 客户端的archivecode*/@OnOpenpublic void onOpen(Session session, @PathParam(value = "archivecode") Long archivecode){List<Session> sessions = sessionPools.get(archivecode);if(CollectionUtil.isNotEmpty(sessions)){sessions.add(session);sessionPools.put(archivecode, sessions);}else {List<Session> sessionList = new ArrayList<>();sessionList.add(session);sessionPools.put(archivecode, sessionList);}addOnlineCount();System.out.println(archivecode + "加入webSocket!当前人数为" + online);try {sendMessage( sessions, "欢迎" + archivecode + "加入连接!");} catch (IOException e) {throw new IllegalArgumentException("webSocket建立连接失败");}}/*** 关闭连接时调用* @param 关闭连接的客户端的session*/@OnClosepublic void onClose(Session session,@PathParam(value = "archivecode") String archivecode){Set<Long> sessionkey = sessionPools.keySet();for (Long key : sessionkey) {List<Session> sessions = sessionPools.get(key);boolean contains = sessions.contains(session);if(contains){sessions.remove(session);}}sessionPools.remove(archivecode);subOnlineCount();System.out.println(archivecode + "断开webSocket连接!当前人数为" + online);}/*** 收到客户端消息时触发(群发)* @param message* @throws IOException*/@OnMessagepublic void onMessage(String message) throws IOException{Set<Long> companyIds = sessionPools.keySet();for (Long companyid : companyIds) {List<Session> sessions = sessionPools.get(companyid);try {sendMessage(sessions, message);} catch(Exception e){e.printStackTrace();}}}/*** 发生错误时候* @param session* @param throwable*/@OnErrorpublic void onError(Session session, Throwable throwable){System.out.println("发生错误");throwable.printStackTrace();}/*** 给指定用户发送消息* @param archivecode 用户名* @param message 消息* @throws IOException*/public void sendInfo(Long archivecode, String message){List<Session> sessions = sessionPools.get(archivecode);try {sendMessage(sessions, message);}catch (Exception e){e.printStackTrace();}}/*** 根据用户名获取session会话对象* @param archivecode* @return*/public  List<Session> getSession(Long archivecode){List<Session> sessions = sessionPools.get(archivecode);return sessions;}public static void addOnlineCount(){online.incrementAndGet();}public static void subOnlineCount() {online.decrementAndGet();}}
package com.js.controller;import cn.hutool.json.JSONUtil;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;/***  6.密集架报警信息实时更新获取*/@RequestMapping(value = "/denseRack/alarm", method = RequestMethod.POST)public void testSocket1(@RequestBody FilealertInformation dto) throws JsonProcessingException {Long archiveCompanyId = ThreadLocalUtil.getArchiveCompanyId();dto.setPageRefreshType("warning");String s = JSONUtil.toJsonStr(dto);webSocketServer.sendInfo(archiveCompanyId, s);}

测试发送

在这里插入图片描述

结果

在这里插入图片描述

Spring boot接入websocket时,启动报错

Spring Boot 2.x

javax.websocket.server.ServerContainer not available

Spring Boot 3.x

jakarta.websocket.server.ServerContainer not available

问题原因

1. 因为spring boot内带tomcat,tomcat中的websocket会有冲突。
解决方案:​ spring boot启动时排除tomcat依赖包即可<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions>
</dependency>

@SpringBootTest启动时没有启动servlet

解决方案:@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

Spring Boot 与WebSocket API版本不对应

Spring Boot 2.x 使用 javax.websocketSpring Boot 3.x 使用 jakarta.websocket解决方案:<!-- SpringBoot3 引入以下依赖,并删除之前的 javax.websocket依赖 -->
<dependency><groupId>jakarta.websocket</groupId><artifactId>jakarta.websocket-api</artifactId><version>2.1.0</version>
</dependency>

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法分析与设计课后练习28

在图灵机中, 设 B 表示空格, q0表示图灵机的初始状态,qF表示图灵机的终止状态, 如果工作带上的信息为B10100010B, 读写头对准最右边第一个为0的单元, 则按照下指令执行后, 得到的结果是什么? 如果工作带上的信息为 B10100011B, 读写头对准右边第一个为 1的单元, 则执行指令后得…

JDK17 SpringBoot3 整合常见依赖

JDK版本&#xff1a;17 SpringBoot 整合Mybatis Plus 、Redis等 依赖文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance&q…

计算机服务器中了halo勒索病毒怎么处理,halo勒索病毒解密步骤

网络技术的不断发展与应用&#xff0c;为企业的生产运营提供了极大便利&#xff0c;但随之而来的网络安全威胁也在不断增加&#xff0c;近期云天数据恢复中心接到很多企业的求助&#xff0c;企业的计算机服务器遭到了halo勒索病毒攻击&#xff0c;导致企业计算机系统瘫痪&#…

基于Antd4 和React-hooks的项目开发

基于Antd4 和React-hooks的项目开发 https://github.com/dL-hx/react-cnode 项目依赖使用 react 16.13react-redux 7.xreact-router-dom 5.xredux 4.xantd 4axiosmoment 2.24 (日期格式化)qs 项目视图说明 首页主题详情用户列表用户详情关于 配置按需加载 https://3x.an…

【3D数据读取】利用JAVA读取GLB(GLTF)文件数据

了解GLB和GLTF&#xff1a; GLB和GLTF是用于共享3D数据的标准化文件格式。GLB是GLTF的二进制格式&#xff0c;而GLTF基于JSON&#xff0c;一种基于文本的数据格式。 GLB文件&#xff1a; 由一个头部和一个二进制数据块组成。头部包含文件的元数据&#xff0c;例如文件版本、文件…

Ansible常用模块详解(附各模块应用实例和Ansible环境安装部署)

目录 一、ansible概述 1、简介 2、Ansible主要功能&#xff1a; 3、Ansible的另一个特点&#xff1a;所有模块都是幂等性 4、Ansible的优点&#xff1a; 5、Ansible的四大组件&#xff1a; 二、ansible环境部署&#xff1a; 1、环境&#xff1a; 2、安装ansible&#…

final的详解

在Java中&#xff0c;final 关键字用于表示不可改变的实体&#xff0c;可以应用于变量、方法、类和指令重排序。它有不同的作用&#xff0c;具体取决于它被应用的上下文。 1.对于变量&#xff1a; 如果一个变量被声明为 final&#xff0c;则该变量的值在一旦被赋予后就不能再被…

SLAM算法与工程实践——RTKLIB编译

SLAM算法与工程实践系列文章 下面是SLAM算法与工程实践系列文章的总链接&#xff0c;本人发表这个系列的文章链接均收录于此 SLAM算法与工程实践系列文章链接 下面是专栏地址&#xff1a; SLAM算法与工程实践系列专栏 文章目录 SLAM算法与工程实践系列文章SLAM算法与工程实践…

selenium css定位

selenium-css定位 element_css driver.find_element(By.CSS_SELECTOR, css表达式)css定位说明 selenium中的css定位&#xff0c;实际是通过css选择器来定位到具体元素&#xff0c;css选择器来自于css语法 css定位优点 语法简洁对比其他定位方式&#xff0c;定位效率更快对…

MyBatis的ORM!!!

首先你要明白为什么使用ORM&#xff1a;我们看一个示例&#xff0c;我们发现我们要声明的pojo类中的属性名和数据库中的字段名不一致&#xff0c;这时就需要我们使用MyBatis的ORM。 首先还是准备工作&#xff1a; 1.创建Maven工程&#xff0c;还没有配置Maven的和还不会的去看这…

macOS系统下载百度网盘的操作流程

第一步 进入百度网盘的官网&#xff0c;链接&#xff1a;百度网盘-免费云盘丨文件共享软件丨超大容量丨存储安全​​​​​​​&#xff0c;选择“客户端下载” 第二步 根据自己的电脑配置选择版本进行下载。芯片的查看路径是系统设置-通用-关于本机 第三步 点击右上角的图标…

Linux线程——条件变量

什么是条件变量 条件变量是线程另一可用的同步机制。条件变量给多个线程提供了一个会合的场所。条件变量与互斥量一起使用时&#xff0c;允许线程以无竞争的方式等待特定的条件发生。 条件本身是由互斥量保护的。线程在改变条件状态前必须首先锁住互斥量&#xff0c;其他线程…