Spring Boot中使用WebSocket

news/2024/11/20 2:29:39/

文章目录

  • 为什么要用WebSocket?
  • WebSocket的握手阶段
  • Spring Boot中使用WebSocket
    • 添加WebSocket依赖
    • 服务器代码编写
    • WebSocketSession如何获取用户信息?
    • 创建管理类管理用户与会话
    • 客户端代码

为什么要用WebSocket?

我们往往需要一些这样的场景,服务器给客户端推送消息,如淘宝推送消息,网上聊天等,这些场景下客户端没有主动向服务器发请求,而是由服务器主动的向客户端发送消息,但是之前用的HTTP协议是一次请求一次响应

那该如何实现服务器主动的向客户端推送消息呢?

如果继续使用HTTP协议,可以基于轮询的方式实现,也就是客户端每隔一段时间给服务器发请求,看看有没有要发送给我的消息,如果有就获取到消息,如果没有就等待

上述轮询存在一定问题:

  1. 消耗更多的系统资源,客户端要频繁的向服务器发请求,而这些请求大多数是没有响应的
  2. 获取消息不够及时,只有轮询的时候(下次请求的周期)才能够获取到消息

如果提高轮询频率,则将消耗更多的系统资源,如果降低轮询频率,那获取消息就不够及时

此时可以使用WebSocket协议,WebSocket协议也是应用层协议,传输层也是基于TCP协议的,该协议可以实现服务器主动向客户端推送消息的功能

WebSocket的握手阶段

先了解一下报文格式中的几个重要信息:

  • FIN:表示是否关闭websocket
  • opcode操作码:描述了当前的websocket数据帧是起到了啥作用(0x1表示文本数据,0x2表示二进制数据)
  • MASK:是否开启掩码操作,掩码操作是为了避免缓冲区溢出
  • payload length:载荷的长度
  • payload data:载荷真正携带的数据

WebSocket协议的握手过程

在这里插入图片描述

总结如下:

  1. 客户端向服务端发一个申请建立websocket连接的HTTP请求,该请求是基于HTTP协议的,这个HTTP请求的请求头包含了重要的Header头,如Connection: upgradeUpgrade: websocket,标识要进行协议升级,并升级的协议类型为websocket
  2. 服务端收到该请求后,返回一个HTTP响应,响应状态码为101表示协议切换,并且响应也会包含重要的Header头Connection: upgradeUpgrade: websocket
  3. 客户端与服务端建立好全双工的websocket长连接,后续传输都是基于WebSocket协议

Spring Boot中使用WebSocket

添加WebSocket依赖

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

服务器代码编写

主要的步骤分为以下两步:

  1. 创建一个类作为WebSocketHandler(处理WebSocket中各个通信流程)
  2. 把上述类注册到Spring中,配置路由(关联上哪个路径对应上述的handler)

创建一个类继承TextWebSocketHandler,并添加类注解@Component将该类注册到Spring中,并重写:

  • afterConnectionEstablished:该方法会在websocket连接成功后被调用
  • handleTextMessage:该方法是在websocket收到消息的时候自动调用
  • handleTransportError:该方法是在websocket连接出现异常的时候自动调用的
  • afterConnectionClosed:该方法是在websocket连接关闭后自动调用的
@Component
public class WebSocketAPI extends TextWebSocketHandler {@Override //该方法会在websocket连接成功后被调用public void afterConnectionEstablished(WebSocketSession session) throws Exception {//WebSocketSession是websocket连接对应的会话System.out.println("建立连接了");}@Override //该方法是在websocket收到消息的时候自动调用protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {//message 为收到的消息System.out.println("发送消息:"+message.toString());//session是个会话,里面记录了通信双方,通过session对象调用send方法实现服务器推送消息session.sendMessage(message);message.getPayload(); //获取的message字符串}@Override //该方法是在websocket连接出现异常的时候自动调用的public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {//exception记录了异常信息System.out.println("连接出现异常了");}@Override //该方法是在websocket连接关闭后自动调用的public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {//status 为关闭的状态System.out.println("连接关闭了");}
}

创建另一个类实现WebSocketConfigurer接口,在类上添加@Configuration@EnableWebSocket,并重写registerWebSocketHandlers方法

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Autowiredprivate WebSocketAPI webSocketAPI;@Override //通过该方法,把创建好的Handler类注册到具体的路径上public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {//当浏览器,websocket的请求路径是/test的时候,就会调用到webSocketTest中的方法registry.addHandler(webSocketAPI,"/websocketMessage");}
}

每个和服务端建立websocket连接的客户端,都会在服务器这边有与之对应的WebSocketSession对象,服务器要想给谁发消息,就必须使用谁的WebSocketSession对象调用sendMessage方法发送消息,服务器向客户端推送消息使用session.sendMessage(String message)发送消息,session为每个服务器与客户端建立的websocket会话WebSocketSession

WebSocketSession如何获取用户信息?

我们通常需要获取websocket保存的用户会话的用户信息,那如何获取到连接用户的用户信息呢?

通过注册特定的HttpSession拦截器,就可以把用户给HttpSession中添加的Attribute键值对,往WebSocketSession中也添加一份

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Autowiredprivate WebSocketAPI webSocketAPI;@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(webSocketAPI,"/websocketMessage").// 通过注册特定的HttpSession拦截器,就可以把// 用户给HttpSession中添加的Attribute键值对,往WebSocketSession中也添加一份addInterceptors(new HttpSessionHandshakeInterceptor());}
}

