SpringBoot中使用WebSocket的教程分享

 更新时间:2023年06月01日 16:20:31   作者:X_H学Java  
这篇文章主要为大家详细介绍了如何在SpringBoot中使用WebSocket,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以了解一下

为什么要用WebSocket

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

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

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

上述轮询存在一定问题:

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

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

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

WebSocket的握手阶段

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

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

WebSocket协议的握手过程

总结如下:

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

Spring Boot中使用WebSocket

添加WebSocket依赖

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

服务器代码编写

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

  • 创建一个类作为WebSocketHandler(处理WebSocket中各个通信流程)
  • 把上述类注册到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 {
    @Autowired
    private 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 {
    @Autowired
    private WebSocketAPI webSocketAPI;
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(webSocketAPI,"/websocketMessage").
                // 通过注册特定的HttpSession拦截器,就可以把
                // 用户给HttpSession中添加的Attribute键值对,往WebSocketSession中也添加一份
                addInterceptors(new HttpSessionHandshakeInterceptor());
    }
}

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

    @Override
    public 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获取WebSocketSession
    public WebSocketSession getWebSocketSession(Integer userId){
        return websocketSessions.get(userId);
    }
}

客户端代码

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

 //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");

到此这篇关于SpringBoot中使用WebSocket的教程分享的文章就介绍到这了,更多相关SpringBoot WebSocket内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java实现布隆过滤器的几种方式总结

    Java实现布隆过滤器的几种方式总结

    这篇文章给大家总结了几种Java实现布隆过滤器的方式,手动硬编码实现,引入Guava实现,引入hutool实现,通过redis实现等几种方式,文中有详细的代码和图解,需要的朋友可以参考下
    2023-07-07
  • Java 实战项目锤炼之IT设备固定资产管理系统的实现流程

    Java 实战项目锤炼之IT设备固定资产管理系统的实现流程

    读万卷书不如行万里路,只学书上的理论是远远不够的,只有在实战中才能获得能力的提升,本篇文章手把手带你用Java+SSM+jsp+mysql+maven实现一个IT设备固定资产管理系统,大家可以在过程中查缺补漏,提升水平
    2021-11-11
  • java Swing组件setBounds()简单用法实例分析

    java Swing组件setBounds()简单用法实例分析

    这篇文章主要介绍了java Swing组件setBounds()简单用法,结合实例形式分析了Swing组件setBounds()方法的功能与简单使用方法,需要的朋友可以参考下
    2017-11-11
  • springboot layui hutool Excel导入的实现

    springboot layui hutool Excel导入的实现

    本文主要介绍了springboot layui hutool Excel导入的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-03-03
  • SpringMVC底层执行流程及原理解析

    SpringMVC底层执行流程及原理解析

    这篇文章主要介绍了SpringMVC底层执行流程及原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05
  • SpringMVC和Ajax的交互详解(手工处理)

    SpringMVC和Ajax的交互详解(手工处理)

    Ajax即异步的 JavaScript和XML,是一种无需重新加载整个网页的情况下,能够更新部分模块的网页技术,下面这篇文章主要给大家介绍了关于SpringMVC和Ajax交互的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-08-08
  • 微信小程序与AspNetCore SignalR聊天实例代码

    微信小程序与AspNetCore SignalR聊天实例代码

    这篇文章主要介绍了微信小程序与AspNetCore SignalR聊天实例代码,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-08-08
  • JavaSwing BorderLayout 边界布局的实现代码

    JavaSwing BorderLayout 边界布局的实现代码

    这篇文章主要介绍了JavaSwing BorderLayout 边界布局的实现代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • Java中如何避免sql注入实例详解

    Java中如何避免sql注入实例详解

    SQL注入是最常见的攻击方式之一,它不是利用操作系统或其它系统的漏洞来实现攻击的,而是程序员因为没有做好判断,被不法用户钻了SQL的空子,下面这篇文章主要给大家介绍了关于Java中如何避免sql注入的相关资料,需要的朋友可以参考下
    2022-01-01
  • Spring AOP访问目标方法的参数操作示例

    Spring AOP访问目标方法的参数操作示例

    这篇文章主要介绍了Spring AOP访问目标方法的参数操作,结合实例形式详细分析了spring面向切面AOP访问目标方法的参数相关实现步骤与操作注意事项,需要的朋友可以参考下
    2020-01-01

最新评论