自定义springboot组件--实现平台的websocket统一整合

一 基本思路

基于websocketHandler实现平台websocket的统一封装

在这里插入图片描述

  • 客户端发起长链接时会携带token凭证,服务端根据token获得用户基本信息,在与服务端握手前,先通过UserHandshakeInterceptor拦截请求,将用户的基本信息保存到当前会话中
  • 通过MapSessionHandlerDecorator在建立连接前后通过SessionKeyGenerate解析用户基本信息和会话id同步数据到内存和内存中数据的释放,用服务端想客户端推送消息
  • 通过CustomTextWebSocketHandler处理客户端的推送过来的消息,首先,会更具当前消息的类型选择相应的文本解析器
  • 普通文本解析器,打印当前数据,不做数据的深加工
  • json文本解析器根据当前type获得相应的消息处理器,执行自定义业务逻辑

服务端消息推送

在这里插入图片描述
服务端会更具当前项目的性质选择不同的消息发射器:

  • local:单体项目,直接推送
  • redis:分布式集群,通过redis的发布订阅实现消息的转发,分布式集群中监听到消息推送实现后判断当前服务中是否包含相应的session在推送到数据的客户端

二 核心代码实现

2.1 消息处理

定义相应配置约束

@Data
@ConfigurationProperties(prefix = XlcpWebSocketProperties.PRE_FIX)
public class XlcpWebSocketProperties {
    public static final String PRE_FIX = "config.websocket";
    /**
     * websocket请求路径
     */
    private Set<String> paths = new HashSet<String>(Arrays.asList("/ws/info"));


    private String allowedOrigins = "*";

    /**
     * 是否开启心跳
     */
    private Boolean heart=true;

    /**
     * <b>消息推送类型</b>
     * <ul>
     *     <li>local:单机部署时使用</li>
     *     <li>redis:分布式集群时使用</li>
     *     <li>custom:自定义消息发送器</li>
     * </ul>
     */
    private String distributorType = DistributorType.REDIS;

}

握手前将用户信息保存到当前会话中

@Slf4j
public class UserHandshakeInterceptor implements HandshakeInterceptor {
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
        //获得用户的基础信息 保存到当前会话的信息中去
        XlcpUser xlcpUser = SecurityUtils.getUser();
        attributes.put(CommonConstants.WEBSOCKET_USER_INFO,xlcpUser);
        return true;
    }

    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
        log.debug("握手后置处理....");
    }
}

用户基础信息,会话等的处理

public class MapSessionHandlerDecorator extends WebSocketHandlerDecorator {
    private final SessionKeyGenerate sessionKeyGenerate;

    public MapSessionHandlerDecorator(WebSocketHandler delegate, SessionKeyGenerate sessionKeyGenerate) {
        super(delegate);
        this.sessionKeyGenerate=sessionKeyGenerate;
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        String sessionKey = sessionKeyGenerate.sessionKey(session);
        if (StrUtil.isNotBlank(sessionKey)){
            MapSessionHolder.addSession(sessionKey,session);
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        String sessionKey = sessionKeyGenerate.sessionKey(session);
        if (StrUtil.isNotBlank(sessionKey)){
            MapSessionHolder.removeSession(sessionKey);
        }
    }
}

public interface SessionKeyGenerate {

    /**
     * 构造websocketSession的存储key值
     * @param webSocketSession
     * @return
     */
    String sessionKey(WebSocketSession webSocketSession);
}

public class WebSocketSessionKeyGenerate implements SessionKeyGenerate {

    @Override
    public String sessionKey(WebSocketSession webSocketSession) {
        Map<String, Object> attributes = webSocketSession.getAttributes();
        Object obj = attributes.get(CommonConstants.WEBSOCKET_USER_INFO);
        if (obj instanceof XlcpUser){
            XlcpUser xlcpUser = (XlcpUser) obj;
            return String.format("%d%s%s",xlcpUser.getId(), StrPool.COLON,webSocketSession.getId());
        }
        return null;
    }
}

public class MapSessionHolder {
    public static Map<String, WebSocketSession> MAP_SESSION = new ConcurrentHashMap<>();

