SpringBoot 整合 WebSocket

简介: WebSocket是基于TCP协议的一种网络协议,它实现了浏览器与服务器全双工通信,支持客户端和服务端之间相互发送信息。在有WebSocket之前,如果服务端数据发生了改变,客户端想知道的话,只能采用定时轮询的方式去服务端获取,这种方式很大程度上增大了服务器端的压力,有了WebSocket之后,如果服务端数据发生改变,可以立即通知客户端,客户端就不用轮询去换取,降低了服务器的压力。目前主流的浏览器都已经支持WebSocket协议了。

一、WebSocket概述:

WebSocket是基于TCP协议的一种网络协议,它实现了浏览器与服务器全双工通信,支持客户端和服务端之间相互发送信息。在有WebSocket之前,如果服务端数据发生了改变,客户端想知道的话,只能采用定时轮询的方式去服务端获取,这种方式很大程度上增大了服务器端的压力,有了WebSocket之后,如果服务端数据发生改变,可以立即通知客户端,客户端就不用轮询去换取,降低了服务器的压力。目前主流的浏览器都已经支持WebSocket协议了。
WebSocket使用ws和wss作资源标志符,它们两个类似于http和https,wss是使用TSL的ws。主要有4个事件:

  • onopen 创建连接时触发
  • onclose 连接断开时触发
  • onmessage   接收到信息时触发
  • onerror   通讯异常时触发

最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。

其他特点包括:

(1)建立在 TCP 协议之上,服务器端的实现比较容易。

(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

(3)数据格式比较轻量,性能开销小,通信高效。

(4)可以发送文本,也可以发送二进制数据。

(5)没有同源限制,客户端可以与任意服务器通信。

(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

1.使用WebSocket原因:

了解计算机网络协议的人,应该都知道:HTTP 协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求/响应模型。通信请求只能由客户端发起,服务端对请求做出应答处理。

这种通信模型有一个弊端:HTTP 协议无法实现服务器主动向客户端发起消息。

这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。大多数 Web 应用程序将通过频繁的异步 JavaScript 和 XML(AJAX)请求实现长轮询。轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开)。

因此,工程师们一直在思考,有没有更好的方法。WebSocket 就是这样发明的。WebSocket 连接允许客户端和服务器之间进行全双工通信,以便任一方都可以通过建立的连接将数据推送到另一端。WebSocket 只需要建立一次连接,就可以一直保持连接状态。这相比于轮询方式的不停建立连接显然效率要大大提高。

2.WebSocket工作方式:

Web 浏览器和服务器都必须实现 WebSockets 协议来建立和维护连接。由于 WebSockets 连接长期存在,与典型的 HTTP 连接不同,对服务器有重要的影响。

基于多线程或多进程的服务器无法适用于 WebSockets,因为它旨在打开连接,尽可能快地处理请求,然后关闭连接。任何实际的 WebSockets 服务器端实现都需要一个异步服务器。


二、WebSocket使用:

1.WebSocket客户端:

创建一个WebSocket对象:

var Socket = new WebSocket(url, [protocol] );

以上代码中的第一个参数 url, 指定连接的 URL。第二个参数 protocol 是可选的,指定了可接受的子协议。

a.WebSocket 属性:

以下是 WebSocket 对象的属性。假定我们使用了以上代码创建了 Socket 对象:

属性

描述

Socket.readyState

只读属性readyState表示连接状态,可以是以下值:0 - 表示连接尚未建立。1 - 表示连接已建立,可以进行通信。2 - 表示连接正在进行关闭。3 - 表示连接已经关闭或者连接不能打开。

Socket.bufferedAmount

只读属性bufferedAmount已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。

b.WebSocket 事件:

以下是 WebSocket 对象的相关事件。假定我们使用了以上代码创建了 Socket 对象:

事件

事件处理程序

描述

open

Socket.onopen

连接建立时触发

message

Socket.onmessage

客户端接收服务端数据时触发

error

Socket.onerror

通信发生错误时触发

close

Socket.onclose

连接关闭时触发

c.WebSocket 方法:

以下是 WebSocket 对象的相关方法。假定我们使用了以上代码创建了 Socket 对象:

方法

描述

Socket.send()

使用连接发送数据

Socket.close()

关闭连接

2.WebSocket 服务端


SpringBoot整合WebSocket:

SpringBoot对WebSocket也做了支持,需要使用的话引入依赖所需要的包spring-boot-starter-websocket就可以了。利用它可以双向通信的特性来实现一个简单的聊天室功能

  • 用户在浏览器端进入聊天室(创建WebSocket连接);
  • 用户端发送消息到服务端(客户端像服务端发信息);
  • 服务端将消息转发到客户端(服务端向客户端发信息);
  • 用户退出聊天室(断开WebSocket连接)。
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
server.port=8090
server.servlet.context-path=/websocket

要使用WebSocket,我们需要在启动来开启对WebSocket的支持功能,使用@EnableWebSocket注解

@SpringBootApplication
@EnableWebSocket
public class WebSocketApplication {
    public static void main(String[] args) {
        SpringApplication.run(WebSocketApplication.class, args);
    }
    /**
    * 初始化Bean,它会自动注册使用了 @ServerEndpoint 注解声明的 WebSocket endpoint
    * @return
    */
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    } 
}

