mirror of
http://git.pig4cloud.com/pig/pigx.git
synced 2026-11-08 12:39:05 +08:00
✨ Introducing new features. support sse
This commit is contained in:
1 parent
d15832c784
commit
5a8e4b72b1
18 files changed
+571
No files matched your search
@@ -139,6 +139,11 @@
|
||||
<artifactId>pigx-common-xss</artifactId>
|
||||
<version>${pigx.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pigx-common-sse</artifactId>
|
||||
<version>${pigx.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pigx-common-websocket</artifactId>
|
||||
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pigx-common</artifactId>
|
||||
<version>5.3.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pigx-common-sse</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<description>pigx sse 服务端推送</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-json</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pigx-common-security</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.pig4cloud.pigx.common.sse.config;
|
||||
|
||||
import com.pig4cloud.pigx.common.sse.distribute.LocalMessageDistributor;
|
||||
import com.pig4cloud.pigx.common.sse.distribute.MessageDistributor;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 本地的消息分发器配置
|
||||
*
|
||||
* @author lengleng
|
||||
*/
|
||||
@ConditionalOnProperty(prefix = SseEmitterProperties.PREFIX, name = "message-distributor",
|
||||
havingValue = MessageDistributorTypeConstants.LOCAL)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class LocalMessageDistributorConfiguration {
|
||||
|
||||
/**
|
||||
* 本地基于内存的消息分发,不支持集群
|
||||
* @return LocalMessageDistributor
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(MessageDistributor.class)
|
||||
public LocalMessageDistributor messageDistributor() {
|
||||
return new LocalMessageDistributor();
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.pig4cloud.pigx.common.sse.config;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
*/
|
||||
public final class MessageDistributorTypeConstants {
|
||||
|
||||
private MessageDistributorTypeConstants() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 本地
|
||||
*/
|
||||
public static final String LOCAL = "local";
|
||||
|
||||
/**
|
||||
* 基于 Redis PUB/SUB
|
||||
*/
|
||||
public static final String REDIS = "redis";
|
||||
|
||||
/**
|
||||
* 自定义
|
||||
*/
|
||||
public static final String CUSTOM = "custom";
|
||||
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package com.pig4cloud.pigx.common.sse.config;
|
||||
|
||||
import com.pig4cloud.pigx.common.sse.distribute.MessageDistributor;
|
||||
import com.pig4cloud.pigx.common.sse.distribute.RedisMessageDistributor;
|
||||
import com.pig4cloud.pigx.common.sse.distribute.RedisSseEmitterMessageListener;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.data.redis.listener.PatternTopic;
|
||||
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||
|
||||
/**
|
||||
* 基于 Redis Pub/Sub 的消息分发器
|
||||
*
|
||||
* @author lengleng
|
||||
*/
|
||||
@ConditionalOnClass(StringRedisTemplate.class)
|
||||
@ConditionalOnProperty(prefix = SseEmitterProperties.PREFIX, name = "message-distributor",
|
||||
havingValue = MessageDistributorTypeConstants.REDIS, matchIfMissing = true)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class RedisMessageDistributorConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(MessageDistributor.class)
|
||||
public RedisMessageDistributor messageDistributor(StringRedisTemplate stringRedisTemplate) {
|
||||
return new RedisMessageDistributor(stringRedisTemplate);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(RedisMessageDistributor.class)
|
||||
@ConditionalOnMissingBean
|
||||
public RedisSseEmitterMessageListener redisWebsocketMessageListener(StringRedisTemplate stringRedisTemplate) {
|
||||
return new RedisSseEmitterMessageListener(stringRedisTemplate);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(RedisMessageDistributor.class)
|
||||
@ConditionalOnMissingBean
|
||||
public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory) {
|
||||
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
|
||||
container.setConnectionFactory(connectionFactory);
|
||||
return container;
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(MessageDistributor.class)
|
||||
@RequiredArgsConstructor
|
||||
static class RedisMessageListenerRegisterConfiguration {
|
||||
|
||||
private final RedisMessageListenerContainer redisMessageListenerContainer;
|
||||
|
||||
private final RedisSseEmitterMessageListener redisWebsocketMessageListener;
|
||||
|
||||
@PostConstruct
|
||||
public void addMessageListener() {
|
||||
redisMessageListenerContainer.addMessageListener(redisWebsocketMessageListener,
|
||||
new PatternTopic(RedisSseEmitterMessageListener.CHANNEL));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.pig4cloud.pigx.common.sse.config;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
/**
|
||||
* websocket自动配置
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
@EnableConfigurationProperties(SseEmitterProperties.class)
|
||||
public class SseEmitterAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public SseEmitterEndpoint sseEmitterEndpoint() {
|
||||
return new SseEmitterEndpoint();
|
||||
}
|
||||
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.pig4cloud.pigx.common.sse.config;
|
||||
|
||||
import com.pig4cloud.pigx.common.security.util.SecurityUtils;
|
||||
import com.pig4cloud.pigx.common.sse.holder.SseEmitterHolder;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2023/12/11
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/sse")
|
||||
public class SseEmitterEndpoint {
|
||||
|
||||
@RequestMapping("/info")
|
||||
public SseEmitter info() {
|
||||
SseEmitter sseEmitter = new SseEmitter(0L);
|
||||
|
||||
if (Objects.isNull(SecurityUtils.getUser())) {
|
||||
log.debug("MSG: SseConnectError");
|
||||
return null;
|
||||
}
|
||||
log.info("MSG: SseConnect | EmitterHash: {} | ID: {}", sseEmitter.hashCode(), SecurityUtils.getUser().getId());
|
||||
sseEmitter.onCompletion(() -> {
|
||||
log.info("MSG: SseConnectCompletion | EmitterHash: {} |ID: {}", sseEmitter.hashCode(), SecurityUtils.getUser().getId());
|
||||
});
|
||||
sseEmitter.onTimeout(() -> {
|
||||
log.error("MSG: SseConnectTimeout | EmitterHash: {} |ID: {} ", sseEmitter.hashCode(), SecurityUtils.getUser().getId());
|
||||
});
|
||||
sseEmitter.onError(t -> {
|
||||
log.error("MSG: SseConnectError | EmitterHash: {} |ID: {}", sseEmitter.hashCode(), SecurityUtils.getUser().getId());
|
||||
});
|
||||
SseEmitterHolder.addSseEmitter(SecurityUtils.getUser().getId(), sseEmitter);
|
||||
return sseEmitter;
|
||||
}
|
||||
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package com.pig4cloud.pigx.common.sse.config;
|
||||
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import com.pig4cloud.pigx.common.sse.holder.SseEmitterHolder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author lengleng 2021/1/4
|
||||
* @version 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
public class SseEmitterMessageSender {
|
||||
|
||||
public static void broadcast(String message) {
|
||||
Collection<SseEmitter> sseEmitters = SseEmitterHolder.getSseEmitters();
|
||||
for (SseEmitter sseEmitter : sseEmitters) {
|
||||
send(sseEmitter, message);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean send(Object sseEmitterKey, String message) {
|
||||
SseEmitter sseEmitter = SseEmitterHolder.getSseEmitter(sseEmitterKey);
|
||||
if (sseEmitter == null) {
|
||||
log.info("[send] 当前 sseEmitterKey:{} 对应 sseEmitter 不在本服务中", sseEmitterKey);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return send(sseEmitter, message);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean send(SseEmitter sseEmitter, String message) {
|
||||
if (sseEmitter == null) {
|
||||
log.error("[send] sseEmitter 为 null");
|
||||
return false;
|
||||
}
|
||||
|
||||
Object sendFailed = ReflectUtil.getFieldValue(sseEmitter, "sendFailed");
|
||||
if ((boolean) sendFailed) {
|
||||
log.error("[send] sseEmitter 已经关闭");
|
||||
SseEmitterHolder.removeSseEmitter(sseEmitter);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
sseEmitter.send(message);
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("[send] sseEmitter({}) 发送消息({}) 异常", sseEmitter, message, e);
|
||||
SseEmitterHolder.removeSseEmitter(sseEmitter);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.pig4cloud.pigx.common.sse.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* websocket props
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties(SseEmitterProperties.PREFIX)
|
||||
public class SseEmitterProperties {
|
||||
|
||||
public static final String PREFIX = "pigx.sse";
|
||||
|
||||
/**
|
||||
* 路径: 无参: /ws 有参: PathVariable: 单参: /ws/{test} 多参: /ws/{test1}/{test2} query:
|
||||
* /ws?uid=1&name=test
|
||||
*/
|
||||
private String path = "/sse/info";
|
||||
|
||||
/**
|
||||
* 消息分发器:local | redis,默认 local, 如果自定义的话,可以配置为其他任意值
|
||||
*/
|
||||
private String messageDistributor = MessageDistributorTypeConstants.LOCAL;
|
||||
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.pig4cloud.pigx.common.sse.distribute;
|
||||
|
||||
/**
|
||||
* 本地消息分发,直接进行发送
|
||||
*
|
||||
* @author lengleng 2021/1/12
|
||||
* @version 1.0
|
||||
*/
|
||||
public class LocalMessageDistributor implements MessageDistributor, MessageSender {
|
||||
|
||||
/**
|
||||
* 消息分发
|
||||
* @param messageDO 发送的消息
|
||||
*/
|
||||
@Override
|
||||
public void distribute(MessageDO messageDO) {
|
||||
doSend(messageDO);
|
||||
}
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.pig4cloud.pigx.common.sse.distribute;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author lengleng 2021/1/12
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class MessageDO {
|
||||
|
||||
/**
|
||||
* 是否广播
|
||||
*/
|
||||
private Boolean needBroadcast;
|
||||
|
||||
/**
|
||||
* sessionKeys
|
||||
*/
|
||||
private List<Object> sessionKeys;
|
||||
|
||||
/**
|
||||
* 需要发送的消息文本
|
||||
*/
|
||||
private String messageText;
|
||||
|
||||
/**
|
||||
* 构建需要广播的message
|
||||
* @author lingting 2021-03-25 17:28
|
||||
*/
|
||||
public static MessageDO broadcastMessage(String text) {
|
||||
return new MessageDO().setMessageText(text).setNeedBroadcast(true);
|
||||
}
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.pig4cloud.pigx.common.sse.distribute;
|
||||
|
||||
/**
|
||||
* 消息分发器
|
||||
*
|
||||
* @author lengleng 2021/1/12
|
||||
* @version 1.0
|
||||
*/
|
||||
public interface MessageDistributor {
|
||||
|
||||
/**
|
||||
* 消息分发
|
||||
* @param messageDO 发送的消息
|
||||
*/
|
||||
void distribute(MessageDO messageDO);
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.pig4cloud.pigx.common.sse.distribute;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.pig4cloud.pigx.common.sse.config.SseEmitterMessageSender;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author lengleng 2021/1/12
|
||||
* @version 1.0
|
||||
*/
|
||||
public interface MessageSender {
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
* @param messageDO 发送的消息
|
||||
*/
|
||||
default void doSend(MessageDO messageDO) {
|
||||
Boolean needBroadcast = messageDO.getNeedBroadcast();
|
||||
String messageText = messageDO.getMessageText();
|
||||
List<Object> sessionKeys = messageDO.getSessionKeys();
|
||||
if (needBroadcast != null && needBroadcast) {
|
||||
// 广播信息
|
||||
SseEmitterMessageSender.broadcast(messageText);
|
||||
}
|
||||
else if (CollectionUtil.isNotEmpty(sessionKeys)) {
|
||||
// 指定用户发送
|
||||
for (Object sessionKey : sessionKeys) {
|
||||
SseEmitterMessageSender.send(sessionKey, messageText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.pig4cloud.pigx.common.sse.distribute;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息分发器
|
||||
*
|
||||
* @author lengleng 2021/1/12
|
||||
* @version 1.0
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class RedisMessageDistributor implements MessageDistributor {
|
||||
|
||||
private final StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
/**
|
||||
* 消息分发
|
||||
* @param messageDO 发送的消息
|
||||
*/
|
||||
@Override
|
||||
public void distribute(MessageDO messageDO) {
|
||||
// 包装 sessionKey 适配分布式多环境
|
||||
List<Object> sessionKeyList = new ArrayList<>(messageDO.getSessionKeys());
|
||||
messageDO.setSessionKeys(sessionKeyList);
|
||||
|
||||
String str = JSONUtil.toJsonStr(messageDO);
|
||||
stringRedisTemplate.convertAndSend(RedisSseEmitterMessageListener.CHANNEL, str);
|
||||
}
|
||||
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package com.pig4cloud.pigx.common.sse.distribute;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.connection.Message;
|
||||
import org.springframework.data.redis.connection.MessageListener;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
|
||||
/**
|
||||
* redis订阅 websocket 发送消息,接收到消息时进行推送
|
||||
*
|
||||
* @author lengleng 2021/1/12
|
||||
* @version 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class RedisSseEmitterMessageListener implements MessageListener, MessageSender {
|
||||
|
||||
public static final String CHANNEL = "sse-send";
|
||||
|
||||
private final StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Override
|
||||
public void onMessage(Message message, byte[] bytes) {
|
||||
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);
|
||||
MessageDO messageDO = JSONUtil.toBean(body, MessageDO.class);
|
||||
doSend(messageDO);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package com.pig4cloud.pigx.common.sse.holder;
|
||||
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* SseEmitter 持有者 主要用于保存当前所有在线的会话信息
|
||||
*
|
||||
* @author lengleng 2021/1/4
|
||||
* @version 1.0
|
||||
*/
|
||||
public final class SseEmitterHolder {
|
||||
|
||||
private SseEmitterHolder() {
|
||||
}
|
||||
|
||||
private static final Map<String, SseEmitter> USER_SSE_EMITTER_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 添加一个 sseEmitter
|
||||
* @param sseEmitterKey sseEmitter 唯一标识
|
||||
* @param sseEmitter 待添加的 SseEmitter
|
||||
*/
|
||||
public static void addSseEmitter(Object sseEmitterKey, SseEmitter sseEmitter) {
|
||||
USER_SSE_EMITTER_MAP.put(sseEmitterKey.toString(), sseEmitter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除一个 sseEmitter
|
||||
* @param sseEmitterKey sseEmitter唯一标识
|
||||
*/
|
||||
public static void removeSseEmitter(Object sseEmitterKey) {
|
||||
USER_SSE_EMITTER_MAP.remove(sseEmitterKey.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定标识的 sseEmitter
|
||||
* @param sseEmitterKey sseEmitter唯一标识
|
||||
* @return SseEmitter 该标识对应的 sseEmitter
|
||||
*/
|
||||
public static SseEmitter getSseEmitter(Object sseEmitterKey) {
|
||||
return USER_SSE_EMITTER_MAP.get(sseEmitterKey.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前所有在线的 sseEmitter
|
||||
* @return Collection<SseEmitter> sseEmitter集合
|
||||
*/
|
||||
public static Collection<SseEmitter> getSseEmitters() {
|
||||
return USER_SSE_EMITTER_MAP.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有在线的用户标识
|
||||
* @return Set<Object> sseEmitter唯一标识集合
|
||||
*/
|
||||
public static Set<String> getSseEmitterKeys() {
|
||||
return USER_SSE_EMITTER_MAP.keySet();
|
||||
}
|
||||
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
com.pig4cloud.pigx.common.sse.config.SseEmitterAutoConfiguration
|
||||
com.pig4cloud.pigx.common.sse.config.RedisMessageDistributorConfiguration
|
||||
com.pig4cloud.pigx.common.sse.config.LocalMessageDistributorConfiguration
|
||||
@@ -52,6 +52,7 @@
|
||||
<module>pigx-common-sentinel</module>
|
||||
<module>pigx-common-sequence</module>
|
||||
<module>pigx-common-swagger</module>
|
||||
<module>pigx-common-sse</module>
|
||||
<module>pigx-common-websocket</module>
|
||||
<module>pigx-common-xss</module>
|
||||
</modules>
|
||||
|
||||
Reference in new issue
Block a user