    public static void addSession(String sessionKey,WebSocketSession webSocketSession){
        MAP_SESSION.put(sessionKey,webSocketSession);
    }

    public static void removeSession(String sessionKey){
        MAP_SESSION.remove(sessionKey);
    }


    public static Set<WebSocketSession> getWebSocketSessionBySessionKey(Object sessionkey){
        HashSet<WebSocketSession> webSocketSessions = new HashSet<>();
        MAP_SESSION.forEach((sessionKey,websocketSession)->{
            if (StrUtil.startWith(sessionKey, Convert.toStr(sessionKey))){
                webSocketSessions.add(websocketSession);
            }
        });
        return webSocketSessions;
    }

}

核心handler 处理客户端消息

@Slf4j
public class CustomTextWebSocketHandler extends TextWebSocketHandler {

    private final PlanTextMessageHandler planTextMessageHandler;

    public CustomTextWebSocketHandler(PlanTextMessageHandler planTextMessageHandler){
        this.planTextMessageHandler=planTextMessageHandler;
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        if (message.getPayloadLength()==0){
            return;
        }
        String messageText = message.getPayload();
        // 判断是否为json数据处理文本
        if (JSONUtil.isTypeJSON(messageText)){
            boolean checkResult = JsonCheckUtil.checkJson(messageText);
            if (!checkResult){
                checkErrorMessage(session);
                return;
            }
            /**
             * json文本处理器
             */
            JSONObject jsonObject = JSONUtil.parseObj(messageText);
            String type = (String) jsonObject.get(AbstractJsonWebSocketMessage.TYPE_FIELD);
            if (StrUtil.isNotBlank(type)){
                JsonWebSocketMessageHandler jsonWebSocketMessageHandler = JsonWebSocketMessageHandlerRegister.MESSAGE_HANDLERS.get(type);
                if (jsonWebSocketMessageHandler==null){
                    String jsonWebSocketMessage = JsonWebSocketMessageBuilder.getInstance()
                            .msg("没有匹配到相对应的type类型")
                            .type(JsonMessageType.ERROR)
                            .build();
                    WebSocketMessageSender.sendMessage(session,jsonWebSocketMessage);
                    return;
                }
                Class messageClass = jsonWebSocketMessageHandler.getMessageClass();
                Object jsonMessage = JSONUtil.toBean(messageText, messageClass);
                jsonWebSocketMessageHandler.handler((AbstractJsonWebSocketMessage) jsonMessage,session);
            }else {
                checkErrorMessage(session);
            }
        }else {
            // 普通文本处理器
            planTextMessageHandler.handler(session,messageText);
        }
    }

    private void checkErrorMessage(WebSocketSession session) {
        String jsonWebSocketMessage = JsonWebSocketMessageBuilder.getInstance()
                .msg("json 数据格式错误!")
                .type(JsonMessageType.ERROR)
                .build();
        WebSocketMessageSender.sendMessage(session,jsonWebSocketMessage);
    }


}

public class JsonWebSocketMessageBuilder {
    @Getter
    private String type;

    @Getter
    private String msg;

    @Getter
    private Object data;

    public static JsonWebSocketMessageBuilder getInstance(){
        return new JsonWebSocketMessageBuilder();
    }

    public JsonWebSocketMessageBuilder type(JsonMessageType jsonMessageType){
        this.type=jsonMessageType.getType();
        return this;
    }

    public JsonWebSocketMessageBuilder msg(String msg){
        this.msg=msg;
        return this;
    }

    public JsonWebSocketMessageBuilder data(Object data){
        this.data=data;
        return this;
    }

    public String build(){
        Assert.notBlank(this.type);
        return JSONUtil.toJsonStr(this);
    }
}

public enum JsonMessageType {
    PONG("pong","pong消息"),
    ERROR("error","错误"),
    PING("ping","心跳");

    @Getter
    private String type;
    private String describe;