聊天时,我们需要知道有哪些用户在线,所以我们创建一个工具类来记录在线用户和实现服务端向客户端发送消息

public class WebSocketUtil {
    /**
     * 模拟存储   在线用户
     */
    public static final Map<String, Session> USERS_ONLINE = new ConcurrentHashMap<>();
    /**
     * 向所有在线用户发送消息(遍历 向每一个用户发送)
     * @param message
     */
    public static void sendMessageToAllOnlineUser(String message){
        USERS_ONLINE.forEach((username, Session) -> sendMessage(Session, message));
    }
    /**
     * 向指定用户发送消息
     * @param session 用户session
     * @param message 发送消息内容
     */
    private static void sendMessage(Session session, String message) {
        if (session == null) {
            return;
        }
        final RemoteEndpoint.Basic basic = session.getBasicRemote();
        if (basic == null) {
            return;
        }
        try {
            basic.sendText(message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

服务端类,使用@ServerEndpoint("")说明服务端监听此地址的消息:

@Controller
@ServerEndpoint("/chat/{username}") //说明创建websocket的endpoint
public class ChatServerEndpoint {
  /**
     * 访问聊天室页面
     * @return
     */
    @GetMapping("/chatPage")
    public String chatPage(){
        return "chat.html";
    } 
}

WebSocket有4个事件,我们对每个事件做监听,使用对应的注解即可实现监听

WebSocket四个事件:

onopen:

onopen 在连接创建(用户进入聊天室)时触发

@OnOpen
public void openSession(@PathParam("username") String username, Session session){
    //存储用户
    WebSocketUtil.USERS_ONLINE.put(username, session);
    //向所有在线用户发送用户上线通知消息
    String message = "["+username+"]进入聊天室";
    System.out.println(message);
    WebSocketUtil.sendMessageToAllOnlineUser(message);
}

onclose:

onclose 在连接断开(用户离开聊天室)时触发

@OnClose
public void closeSession(@PathParam("username") String username, Session session){
    //删除用户
    WebSocketUtil.USERS_ONLINE.remove(username);
    //向所有在线用户发送用户下线通知消息
    String message = "["+username+"]离开了聊天室";
    System.out.println(message);
    WebSocketUtil.sendMessageToAllOnlineUser(message);
    //下线后关闭session
    try {
        session.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

onmessage:

onmessage 在接收到消息时触发

@OnMessage
public void onMessage(@PathParam("username") String username, String message){
    //向聊天室中的人发送消息
    message = "["+username+"]:" + message;
    System.out.println(message);
    WebSocketUtil.sendMessageToAllOnlineUser(message);
}

onerror:

onerror 在连接发生异常时触发

@OnError
public void sessionError(Session session, Throwable throwable){
    try {
        session.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    System.out.println("WebSocket连接发生异常,message:"+throwable.getMessage());
}

聊天室页面:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="jquery-1.9.1.min.js"></script>
  </head>
  <body>
    <table>
      <tr><td>
        <label for="messageArea">聊天信息:</label><textarea id="messageArea" cols="50" rows="30"></textarea></br>
      </td></tr>
  <tr><td>
    <label for="username">用  户  名:</label><input type="text" id="username" ></br>
  </td></tr>
<tr><td>
  <input type="button" id="joinRoomBtn" value="进入聊天室" />    
  <input type="button" id="leaveRoomBtn" value="离开聊天室" /></br>
</td></tr>
<tr><td>
  <label for="sendMessage">输入消息:</label><textarea id="sendMessage" cols="50" rows="3"></textarea></br>
</td></tr>
<tr><td>
  <input type="button" id="sendBtn" value="发送消息" />
  </td></tr>
</table>
</body>
</html>
<script>
  $(function(){
    var webSocket;
    var url = 'ws://localhost:8090/websocket/chat/';
    //进入聊天室
    $('#joinRoomBtn').click(function(){
      var username = $('#username').val();
      webSocket = new WebSocket(url+username);
      webSocket.onopen = function (){
        console.log('webSocket连接创建。。。');
      }
      webSocket.onclose = function(){
        $('#messageArea').append('['+username+']离开了聊天室\n');
      }
      webSocket.onmessage = function(event){
        $('#messageArea').append(event.data + '\n');
      }
      webSocket.onerror = function (event) {            console.log('webSocket连接异常。。。');
                                           }
    });
    //退出聊天室
    $('#leaveRoomBtn').click(function(){
      if(webSocket){
        //关闭连接
        webSocket.close();
      }
    });
    //发送消息
    $('#sendBtn').click(function(){
      var msg = $('#sendMessage').val();
      webSocket.send(msg);
      $('#sendMessage').val('');
    });
  });
</script>

相关文章
|
5月前
|
前端开发 网络协议 JavaScript
在Spring Boot中实现基于WebSocket的实时通信
在Spring Boot中实现基于WebSocket的实时通信
|
2月前
|
开发框架 前端开发 网络协议
Spring Boot结合Netty和WebSocket,实现后台向前端实时推送信息
【10月更文挑战第18天】 在现代互联网应用中,实时通信变得越来越重要。WebSocket作为一种在单个TCP连接上进行全双工通信的协议,为客户端和服务器之间的实时数据传输提供了一种高效的解决方案。Netty作为一个高性能、事件驱动的NIO框架,它基于Java NIO实现了异步和事件驱动的网络应用程序。Spring Boot是一个基于Spring框架的微服务开发框架,它提供了许多开箱即用的功能和简化配置的机制。本文将详细介绍如何使用Spring Boot集成Netty和WebSocket,实现后台向前端推送信息的功能。
340 1
|
2月前
|
前端开发 Java C++
RSocket vs WebSocket:Spring Boot 3.3 中的两大实时通信利器
本文介绍了在 Spring Boot 3.3 中使用 RSocket 和 WebSocket 实现实时通信的方法。RSocket 是一种高效的网络通信协议,支持多种通信模式,适用于微服务和流式数据传输。WebSocket 则是一种标准协议,支持全双工通信,适合实时数据更新场景。文章通过一个完整的示例,展示了如何配置项目、实现前后端交互和消息传递,并提供了详细的代码示例。通过这些技术,可以大幅提升系统的响应速度和处理效率。
|
4月前
|
开发框架 网络协议 Java
SpringBoot WebSocket大揭秘:实时通信、高效协作,一文让你彻底解锁!
【8月更文挑战第25天】本文介绍如何在SpringBoot项目中集成WebSocket以实现客户端与服务端的实时通信。首先概述了WebSocket的基本原理及其优势,接着详细阐述了集成步骤:添加依赖、配置WebSocket、定义WebSocket接口及进行测试。通过示例代码展示了整个过程,旨在帮助开发者更好地理解和应用这一技术。
327 1
|
4月前
|
小程序 Java API
springboot 微信小程序整合websocket,实现发送提醒消息
springboot 微信小程序整合websocket,实现发送提醒消息
|
4月前
|
JavaScript 前端开发 网络协议
WebSocket在Java Spring Boot+Vue框架中实现消息推送功能
在现代Web应用中,实时消息提醒是一项非常重要的功能,能够极大地提升用户体验。WebSocket作为一种在单个TCP连接上进行全双工通信的协议,为实现实时消息提醒提供了高效且低延迟的解决方案。本文将详细介绍如何在Java Spring Boot后端和Vue前端框架中利用WebSocket实现消息提醒功能。
186 0
|
5月前
|
监控 网络协议 Java
如何在Spring Boot中使用WebSocket
如何在Spring Boot中使用WebSocket
|
消息中间件 缓存 前端开发
Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)
Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)
2101 1
Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)
|
消息中间件 存储 负载均衡
Springboot 整合 WebSocket ,使用STOMP协议+Redis 解决负载场景问题(二)
Springboot 整合 WebSocket ,使用STOMP协议+Redis 解决负载场景问题(二)
1287 0
Springboot 整合 WebSocket ,使用STOMP协议+Redis 解决负载场景问题(二)
|
2月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
162 1