二十八、Springboot整合WebSocket(长连接),聊天室案例

(一)WebSocket简介
  WebSocket是一种通讯协议,通过单个TCP连接提供完全多工通讯管道。大白话就是:WebSocket协议相对于Http协议来说,它能在一段时间内一直保持连接,而Http协议是三次握手后就断开连接。WebSocket经常用于聊天室这种实时通讯场景。

  WebSocket协议地址相对于Http协议地址来说,Schema部分变了:Http地址:http://host:port/… ,而WebSocke地址:ws://host:port/…

(二)WebSocke API
  相关术语:

  • 端点(Endpoint)
  • 连接(Connection)
  • 对点(Peer)
  • 会话(Session)
  • 客户端端点、服务器端点

1、端点生命周期
(1)打开连接
  Endpoint#onOpen(Session,EndpointConfig) ------编程
  @OnOpen ------注解
(2)关闭连接
  Endpoint#onClose(Session,CloseReason)
  @OnClose
(3)错误
  Endpoint#onError(Session,Throwable)
  @OnError
(4)发送消息
  @OnMessage(PS:无对应编程方法)

2、会话(Sessions)
(1)API:javax.websocket.Session
(2)接收消息:javax.websocket.MessageHandler
(3)发送消息:javax.websocket.RemoteEndpoint.Basic

3、配置(Configuration)
(1)服务端配置(javax.websocket.ServerEndpointConfig)

  • URI 映射
  • 子协议协商
  • 扩展点修改
  • Origin检测
  • 握手修改
  • 自定义端点创建
    (2)客户端配置(javax.websocket.ClientEndpointConfig)
  • 子协议
  • 扩展点
  • 客户端配置修改

3、部署(Deployment)(PS:这里只是介绍原理,并不需要我们手动去部署)
(1)应用部署到WEB容器

  • WEB-INF/classes
  • WEB-INF/lib
    (2)应用部署到独立WebSocket服务器
  • javax.websocket.server.ServerApplicationConfig
    (3)编程方式(Springboot中的方式)
  • javax.websocket.server.ServerContainer

(三)Springboot整合WebSocket及其聊天室案例

1、添加依赖

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

2、自定义端点

/**
 * 聊天室服务端
 * 标注为端点:@ServerEndpoint,其中"/chat-room/{username}"为访问路径
 */
@ServerEndpoint("/chat-room/{username}")
public class ChatRoomServerEndpoint {
    /**
     * 存储所有存活的用户
     * 注意1:高并发问题
     * 注意2:livingSessions必须是全局变量(保证全局就他一个变量,否则每次调用都会被刷新)
     * 注意3:很难保证,用户在退出聊天室时,正确调用了WebSocket.close(),也就是调用后端的onClose()方法,这样
     *        就可能会导致Session无法被有效清除,livingSessions会越来越大,服务器压力也会越来越大。
     *        所以,我们需要周期性的去检查用户是否还处于活跃状态,不活跃的,移除该用户的session
     */
    private static Map<String , Session> livingSessions = new ConcurrentHashMap<>();

    /**
     * 前端一旦启用WebSocket,机会调用@OnOpen注解标注的方法
     * @param username 路径参数
     * @param session 会话,每个访问对象都会有一个单独的会话
     */
    @OnOpen
    public void openSession(@PathParam("username") String username, Session session){
        livingSessions.put(session.getId(), session);
        sendTextAll("欢迎用户【" + username +"】来到聊天室!");
    }

    /**
     * 服务端发送消息给前端时调用
     * @param username   路径参数
     * @param session    会话,每个访问对象都会有一个单独的会话
     * @param message    待发送的消息
     */
    @OnMessage
    public void onMessage(@PathParam("username") String username, Session session, String message){
        sendTextAll("用户【" + username + "】:" + message);
    }

    /**
     * 客户端关闭WebSocket连接时,调用标注@OnClose的方法
     * @param username   路径参数
     * @param session    会话,每个访问对象都会有一个单独的会话
     */
    @OnClose
    public void onClose(@PathParam("username") String username, Session session){
        //将当前用户移除
        livingSessions.remove(session.getId());
        //给所有存活的用户发送消息
        sendTextAll("用户【" + username +"】离开聊天室!");
    }