    JsonMessageType(String type,String describe){
        this.type=type;
        this.describe=describe;
    }

}

@Slf4j
public class CustomPlanTextMessageHandler implements PlanTextMessageHandler{
    @Override
    public void handler(WebSocketSession session, String message) {
        log.info("messageId [{}] message [{}]",session.getId(),message);
    }
}

消息处理器

public interface JsonWebSocketMessageHandler<T extends AbstractJsonWebSocketMessage> {
    /**
     * 处理消息
     * @param t
     * @param webSocketSession
     */
    void handler(T t, WebSocketSession webSocketSession);


    /**
     * 获得当前处理器处理的消息的class
     * @return
     */
    Class<T> getMessageClass();

    /**
     * 当前消息处理器处理的类型
     * @return
     */
    String getType();

}

public abstract class AbstractJsonWebSocketMessage implements JsonWebSocketMessage {
    public static final String TYPE_FIELD = "type";

    @Getter
    public String type;

    public AbstractJsonWebSocketMessage(String type){
        this.type=type;
    }

    @Override
    public String getType() {
        return this.type;
    }
}

public interface JsonWebSocketMessage {
    /**
     * 当前消息的处理类型
     * @return
     */
    String getType();
}

心跳消息处理器

public class PingJsonWebSocketMessageHandler implements JsonWebSocketMessageHandler<PingJsonWebSocketMessage>{
    @Override
    public void handler(PingJsonWebSocketMessage pingJsonWebSocketMessage, WebSocketSession webSocketSession) {
        // 接受到客户端的心跳 返回一个pong消息给客户端
        String jsonMessage = JsonWebSocketMessageBuilder.getInstance().type(JsonMessageType.PONG).build();
        WebSocketMessageSender.sendMessage(webSocketSession, jsonMessage);
    }

    @Override
    public Class<PingJsonWebSocketMessage> getMessageClass() {
        return PingJsonWebSocketMessage.class;
    }

    @Override
    public String getType() {
        return JsonMessageType.PING.getType();
    }
}

public class PingJsonWebSocketMessage extends AbstractJsonWebSocketMessage{
    public PingJsonWebSocketMessage(String type) {
        super(JsonMessageType.PING.getType());
    }
}

2.2 消息分发

定义消息分发的基础接口,及消息基础定义

public interface DistributorType {
    /**
     * 本地
     */
    String LOCAL = "local";

    /**
     * redis 支持分布式
     */
    String REDIS = "redis";

    /**
     * 自定义
     */
    String CUSTOM = "custom";

}

public interface MessageDistributor {
    /**
     * 推送消息
     * @param messageDto
     */
    void distributor(MessageDto messageDto);
}

@Data
@Accessors(chain = true)
public class MessageDto {
    /**
     * 是否为广播消息
     */
    private Boolean broadcastFlag = Boolean.FALSE;

    /**
     * sessionKeys
     */
    private List<Object> sessionKeys;

    /**
     * 消息
     */
    private String messageText;


