SpringBoot2.0集成WebSocket

        
        
            org.springframework.boot
            spring-boot-starter-websocket
        

新建配置类

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * @Description 开启springboot对websocket的支持
 * @Author WangKun
 * @Date 2023/8/14 17:21
 * @Version
 */
@ConditionalOnProperty(name = "spring.profiles.active", havingValue = "dev")
@Configuration
public class WebSocketConfig{

    /**
     * @Description 注入一个ServerEndpointExporter, 会自动注册使用@ServerEndpoint注解
      * @param
     * @Throws
     * @Return org.springframework.web.socket.server.standard.ServerEndpointExporter
     * @Date 2023-08-14 17:26:31
     * @Author WangKun
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}
@ConditionalOnProperty(name = "spring.profiles.active", havingValue = "dev")

这个注解需要打上声明是开发环境,否则在tomcat部署中会报错

新建服务类

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Description websocket服务,不考虑分组
 * @Author WangKun
 * @Date 2023/8/14 17:29
 * @Version
 */
@ConditionalOnClass(value = WebSocketConfig.class)
@ServerEndpoint("/websocket/{userId}")
@Component
@Slf4j
public class WebSocket {
     //在线计数器
    private static int onlineCount = 0;
    //存放每个客户端对应的WebSocket对象。
    private static final ConcurrentHashMap WEB_SOCKET_MAP = new ConcurrentHashMap<>();

    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;
    private String userId;

    /**
     * @param
     * @Description 在线数
     * @Throws
     * @Return int
     * @Date 2023-08-14 17:47:19
     * @Author WangKun
     */
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    /**
     * @param
     * @Description 在线数加1
     * @Throws
     * @Return void
     * @Date 2023-08-14 17:47:32
     * @Author WangKun
     */
    public static synchronized void addOnlineCount() {
        WebSocket.onlineCount++;
    }

    /**
     * @param
     * @Description 在线数减1
     * @Throws
     * @Return void
     * @Date 2023-08-14 17:47:47
     * @Author WangKun
     */
    public static synchronized void subOnlineCount() {
        WebSocket.onlineCount--;
    }

    /**
     * @param session
     * @param userId
     * @Description 建立连接
     * @Throws
     * @Return void
     * @Date 2023-08-14 17:52:08
     * @Author WangKun
     */
    @OnOpen
    public void onOpen(final Session session, @PathParam("userId") String userId) {
        this.session = session;
        this.userId = userId;
        // 防止前端刷新重连用户重复,存在计数器不累加
        if (WEB_SOCKET_MAP.containsKey(userId)) {
            WEB_SOCKET_MAP.remove(userId);
            WEB_SOCKET_MAP.put(userId, this);
        } else {
            WEB_SOCKET_MAP.put(userId, this);
            addOnlineCount();
        }
        sendMessage(String.valueOf(ResponseCode.CONNECT_SUCCESS.getCode())); //自定义成功返回码
        log.info("用户--->{} 连接成功,当前在线人数为--->{}", userId, getOnlineCount());
    }

    /**
     * @param message
     * @Description 向客户端发送消息 session.getBasicRemote()与session.getAsyncRemote()的区别
     * @Throws
     * @Return void
     * @Date 2023-08-14 17:51:07
     * @Author WangKun
     */
    public synchronized void sendMessage(String message) {
        try {
            // 加锁避免阻塞
            this.session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            log.error("向客户端发送消息--->{}", e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

    /**
     * @param
     * @Description 关闭连接
     * @Throws
     * @Return void
     * @Date 2023-08-14 17:52:30
     * @Author WangKun
     */
    @OnClose
    public void onClose(Session session) {
        if (!WEB_SOCKET_MAP.isEmpty()  && WEB_SOCKET_MAP.containsKey(userId)) {
            this.session = session;
            WEB_SOCKET_MAP.remove(userId);
            subOnlineCount();
            log.info("用户--->{} 关闭连接!当前在线人数为--->{}", userId, getOnlineCount());
        }
    }

    /**
     * @param message
     * @param session
     * @Description 收到客户端消息
     * @Throws
     * @Return void
     * @Date 2023-08-15 10:54:55
     * @Author WangKun
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        //这一块可以操作数据,比如存到数据

        //判断心跳是否存活, 防止心跳自动断开,再重连
        if ("ping".equalsIgnoreCase(message) && !WEB_SOCKET_MAP.isEmpty() && WEB_SOCKET_MAP.containsKey(userId)) {
            WEB_SOCKET_MAP.get(userId).sendMessage("pong");
        }
        log.info("收到来自客户端用户:{} 消息:--->{}", userId, message);
    }

    /**
     * @param session
     * @param error
     * @Description 发生错误时
     * @Throws
     * @Return void
     * @Date 2023-08-15 10:55:27
     * @Author WangKun
     */
    @OnError
    public void onError(Session session, Throwable error) {
        if (!WEB_SOCKET_MAP.isEmpty() && WEB_SOCKET_MAP.containsKey(userId)) {
            WEB_SOCKET_MAP.remove(userId);
            subOnlineCount();
            log.error("用户--->{} 错误!" + userId, "原因--->{}" + error.getMessage());
            error.printStackTrace();
        }
    }

    /**
     * @param userId
     * @param message
     * @Description 通过userId向客户端发送消息(指定用户发送)
     * @Throws
     * @Return void
     * @Date 2023-08-14 18:01:35
     * @Author WangKun
     */
    public static void sendTextMessageByUserId(String userId, String message) {
        log.info("服务端发送消息到用户{},消息:{}", userId, message);
        if (!WEB_SOCKET_MAP.isEmpty() && StringUtils.isNotBlank(userId) && WEB_SOCKET_MAP.containsKey(userId)) {
            WEB_SOCKET_MAP.get(userId).sendMessage(message);
        } else {
            log.error("用户{}不在线", userId);
        }
    }

    /**
     * @param message
     * @Description 群发自定义消息
     * @Throws
     * @Return void
     * @Date 2023-08-14 18:03:38
     * @Author WangKun
     */
    public static void sendTextMessage(String message) {
        // 如果在线一个就广播
        log.info("广播数据到当前在线人,人数:{}", getOnlineCount());
        if (getOnlineCount() > 0 && !WEB_SOCKET_MAP.isEmpty()) {
            for (String item : WEB_SOCKET_MAP.keySet()) {
                WEB_SOCKET_MAP.get(item).sendMessage(message);
                log.info("服务端发送消息到用户{},消息:{}", item, message);
            }
        }
    }
}

@ConditionalOnClass(value = WebSocketConfig.class)

指定使用自定义配置文件

你可能感兴趣的:(websocket,网络协议,网络)