【烦人的WebSocket】基于spring boot 版本的 web socket 后端代码实践

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

创建Spring boot项目,添加依赖

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

WebSocketConfig,启用websocket支持

package com.example.websocket.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * WebSocketConfig
 *
 * @author hcf
 * @date 2022/1/6 17:59
 */
@Configuration
public class WebSocketConfig {

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

WebSocketServer
websocket 和 socket 类似,有客户端和服务端,客户端就是pc、app等,服务端就是后端。因为 WebSocket 是类似客户端服务端的形式(采用ws协议)

所以 WebSocketServer 其实就相当于一个 ws 协议的 Controller,直接使用注解@ServerEndpoint 和 @Component启用即可

package com.example.websocket.server;

import com.example.websocket.util.WebSocketUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Date;
import java.util.Objects;

/**
 * WebSocketServer
 *
 * @author hcf
 * @date 2022/1/6 17:57
 */
@Component
@ServerEndpoint(value = "/websocket/{appNo}")
public class WebSocketServer {

    private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketServer.class);

    @OnOpen
    public void onOpen(@PathParam("appNo") String appNo, Session session) {
        LOGGER.info("用户【{}】于 {} 时间,与服务器建立 websocket 连接!", appNo, new Date());
        WebSocketUtil.addSession(appNo, session);
    }

    @OnClose
    public void onClose(@PathParam("appNo") String appNo) {
        LOGGER.info("用户【{}】于 {} 时间,与服务器断开 websocket 连接!", appNo, new Date());
        WebSocketUtil.remoteSession(appNo);
    }

    @OnMessage
    public void onMessage(@PathParam("appNo") String appNo, String message) {
        LOGGER.info("服务器于 {} 时间,对用户【{}】发送消息,消息内容:{}", new Date(), appNo, message);
        Session session = WebSocketUtil.ONLINE_SESSION.get(appNo);
        if (Objects.isNull(session)) {
            LOGGER.info("服务器和用户【{}】之间的链接已断开", appNo);
            return;
        }
        Boolean success = WebSocketUtil.sendMessage(appNo, session, message);
        LOGGER.info("客户端向服务端发送消息结果:{}", success);
    }

    @OnError
    public void onError(Session session, Throwable throwable) {
        LOGGER.error("服务器和用户之间的链接产生异常,异常原因:{}", throwable.getMessage(), throwable);
        try {
            session.close();
        } catch (IOException e) {
            LOGGER.error("断开服务器和用户之间的链接产生异常,异常原因:{}", e.getMessage(), e);
        }
    }
}
package com.example.websocket.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.websocket.Session;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * WebSocketUtil
 *
 * @author hcf
 * @date 2022/1/6 18:01
 */
public class WebSocketUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketUtil.class);

    public static final Map<String, Session> ONLINE_SESSION = new ConcurrentHashMap<>();

    public static void addSession(String userKey, Session session) {
        ONLINE_SESSION.put(userKey, session);
    }

    public static void remoteSession(String userKey) {
        ONLINE_SESSION.remove(userKey);
    }


    public static Boolean sendMessage(String appNo, Session session, String message) {
        // getAsyncRemote() 和 getBasicRemote() 异步与同步
        Future<Void> future = session.getAsyncRemote().sendText(message);
        try {
            future.get(3, TimeUnit.SECONDS);
        } catch (Exception e) {
            LOGGER.error("服务器发送消息给客户端 【{}】 下的用户【{}】,传输失败。消息内容为:{},", session.getId(), appNo, message);
            return false;
        }
        LOGGER.info("服务器发送消息给客户端 【{}】 下的用户【{}】,传输结果为:{}。消息内容为:{}", session.getId(), appNo, message, future.isDone());
        return future.isDone();
    }
}

启动项目进行测试

可以使用 http://www.websocket-test.com/ 测试网址

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值