    /**
     * 构建广播消息
     * @param messageText
     * @return
     */
    public static MessageDto buildBroadcastMessage(String messageText){
        return new MessageDto().setMessageText(messageText).setBroadcastFlag(true);
    }
}

public interface MessageSender {
    /**
     * 发送消息
     * @param messageDto
     */
    default void doSend(MessageDto messageDto){
        Boolean broadcastFlag = messageDto.getBroadcastFlag();
        Assert.notBlank(messageDto.getMessageText());
        if (broadcastFlag){
            /**
             * 广播模式
             */
            WebSocketMessageSender.broadcastMessage(messageDto.getMessageText());
        }else {
            List<Object> sessionKeys = messageDto.getSessionKeys();
            for (Object sessionKey : sessionKeys) {
                Set<WebSocketSession> webSocketSessions = MapSessionHolder.getWebSocketSessionBySessionKey(sessionKey);
                WebSocketMessageSender.sendMessageByWebSocketSessions(webSocketSessions, messageDto.getMessageText());
            }
        }
    }
}

@UtilityClass
@Slf4j
public class WebSocketMessageSender {
    public Boolean sendMessage(WebSocketSession webSocketSession,String message){
        if (webSocketSession==null){
            log.error("message send fail,websocketSession Can not be empty!");
            return Boolean.FALSE;
        }
        if (!webSocketSession.isOpen()){
            log.error("message send fail,websocketSession is closed");
            return Boolean.FALSE;
        }
        try {
            webSocketSession.sendMessage(new TextMessage(message));
        } catch (IOException e) {
            e.printStackTrace();
            log.error("message send fail,the reason is {}",e.getMessage());
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    public void broadcastMessage(String message){
        MapSessionHolder.MAP_SESSION.forEach((sessionKey,webSocketSession)->{
            sendMessage(webSocketSession,message);
        });
    }

    public void sendMessageByWebSocketSessions(Set<WebSocketSession> webSocketSessions, String message){
        webSocketSessions.stream().forEach(webSocketSession -> sendMessage(webSocketSession,message));
    }


}

本地消息发射器

public class LocalMessageDistributor implements MessageDistributor,MessageSender{
    @Override
    public void distributor(MessageDto messageDto) {
        doSend(messageDto);
    }
}

redis消息发射器

@RequiredArgsConstructor
public class RedisMessageDistributor implements MessageDistributor{
    private final WebSocketRedisMessagePublisher publisher;

    @Override
    public void distributor(MessageDto messageDto) {
        publisher.sendMsg(WebsocketMessageRedisReceiver.CHANNEL, JSONUtil.toJsonStr(messageDto));
    }
}

@Slf4j
public class WebsocketMessageRedisReceiver implements MessageListener,MessageSender {

    public static final String CHANNEL = "websocket-send";
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public void onMessage(Message message, byte[] pattern) {
        log.info("redis channel Listener message send {}", message);
        byte[] channelBytes = message.getChannel();
        RedisSerializer<String> stringSerializer = stringRedisTemplate.getStringSerializer();
        String channel = stringSerializer.deserialize(channelBytes);

        // 这里没有使用通配符,所以一定是true
        if (CHANNEL.equals(channel)) {
            byte[] bodyBytes = message.getBody();
            String body = stringSerializer.deserialize(bodyBytes);
            MessageDto messageDO = JSONUtil.toBean(body, MessageDto.class);
            doSend(messageDO);
        }
    }
}

public class WebSocketRedisMessagePublisher {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    public void sendMsg(String channel, String msg){
        stringRedisTemplate.convertAndSend(channel, msg);
    }
}

2.3 核心配置

@Configuration
@EnableWebSocket
@EnableConfigurationProperties(XlcpWebSocketProperties.class)
@RequiredArgsConstructor
public class XlcpWebSocketAutoConfiguration implements InitializingBean {

    private final List<JsonWebSocketMessageHandler> handlers;

    @Autowired
    private XlcpWebSocketProperties xlcpWebSocketProperties;

    @Bean
    @ConditionalOnMissingBean
    public WebSocketConfigurer webSocketConfigurer(WebSocketHandler webSocketHandler, List<HandshakeInterceptor>handshakeInterceptors){
        return registry -> {
            Set<String> paths = xlcpWebSocketProperties.getPaths();
            registry.addHandler(webSocketHandler,paths.toArray(new String[0]))
                    .setAllowedOrigins(xlcpWebSocketProperties.getAllowedOrigins())
                    .addInterceptors(handshakeInterceptors.toArray(new HandshakeInterceptor[0]));
        };
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        handlers.stream().forEach(handler->{
            JsonWebSocketMessageHandlerRegister.register(handler.getType(),handler);
        });
    }

    @Configuration
    static class JsonMessageHandlerConfig{
        /**
         * 心跳处理配置
         * @return
         */
        @Bean
        @ConditionalOnMissingBean
        @ConditionalOnProperty(prefix = XlcpWebSocketProperties.PRE_FIX,name = "heart",havingValue = "true",matchIfMissing = true)
        public PingJsonWebSocketMessageHandler pingJsonWebSocketMessageHandler(){
            return new PingJsonWebSocketMessageHandler();
        }

        @Bean
        @ConditionalOnMissingBean
        public PlanTextMessageHandler planTextMessageHandler(){
            return new CustomPlanTextMessageHandler();
        }

        @Bean
        public SessionKeyGenerate sessionKeyGenerate(){
            return new WebSocketSessionKeyGenerate();
        }

        @Bean
        @ConditionalOnMissingBean
        public WebSocketHandler webSocketHandler(){
            return new MapSessionHandlerDecorator(new CustomTextWebSocketHandler(planTextMessageHandler()),sessionKeyGenerate());
        }

        @Bean
        @ConditionalOnMissingBean
        public HandshakeInterceptor handshakeInterceptor(){
            return new UserHandshakeInterceptor();
        }
    }


    @Configuration
    @ConditionalOnProperty(prefix = XlcpWebSocketProperties.PRE_FIX,
            name = "distributor-type",
            havingValue = DistributorType.LOCAL)
    static class LocalMessageDistributorConfig{
        @ConditionalOnMissingBean
        @Bean
        public MessageDistributor messageDistributor(){
            return new LocalMessageDistributor();
        }
    }

    @ConditionalOnProperty(prefix = XlcpWebSocketProperties.PRE_FIX,
            name = "distributor-type",
            havingValue = DistributorType.REDIS,
            matchIfMissing = true)
    @Configuration
    static class RedisMessageDistributorConfig{
        @Bean
        @ConditionalOnMissingBean
        public MessageDistributor messageDistributor(){
            return new RedisMessageDistributor(webSocketRedisMessagePublisher());
        }

        @Bean
        public WebsocketMessageRedisReceiver websocketMessageRedisReceiver(){
            return new WebsocketMessageRedisReceiver();
        }

        @Bean
        public WebSocketRedisMessagePublisher webSocketRedisMessagePublisher(){
            return new WebSocketRedisMessagePublisher();
        }

        @Bean
        public MessageListenerAdapter messageListenerAdapter(){
            MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(websocketMessageRedisReceiver(),
                    "onMessage");
            return messageListenerAdapter;
        }

        @Bean
        public RedisMessageListenerContainer listenerContainer(RedisConnectionFactory factory,
                                                               MessageListenerAdapter messageListenerAdapter){
            RedisMessageListenerContainer container = new RedisMessageListenerContainer();
            container.setConnectionFactory(factory);
            container.addMessageListener(messageListenerAdapter, new PatternTopic(WebsocketMessageRedisReceiver.CHANNEL));
            return container;
        }
    }
}

在这里插入图片描述

3 组件的使用

3.1 pom中引入公用组件

<dependency>
	<groupId>com.cncloud</groupId>
	<artifactId>cncloud-common-websocket</artifactId>
</dependency>

3.2 创建handel及socket消息

  • 创建消息拦截器

    @Component
    public class InviteCallJsonMessageHandler extends AbstractJsonMessageHandler<InviteCallJsonWebSocketMessage> {
    
    	@Override
    	protected String doHandler(WebSocketSession webSocketSession, InviteCallJsonWebSocketMessage message) {
    		// todo 业务处理
    	}
    
    	@Override
    	public String type() {
            // 提供消息类型 WebSocketMessageTypeEnum提供统一规范
        	return WebSocketMessageTypeEnum.INVITE_CALL.getValue();
    	}
    
    	@Override
    	public Class<InviteCallJsonWebSocketMessage> getMessageClass() {
            // 返回当前消息类型
    		return InviteCallJsonWebSocketMessage.class;
    	}
    }
    
  • 创建对应的消息结构

    public class InviteCallJsonWebSocketMessage extends AbstractJsonWebSocketMessage {
    	/**
    	 * 任务id
    	 */
    	private String taskId;
    
    	protected InviteCallJsonWebSocketMessage(String type) {
        	super(WebSocketMessageTypeEnum.INVITE_CALL.getValue());
    	}
    
    	public InviteCallJsonWebSocketMessage(){
    		super(WebSocketMessageTypeEnum.INVITE_CALL.getValue());
    	}
    
    	public String getTaskId() {
    		return taskId;
    	}
    
    	public void setTaskId(String taskId) {
    		this.taskId = taskId;
    	}
    }
    

3.3 服务端向客户端推送消息

// websocket 发送消息
MessageDo messageDo = new MessageDo();

messageDo.setNeedBroadcast(Boolean.FALSE);

// 接受用户id
messageDo.setSessionKeys(CollUtil.newArrayList(sendId));

messageDo.setMessageText(JSONUtil.toJsonStr(response));

// 通过redis广播消息 订阅者推送消息
messageDistributor.distribute(messageDo);
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
实现 Spring Boot、RabbitMQ 和 WebSocket 结合的方式主要有以下几个步骤: 1. 创建 Spring Boot 项目,添加 RabbitMQ 和 WebSocket 的相关依赖。 2. 创建 RabbitMQ 队列和交换机,用于发送消息。 3. 创建 WebSocket 配置类,配置 WebSocket 的相关参数。 4. 创建 WebSocket 处理器类,处理 WebSocket 的连接、消息发送等操作。 5. 创建 RabbitMQ 消息监听器类,监听 RabbitMQ 队列中的消息,将消息发送给 WebSocket 处理器。 下面是具体的实现步骤: 1. 创建 Spring Boot 项目,添加 RabbitMQ 和 WebSocket 的相关依赖。 在 pom.xml 中添加以下依赖: ```xml <dependencies> <!-- RabbitMQ 相关依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> <!-- WebSocket 相关依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> </dependencies> ``` 2. 创建 RabbitMQ 队列和交换机,用于发送消息。 在 RabbitMQ 中创建一个交换机和一个队列,然后将队列绑定到交换机上。这里我们使用 RabbitMQ 的默认交换机和队列。 ```java @Configuration public class RabbitMQConfig { @Bean public Queue queue() { return new Queue("websocket"); } @Bean public DirectExchange exchange() { return new DirectExchange(""); } @Bean public Binding binding(Queue queue, DirectExchange exchange) { return BindingBuilder.bind(queue).to(exchange).with("websocket"); } } ``` 3. 创建 WebSocket 配置类,配置 WebSocket 的相关参数。 ```java @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry registry) { registry.enableSimpleBroker("/topic"); registry.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/websocket").setAllowedOrigins("*").withSockJS(); } } ``` 4. 创建 WebSocket 处理器类,处理 WebSocket 的连接、消息发送等操作。 ```java @Component public class WebSocketHandler implements WebSocketHandler { private static final Logger logger = LoggerFactory.getLogger(WebSocketHandler.class); private SimpMessagingTemplate messagingTemplate; @Autowired public WebSocketHandler(SimpMessagingTemplate messagingTemplate) { this.messagingTemplate = messagingTemplate; } @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { logger.info("WebSocket connected: {}", session.getId()); } @Override public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception { logger.info("WebSocket received message: {}", message.getPayload()); } @Override public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { logger.error("WebSocket transport error: {}", exception.getMessage()); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception { logger.info("WebSocket disconnected: {}", session.getId()); } @Override public boolean supportsPartialMessages() { return false; } public void sendMessage(String message) { messagingTemplate.convertAndSend("/topic/messages", message); } } ``` 5. 创建 RabbitMQ 消息监听器类,监听 RabbitMQ 队列中的消息,将消息发送给 WebSocket 处理器。 ```java @Component public class RabbitMQListener { private static final Logger logger = LoggerFactory.getLogger(RabbitMQListener.class); private WebSocketHandler webSocketHandler; @Autowired public RabbitMQListener(WebSocketHandler webSocketHandler) { this.webSocketHandler = webSocketHandler; } @RabbitListener(queues = "websocket") public void handleMessage(String message) { logger.info("RabbitMQ received message: {}", message); webSocketHandler.sendMessage(message); } } ``` 至此,Spring Boot、RabbitMQ 和 WebSocket 结合的实现就完成了。我们可以通过 RabbitMQ 发送消息到队列,然后监听器会将消息发送给 WebSocket 处理器,处理器再将消息发送给 WebSocket 客户端。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值