SpringBoot中怎么使用WebSocket创建一个聊天室

发布时间:2021-06-15 14:16:14 作者:Leah
来源:亿速云 阅读:224

今天就跟大家聊聊有关SpringBoot中怎么使用WebSocket创建一个聊天室,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

一、什么是 WebSocket

1. 简介

WebSocket 协议是基于 TCP 的一种网络协议,它实现了浏览器与服务器全双工(Full-duplex)通信——允许服务器主动发送信息给客户端。

以前,很多网站为了实现推送技术,所用的技术都是轮询。轮询是在特定的的时间间隔(如每 1 秒),由浏览器对服务器发出 HTTP 请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断地向服务器发出请求,然而 HTTP 请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。

在这种情况下,HTML 5 定义了 WebSocket 协议,能更好得节省服务器资源和带宽,并且能够更实时地进行通讯。WebSocket 协议在 2008 年诞生,2011 年成为国际标准,现在主流的浏览器都已经支持。

它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

2. 优点

在连接创建后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较小。在不包含扩展的情况下,对于服务器到客户端的内容,此头部大小只有 2 至 10 字节(和数据包长度有关);对于客户端到服务器的内容,此头部还需要加上额外的 4 字节的掩码。相对于 HTTP 请求每次都要携带完整的头部,此项开销显著减少了。

由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。相对于 HTTP 请求需要等待客户端发起请求服务端才能响应,延迟明显更少;即使是和 Comet 等类似的长轮询比较,其也能在短时间内更多次地传递数据。

与 HTTP 不同的是,Websocket 需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息,而 HTTP 请求可能需要在每个请求都携带状态信息(如身份认证等)。

Websocket 定义了二进制帧,相对 HTTP,可以更轻松地处理二进制内容。 可以支持扩展。Websocket 定义了扩展,用户可以扩展协议、实现部分自定义的子协议。如部分浏览器支持压缩等。

相对于 HTTP 压缩,Websocket 在适当的扩展支持下,可以沿用之前内容的上下文,在传递类似的数据时,可以显著地提高压缩率。

WebSocket 在握手之后便直接基于 TCP 进行消息通信,但 WebSocket 只是 TCP 上面非常轻的一层,它仅仅将 TCP 的字节流转换成消息流(文本或二进制),至于怎么解析这些消息的内容完全依赖于应用本身。

因此为了协助 Client 与 Server 进行消息格式的协商,WebSocket 在握手的时候保留了一个子协议字段。

二、Stomp 和 WebSocket

STOMP 即 Simple(or Streaming)Text Orientated Messaging Protocol,简单(流)文本定向消息协议,它提供了一个可互操作的连接格式,允许 STOMP 客户端与任意 STOMP 消息代理(Broker)进行交互。STOMP 协议由于设计简单,易于开发客户端,因此在多种语言和多种平台上得到了广泛的应用。

STOMP 协议并不是为 Websocket 设计的,它是属于消息队列的一种协议,它和 Amqp、Jms 平级。只不过由于它的简单性恰巧可以用于定义 Websocket 的消息体格式。可以这么理解,Websocket 结合 Stomp 子协议段,来让客户端和服务器在通信上定义的消息内容达成一致。

STOMP 协议分为客户端和服务端,具体如下。

1. STOMP 服务端

STOMP 服务端被设计为客户端可以向其发送消息的一组目标地址。STOMP 协议并没有规定目标地址的格式,它由使用协议的应用自己来定义。例如,/topic/a、/queue/a、queue-a 对于 STOMP 协议来说都是正确的。应用可以自己规定不同的格式以此来表明不同格式代表的含义。比如应用自己可以定义以 /topic 打头的为发布订阅模式,消息会被所有消费者客户端收到,以 /user 开头的为点对点模式,只会被一个消费者客户端收到。

2. STOMP 客户端

3. STOMP 帧结构

COMMAND

header1:value1

header2:value2

Body^@

其中,^@ 表示行结束符。

SEND
destination:/broker/roomId/1
content-length:57