    /**
     * 向指定Session(用户)发送message
     */
    private void sendText(Session session, String message){
        //发送消息对象
        RemoteEndpoint.Basic basicRemote = session.getBasicRemote();
        try {
            //发送消息
            basicRemote.sendText(message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 遍历所有存活的用户,并发送消息(PS:就是广播消息)
     */
    private void sendTextAll(String message){
        //lambda表达式
        livingSessions.forEach((sessionId, session) -> sendText(session, message));
    }
}

3、改造启动接口,激活WebSocket,并注册WebSocket相关类和端点

/**
 * 激活WebSocket:@EnableWebSocket
 */
@SpringBootApplication
@EnableWebSocket
public class WebsocketApplication {

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

	/**
	 * 注册 ServerEndpointExporter Bean对象(因为Springboot没有自动注册,所以得手动注册)
	 */
	@Bean
	public ServerEndpointExporter serverEndpointExporter(){
		return new ServerEndpointExporter();
	}

	/**
	 * 注册 端点对象
	 */
	@Bean
	public ChatRoomServerEndpoint chatRoomServerEndpoint(){
		return new ChatRoomServerEndpoint();
	}
}

4、前端页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>聊天室</title>
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
    <script src="https://cdn.jsdelivr.net/sockjs/1.0.0/sockjs.min.js"></script>
    <script>
        $(document).ready(function () {
            var urlPrefix = "ws://localhost:8080/chat-room/";
            var ws = null;
            //加入聊天室
            $('#bt_join').click(function () {
                var username = $('#username').val();
                //这一步,会调用服务端的@OnOpen注解标注的方法
                ws = new WebSocket(urlPrefix + username);
                ws.onmessage = function (event) {
                    //接收服务端返回给前端的消息
                    $('#text_chat_content').append(event.data + "\n");
                };
                ws.onclose = function () {
                    /**
                     * 问题:为什么这里不是接收服务端的提示信息,而是当前用户自己定义消息?
                     * 原因:当用户离开聊天室时,在遍历存活用户时,当前用户已经不在存活用户集合中,
                     *       所以当前用户的提示信息不能由服务端发送,而得由自己去定义!
                     */
                    $('#text_chat_content').append("用户【" + username +"】离开聊天室!" + "\n");
                };
            });
            //发送消息
            $('#bt_send').click(function () {
                if (ws){
                    ws.send($('#in_msg').val());
                }
            });
            //离开聊天室
            $('#bt_left').click(function () {
                if (ws){
                    ws.close();
                }
            });
        })
    </script>
</head>
<body>
    聊天消息内容:<br/>
    <textarea id="text_chat_content" readonly="readonly" cols="60" rows="20"></textarea>
<br/>
用户:<input id="username" type="text"/>
<button id="bt_join">加入聊天室</button>
<button id="bt_left">离开聊天室</button>
<br/>
输入框:<input id="in_msg" type="text"/>
<button id="bt_send">发送消息</button>
</body>
</html>
Spring Boot是一个开源框架,通过简化Java应用程序的开发过程,提供一种快速构建可独立运行的应用程序的方式。WebSocket是一种实时双向通信的协议,可以在客户端和服务器之间建立持久性连接,实现实时的信息交互。 为了实现Spring Boot整合WebSocket聊天室功能,我们可以按照以下步骤进行: 1. 导入相关依赖:在项目的构建文件中(如pom.xml文件)添加WebSocket和Spring Web的依赖。 2. 创建WebSocket配置类:创建一个类,用于配置WebSocket的相关参数和处理器。在该类上使用`@Configuration`和`@EnableWebSocket`注解,开启WebSocket相关功能。 3. 实现WebSocket处理器:创建一个类,继承自`TextWebSocketHandler`,重写父类的方法来处理消息的接收和发送。可以根据业务需求来处理不同的消息。 4. 实现WebSocket拦截器:创建一个类,实现`HandshakeInterceptor`接口,用于在WebSocket连接建立之前或之后执行一些操作,如校验用户身份等。 5. 配置WebSocket端点:在WebSocket配置类中,重写`registerWebSocketHandlers`方法,配置WebSocket的端点和拦截器。 6. 创建聊天室页面:创建一个前端页面,用于展示聊天室界面,并与WebSocket服务器建立连接。可以使用JavaScript来处理消息的发送和接收。 7. 部署和启动应用程序:将应用程序部署到服务器上,并启动应用程序。通过访问聊天室页面,可以进行实时的聊天。 通过以上步骤,就可以实现Spring Boot整合WebSocket聊天室功能。在聊天室中,用户可以实时发送和接收消息,并且可以处理不同类型的消息,如文本、图片等。这种实时通信的功能可以应用于在线客服、多人协作等场景,提供更好的用户体验。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值