Springboot集成websocket实现简单聊天场景

本文详细介绍了如何使用SpringBoot框架和WebSocket技术创建一个支持点对点和群聊的聊天应用,包括依赖导入、配置类设置和服务器端关键方法的实现。

Springboot集成websocket实现聊天场景

本文展示用springboot集成websocket实现聊天场景。点对点聊天与群聊天。

导入依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
            <version>2.7.12</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.32</version>
        </dependency>

添加配置类

/**
 * WebSocket配置类
 *
 * @author yangfang2
 * @date 2024/2/22 10:28
 */
@Configuration
public class WebSocketConfig {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

编写服务端

  • WebSocketServer类

    /**
     * WebSocket 实现点对点聊天、群聊
     * <p>
     * 每个客户端连接,新生成一个ServerEndpoint实例
     *
     * @author yangfang2
     * @date 2024/2/22 10:26
     */
    @Slf4j
    @Component
    @ServerEndpoint("/chat/{sessionId}")
    public class WebSocketServer {
        /**
         * 静态变量(属于类) 记录当前在线连接数
         */
        private static final AtomicInteger onlineSessionClientCount = new AtomicInteger(0);
        /**
         * 静态变量(属于类) 存放在线的客户端
         */
        private static final Map<String, Session> onlineSessionClientMap = new ConcurrentHashMap<>();
    
        /**
         * 非静态变量(属于类实例) 当前连接的sessionId
         */
        private String curSessionId;
        /**
         * 非静态变量(属于类实例) 当前连接的session
         */
        private Session curSession;
    
        /**
         * 客户端连接成功调用此方法。由前端<code>new WebSocket</code>触发
         *
         * @param sessionId 每次页面建立连接时传入到服务端的id,比如用户id等。可以自定义。
         * @param session   与某个客户端的连接会话,需要通过它来给客户端发送消息
         */
        @OnOpen
        public void onOpen(@PathParam("sessionId") String sessionId, Session session) {
            this.curSessionId = sessionId;
            this.curSession = session;
    
            //放入map中
            onlineSessionClientMap.put(sessionId, session);
    
            //在线客户端数+1
            onlineSessionClientCount.incrementAndGet();
    
            //回复消息
            sendToOne(sessionId, "连接成功!");
            log.info("连接建立成功,当前在线数为:{} ==> 开始监听新连接: sessionId = {}", onlineSessionClientCount, sessionId);
        }
    
    
        /**
         * 服务端收到客户端消息后调用的方法。由前端<code>socket.send</code>触发
         * 当服务端执行toSession.getAsyncRemote().sendText(xxx)后,前端的socket.onmessage得到监听。
         *
         * @param data 服务端收到的消息
         */
        @OnMessage
        public void onMessage(String data) {
            log.info("服务端收到客户端消息 ==> sessionId = {}, data = {}", curSessionId, data);
            ChatVo chatVo = JSON.parseObject(data, ChatVo.class);
            String toSessionId = chatVo.getToSessionId();
            String toMessage = chatVo.getToMessage();
            if (StringUtils.isBlank(toSessionId)) {
                //群发
                sendToAll(toMessage);
            } else {
                //单发
                sendToOne(toSessionId, toMessage);
            }
        }
    
        /**
         * 发生错误调用的方法
         *
         * @param error 错误
         */
        @OnError
        public void onError(Throwable error) throws IOException {
            log.error("WebSocket发生错误,错误信息为:" + error.getMessage());
            //关闭连接
            onClose();
        }
    
        /**
         * 客户端关闭连接调用的方法。由前端<code>socket.close()</code>触发
         */
        @OnClose
        public void onClose() throws IOException {
            // 从 Map中移除
            onlineSessionClientMap.remove(curSessionId);
            //在线数减1
            onlineSessionClientCount.decrementAndGet();
            //断开连接
            curSession.close();
            log.info("连接关闭成功,当前在线数为:{} ==> 关闭该连接信息:sessionId = {}", onlineSessionClientCount, curSessionId);
        }
    
        /**
         * 发送消息给指定session
         *
         * @param toSessionId 接收的sessionId
         * @param message     接收的消息
         */
        private void sendToOne(String toSessionId, String message) {
            Session toSession = onlineSessionClientMap.get(toSessionId);
            if (Objects.isNull(toSession)) {
                log.error("服务端给客户端发送消息 ==> toSessionId = {} 不存在, message = {}", toSessionId, message);
                return;
            }
            // 异步发送
            log.info("服务端给客户端发送消息 ==> toSessionId = {}, message = {}", toSessionId, message);
            toSession.getAsyncRemote().sendText(curSessionId + ":" + message);
        }
    
        /**
         * 发送消息给所有session
         *
         * @param message 接收的消息
         */
        private void sendToAll(String message) {
            Set<String> allSessionIds = onlineSessionClientMap.keySet();
    
            allSessionIds
                    .stream()
                    //不给自己发
                    .filter(s -> !Objects.equals(s, curSessionId))
                    .forEach(toSessionId -> {
                        sendToOne(toSessionId, message);
                    });
        }
        
    }
    
  • ChatVo类

    @Getter
    @Setter
    public class ChatVo {
    
        /**
         * 发送的sessionId
         */
        private String toSessionId;
    
        /**
         * 发送的内容
         */
        private String toMessage;
    
    }
    

使用ApiFox测试

在这里插入图片描述

  • 新建三个连接

    用户1:ws://localhost:8080/chat/user1 并连接到服务端

    用户2:ws://localhost:8080/chat/user2 并连接到服务端

    用户3:ws://localhost:8080/chat/user3 并连接到服务端

在这里插入图片描述

私聊天

  • 用户1用户2发信息

在这里插入图片描述

  • 用户2收到用户1的消息

在这里插入图片描述

  • 用户2用户1回消息

在这里插入图片描述

  • 用户1收到用户2回的消息

在这里插入图片描述

群聊天

  • 用户3给所有连接到服务端用户发送消息

在这里插入图片描述

  • 用户1和用户2都收到用户3的消息

在这里插入图片描述
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值