添加完后,可以使用WebSocketSession对象调用getAttributes().get("user")方法获取用户在HttpSession中保存的用户信息

    @Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {User user = (User)session.getAttributes().get("user");System.out.println("建立连接");}

创建管理类管理用户与会话

可以使用HashMap来维护用户与WebSocketSession的关系,key为用户id,value为WebSocketSession对象,只是此时使用线程安全的集合类ConcurrentHashMap

@Component
public class WebSocketSessionManage {private ConcurrentHashMap<Integer, WebSocketSession> websocketSessions = new ConcurrentHashMap<>();//用户连接,添加连接关系public void addWebSocketSession(Integer userId,WebSocketSession webSocketSession){//用户已经上线,防止多开if(websocketSessions.containsKey(userId)){return;}websocketSessions.put(userId,webSocketSession);}//用户掉线,删除连接关系public void delWebSocketSession(Integer userId,WebSocketSession webSocketSession){WebSocketSession get = websocketSessions.get(userId);//只有关系中存在自己的连接信息,才删除if(get == webSocketSession){websocketSessions.remove(userId);}}//根据用户id获取WebSocketSessionpublic WebSocketSession getWebSocketSession(Integer userId){return websocketSessions.get(userId);}
}

客户端代码

客户端使用WebSocket的实例调用send方法即可向服务器发送消息,发送的消息一般为json字符串,所以我们可以使用websocket.send(JSON.stringfy(js))将js对象序列换为json字符串发送

<script>//websocket传输消息//创建websocket实例let websocket = new WebSocket("ws://" + location.host + "/websocketMessage");//绑定一些函数websocket.onopen = function(){console.log('建立连接')}websocket.onmessage = function(e){//e.data为收到服务端推送的消息//e.data为一个json字符串,可以使用JSON.prase(e.data)转换为js对象let resp = JSON.prase(e.data);console.log('收到消息:'+resp)}websocket.onerror = function(){console.log('出现异常')}websocket.onclose = function(){console.log('关闭连接')}//使用websocket实例调用send方法即可向服务器发送消息//注意:参数为字符串,不能为js对象//要发送json格式的数据,将json对象序列化为字符串,JSON.stringfy(json)websocket.send("hehe");
</script>

http://www.ppmy.cn/news/140731.html

相关文章

新型UVC紫外线口罩杀菌消毒器-疫情期间呵护你的健康

因疫情的影响&#xff0c;大家对细菌病毒有了重新的认识&#xff0c;在日常生活中对健康卫生要求更加严格了&#xff0c;家里开始准备了各种消毒器&#xff0c;也开始囤各种疫情防护用品口罩、酒精棉片、医用酒精、衣物除菌液等&#xff1b;甚至一些医用杀菌设备也会纳入采购清…

河北万豪环保系列之---紫外线消毒器

万豪环保紫外线设备简介 一、紫外线消毒器产品介绍 本设备为管道式紫外线消毒器&#xff0c;采用世界领先水平的高强度无臭紫外线杀菌灯&#xff0c;简体内壁经过特殊处理的食品级304不锈钢&#xff0c;使经过预处理的水流过筒体时受到波长253.7nm紫外线足够量的照射&am…

紫外线消毒器:飞利浦紫外线杀菌灯TUV30W型号

飞利浦紫外线杀菌灯TUV30W是低压汞蒸汽放电灯&#xff0c;有石英管状玻璃外壳&#xff0c;发射短波紫外线辐射&#xff0c;253.7nm(UV-C)是一种UV杀菌设备&#xff0c;具有杀菌的作用&#xff0c;玻璃会把产生臭氧的波长为185nm的辐射过滤掉&#xff0c;用来杀死细菌、病毒及其…

代码随想录算法训练营第58天 | 739、496

739. 每日温度 题目描述 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如果气温在这之后都不会升高&#xff0c;请在该位置用 0 来代替。…

紫外线消毒器:不锈钢紫外线消毒器

紫外线消毒器又称为紫外线杀菌设备&#xff0c;紫外线杀菌器&#xff0c;主要是紫外线是物质运行的一种特殊形式&#xff0c;是一种不连接的粒子流。每一粒波长253.7nm的紫外线光子具有4.9eV的能量&#xff0c;当细菌、病毒吸收超过3600~65000uW/c㎡剂量时&#xff0c;对细菌、…

中国消毒柜行业市场深度调研及投资策略预测报告

智研瞻产业研究院专注于中国产业经济情报及研究&#xff0c;目前主要提供的产品和服务包括传统及新兴行业研究、商业计划书、可行性研究、市场调研、专题报告、定制报告等。涵盖文化体育、物流旅游、健康养老、生物医药、能源化工、装备制造、汽车电子、农林牧渔等领域&#xf…

紫外线消毒器设计和安装说明

近年来&#xff0c;随着对紫外线消毒优势和紫外线消毒器价格优势的认知&#xff0c;越来越多的紫外线消毒设备用于生活饮用水消毒&#xff0c;生活饮用水紫外线消毒设备多采用过流管道式构造形式。管道式紫外线消毒器设计和安装说明有以下几点&#xff1a; 1、紫外线消毒器工作…

微电解自洁消毒器应用介绍与水箱自洁式消毒器的区别

微电解自洁消毒器应用介绍与水箱自洁式消毒器的区别有哪些呢&#xff1f; 我们知道水箱自洁式消毒器分为内置式水箱消毒器与外置式水箱消毒器他们之间的区别有哪些呢 带着疑问我们来看下面的介绍 微电解自洁消毒器概述 人们在生活中都有可能&#xff08;居住、办公、就…