{“type":"OUT","content":"ossxxxxx-wq-yyyyyyyy"}

更多 STOMP 协议细节,可以参考 STOMP官网

三、WebSocket 事件

ws://example.com/wsapi
wss://secure.example.com/
事件事件处理程序描述
openSokcket onopen连接建立时触发
messageSokcket onmessage客户端接收服务端数据时触发
errorSokcket onerror通讯发生错误时触发
closeSokcket onclose链接关闭时触发

下面是一个页面使用 Websocket 的示例:

var ws = new WebSocket("ws://localhost:8080");

ws.onopen = function(evt) { 
  console.log("Connection open ..."); 
  ws.send("Hello WebSockets!");
};

ws.onmessage = function(evt) {
  console.log( "Received Message: " + evt.data);
  ws.close();
};

ws.onclose = function(evt) {
  console.log("Connection closed.");
};

四、Websocket 聊天室

1. 页面开发

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>chat room websocket</title>
    <link rel="stylesheet" href="bootstrap.min.css">
    <script src="jquery-3.2.1.min.js" ></script>
</head>
<body class="container" >
<div class="form-group" ></br>
    <h6>聊天室</h6>
    <textarea id="message_content"  class="form-control"  readonly="readonly" cols="50" rows="10"></textarea>
</div>
<div class="form-group" >
    <label for="in_user_name">用户姓名 &nbsp;</label>
    <input id="in_user_name" value="" class="form-control" /></br>
    <button id="user_join" class="btn btn-success" >加入聊天室</button>
    <button id="user_exit" class="btn btn-warning" >离开聊天室</button>
</div>
<div class="form-group" >
    <label for="in_room_msg" >群发消息 &nbsp;</label>
    <input id="in_room_msg" value="" class="form-control" /></br>
    <button id="user_send_all" class="btn btn-info" >发送消息</button>
</div>
</body>
</html>

SpringBoot中怎么使用WebSocket创建一个聊天室

<script type="text/javascript">
    $(document).ready(function(){
        var urlPrefix ='ws://localhost:8080/chat-room/';
        var ws = null;
        $('#user_join').click(function(){
            var username = $('#in_user_name').val();
            var url = urlPrefix + username;
            ws = new WebSocket(url);
            ws.onopen = function () {
                console.log("建立 websocket 连接...");
            };
            ws.onmessage = function(event){
                //服务端发送的消息
                $('#message_content').append(event.data+'\n');
            };
            ws.onclose = function(){
                $('#message_content').append('用户['+username+'] 已经离开聊天室!');
                console.log("关闭 websocket 连接...");
            }
        });
        //客户端发送消息到服务器
        $('#user_send_all').click(function(){
            var msg = $('#in_room_msg').val();
            if(ws){
                ws.send(msg);
            }
        });
        // 退出聊天室
        $('#user_exit').click(function(){
            if(ws){
                ws.close();
            }
        });
    })
</script>

2. 服务端开发

- 引入依赖
<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>

主要添加 Web 和 Websocket 组件。

- 启动类

启动类需要添加 @EnableWebSocket 开启 WebSocket 功能。

@EnableWebSocket
@SpringBootApplication
public class WebSocketApplication {

    public static void main(String[] args) {
        SpringApplication.run(WebSocketApplication.class, args);
    }

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}
- 请求接收
public static final Map<String, Session> ONLINE_USER_SESSIONS = new ConcurrentHashMap<>();
public 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) {
        logger.error("sendMessage IOException ",e);
    }
}

聊天室的消息是所有在线用户可见,因此每次消息的触发实际上是遍历所有在线用户,给每个在线用户发送消息。

public static void sendMessageAll(String message) {
    ONLINE_USER_SESSIONS.forEach((sessionId, session) -> sendMessage(session, message));
}
import static com.neo.utils.WebSocketUtils.ONLINE_USER_SESSIONS;
import static com.neo.utils.WebSocketUtils.sendMessageAll;
@RestController
@ServerEndpoint("/chat-room/{username}")
public class ChatRoomServerEndpoint {
}
@OnOpen
public void openSession(@PathParam("username") String username, Session session) {
    ONLINE_USER_SESSIONS.put(username, session);
    String message = "欢迎用户[" + username + "] 来到聊天室!";
    logger.info("用户登录:"+message);
    sendMessageAll(message);
}
@OnMessage
public void onMessage(@PathParam("username") String username, String message) {
    logger.info("发送消息:"+message);
    sendMessageAll("用户[" + username + "] : " + message);
}
@OnClose
public void onClose(@PathParam("username") String username, Session session) {
    //当前的Session 移除
    ONLINE_USER_SESSIONS.remove(username);
    //并且通知其他人当前用户已经离开聊天室了
    sendMessageAll("用户[" + username + "] 已经离开聊天室了!");
    try {
        session.close();
    } catch (IOException e) {
        logger.error("onClose error",e);
    }
}
@OnError
public void onError(Session session, Throwable throwable) {
    try {
        session.close();
    } catch (IOException e) {
        logger.error("onError excepiton",e);
    }
    logger.info("Throwable msg "+throwable.getMessage());
}
- 测试
小王:你是谁?
小张:你猜
小王:我猜好了!
小张:你猜的什么
小王:你猜?
小张:…

小张离开聊天室…

SpringBoot中怎么使用WebSocket创建一个聊天室

看完上述内容,你们对SpringBoot中怎么使用WebSocket创建一个聊天室有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注亿速云行业资讯频道,感谢大家的支持。

推荐阅读:
  1. 搭建Websocket简易聊天室
  2. 基于SpringBoot和WebSocket实现简易聊天室

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

websocket springboot

上一篇:jquery中layui弹出层怎么用

下一篇:Java中怎么实现字符串和二进制数组转换

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》