WebSocket使用

本文介绍了如何使用Spring框架和WebSocket技术构建一个实时聊天服务器,包括Maven依赖管理、WebSocket配置、Session管理以及消息发送与接收的处理方法。
摘要由CSDN通过智能技术生成

概要

提示:这里可以添加技术概要

WebSockets 是 Web 浏览器和服务器之间的双向、全双工、持久连接。建立 WebSocket 连接后,该连接将保持打开状态,直到客户端或服务器决定关闭此连接。

一个典型的用例可能是当一个应用涉及多个用户相互通信时,例如在聊天中。

整体架构流程

导入Maven依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-websocket</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-messaging</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>

加入Jackson依赖项–java对象向Json转换(非必须)

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.10.2</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId> 
    <version>2.10.2</version>
</dependency>

在spring中启用WebSocket
首先,我们启用 WebSocket 功能。为了做到这一点,我们需要向我们的应用程序添加一个配置,并用@EnableWebSocketMessageBroker注释这个类。

顾名思义,它支持由消息代理支持的 WebSocket 消息处理:

@Configuration
@EnableWebSocket
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpoint(){
        return new ServerEndpointExporter();
    }
}

实现聊天服务器

@Component
@ServerEndpoint("/chat")
public class ChatServer {
    /**
     * 声明一个连接会话池,用于保存所有的客户端连接会话对象
     */
    private final static ConcurrentHashMap<String, Session> SESSION_POOL = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session) throws IOException {
        // 判断客户对象是否存在
        String clientId = session.getQueryString();
        if (SESSION_POOL.containsKey(clientId)) {
            CloseReason closeReason = new CloseReason(CloseReason.CloseCodes.CANNOT_ACCEPT, "ID冲突,连接拒绝");
            session.getUserProperties().put("cr", closeReason);
            session.close();
            return;
        }
        // 将客户对象存储到池中
        SESSION_POOL.put(clientId, session);
        System.out.println("客户端(" + clientId + "):开启连接");
    }

    @OnMessage
    public String onMessage(String msg, Session session) throws IOException {
        // 解析消息 => ID::消息内容
        String[] msgArr = msg.split("::", 2);
        // 群发消息
        if ("all".equalsIgnoreCase(msgArr[0])) {
            for (Session one : SESSION_POOL.values()) {
                // 排除自己
                if (session == one) {
                    continue;
                }
                // 发送消息
                one.getBasicRemote().sendText(msgArr[1]);
            }
        } else { // 指定发送
            // 获取消息接收对象
            Session target = SESSION_POOL.get(msgArr[0]);
            if (target != null) {
                target.getBasicRemote().sendText(msgArr[1]);
            }
        }
        return session.getQueryString() + ":消息发送成功";
    }

    @OnClose
    public void onClose(Session session) {
        // 如果是拒绝关闭连接触发的关闭,就不做任何处理
        Object crObj = session.getUserProperties().get("cr");
        String clientId = session.getQueryString();
        if (crObj != null) {
            CloseReason cr = (CloseReason) crObj;
            if (cr.getCloseCode() == CloseReason.CloseCodes.CANNOT_ACCEPT) {
                System.out.println("拒绝客户端(" + clientId + "):关闭连接");
                return;
            }
        }
        // 从会话池中移除会话
        SESSION_POOL.remove(clientId);
        System.out.println("客户端(" + clientId + "):关闭连接");
    }

    @OnError
    public void onError(Session session, Throwable throwable) {
        System.out.println("客户端(" + session.getQueryString() + "):错误信息," + throwable.getMessage());
    }

    /**
     * 发送消息给客户端
     * @param id 消息变化
     * @param msg 消息内容
     */
    public void sendMessage(String id, Object msg) {
        // 群发
        if ("all".equalsIgnoreCase(id)) {
            for (Session one : SESSION_POOL.values()) {
                try {
                    one.getBasicRemote().sendText(JSONUtil.toJsonStr(msg));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return;
        }
        // 指定发送
        Session target = SESSION_POOL.get(id);
        if (target != null) {
            try {
                target.getBasicRemote().sendText(JSONUtil.toJsonStr(msg));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

@ServerEndpoint注解主要用于将一个类定义成一个WebSocket服务器端。这个注解的值将被用于监听用户连接的终端访问URL地址,客户端则可以通过这个URL来连接到WebSocket服务器端

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值