SimpUserRegistry 不包含任何会话对象
SimpUserRegistry doesnot contain any session objects
我是 Websockets 的新手。我一直在尝试使用 SimpUserRegistry 通过 Principal 查找会话对象。我编写了一个自定义握手处理程序来将匿名用户转换为经过身份验证的用户,并且我能够从 Websocket 会话对象访问主体名称。
自定义握手处理程序的代码如下所示
import java.security.Principal;
public class StompPrincipal implements Principal {
private String name;
public StompPrincipal(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
}
处理程序
class CustomHandshakeHandlerTwo extends DefaultHandshakeHandler {
// Custom class for storing principal
@Override
protected Principal determineUser(
ServerHttpRequest request,
WebSocketHandler wsHandler,
Map<String, Object> attributes
) {
// Generate principal with UUID as name
return new StompPrincipal(UUID.randomUUID().toString());
}
}
但正如 等许多问题中所述,我无法直接注入 SimpUserRegistry
。
它抛出错误
Field simpUserRegistry required a bean of type 'org.springframework.messaging.simp.user.SimpUserRegistry' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'org.springframework.messaging.simp.user.SimpUserRegistry' in your configuration.
所以我创建了一个配置 class 如下所示。
@Configuration
public class UsersConfig {
final private SimpUserRegistry userRegistry = new DefaultSimpUserRegistry();
@Bean
@Primary
public SimpUserRegistry userRegistry() {
return userRegistry;
}
}
现在我可以自动装配并使用它,但每次我尝试访问 SimpUserRegistry
它都是空的。
这个问题可能是什么原因造成的?
编辑:
正在显示 websocket 配置
@Configuration
@EnableWebSocket
@Controller
@Slf4j
public class WebSocketConfig implements WebSocketConfigurer {
@Autowired
EventTextHandler2 handler;
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
log.info("Registering websocket handler SocketTextHandler");
registry.addHandler(handler, "/event").setHandshakeHandler(new CustomHandshakeHandlerTwo());
}
}
SimpUserRegistry
是 Spring WebSocket 的“基础结构 bean”registered/provided,您不应该直接实例化它。
您的 WebSocket Spring 配置正确吗?
- 确保您的应用程序配置正确(即正在扫描您的配置 class)。
SimpUserRegistry
由 spring-messaging
依赖项导入:确保您的配置 class 带有 @EnableWebSocketMessageBroker
.
注释
官方文档:https://docs.spring.io/spring-framework/docs/5.3.6/reference/html/web.html#websocket-stomp-enable
- 要在 Redis 中支持连接的用户,您可能需要创建一个新的 SimpUserRegistry 实现:
public class RedisSimpUserRegistry implements SimpUserRegistry, SmartApplicationListener {
private final RedisTemplate redisTemplate;
public RedisSimpUserRegistry(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
[...]
@Override
public void onApplicationEvent(ApplicationEvent event) {
// Maintain Redis collection on event type
// ie. SessionConnectedEvent / SessionDisconnectEvent
}
[...]
}
PS:您的配置 class 上的 @Controller
注释不是必需的,除非您在其中定义了端点。
在有新评论后编辑:
您可以查看 DefaultSimpUserRegistry
实现以了解如何执行此操作。
要拦截应用程序事件,您必须实现 ApplicationListener
接口(在本例中为 SmartApplicationListener
)。
supportsEventType
方法对于定义要拦截的事件类型很重要:
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return AbstractSubProtocolEvent.class.isAssignableFrom(eventType);
}
AbstractSubProtocolEvent
有多个实现。最重要的是 SessionConnectEvent
, SessionDisconnectEvent
.
拦截(参见 onApplicationEvent
方法)这些事件类型将允许您的实现在 Redis 缓存中保持所需的状态。然后您可以存储用户(id 等)。
我是 Websockets 的新手。我一直在尝试使用 SimpUserRegistry 通过 Principal 查找会话对象。我编写了一个自定义握手处理程序来将匿名用户转换为经过身份验证的用户,并且我能够从 Websocket 会话对象访问主体名称。
自定义握手处理程序的代码如下所示
import java.security.Principal;
public class StompPrincipal implements Principal {
private String name;
public StompPrincipal(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
}
处理程序
class CustomHandshakeHandlerTwo extends DefaultHandshakeHandler {
// Custom class for storing principal
@Override
protected Principal determineUser(
ServerHttpRequest request,
WebSocketHandler wsHandler,
Map<String, Object> attributes
) {
// Generate principal with UUID as name
return new StompPrincipal(UUID.randomUUID().toString());
}
}
但正如 SimpUserRegistry
。
它抛出错误
Field simpUserRegistry required a bean of type 'org.springframework.messaging.simp.user.SimpUserRegistry' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'org.springframework.messaging.simp.user.SimpUserRegistry' in your configuration.
所以我创建了一个配置 class 如下所示。
@Configuration
public class UsersConfig {
final private SimpUserRegistry userRegistry = new DefaultSimpUserRegistry();
@Bean
@Primary
public SimpUserRegistry userRegistry() {
return userRegistry;
}
}
现在我可以自动装配并使用它,但每次我尝试访问 SimpUserRegistry
它都是空的。
这个问题可能是什么原因造成的?
编辑:
正在显示 websocket 配置
@Configuration
@EnableWebSocket
@Controller
@Slf4j
public class WebSocketConfig implements WebSocketConfigurer {
@Autowired
EventTextHandler2 handler;
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
log.info("Registering websocket handler SocketTextHandler");
registry.addHandler(handler, "/event").setHandshakeHandler(new CustomHandshakeHandlerTwo());
}
}
SimpUserRegistry
是 Spring WebSocket 的“基础结构 bean”registered/provided,您不应该直接实例化它。
您的 WebSocket Spring 配置正确吗?
- 确保您的应用程序配置正确(即正在扫描您的配置 class)。
SimpUserRegistry
由 spring-messaging
依赖项导入:确保您的配置 class 带有 @EnableWebSocketMessageBroker
.
官方文档:https://docs.spring.io/spring-framework/docs/5.3.6/reference/html/web.html#websocket-stomp-enable
- 要在 Redis 中支持连接的用户,您可能需要创建一个新的 SimpUserRegistry 实现:
public class RedisSimpUserRegistry implements SimpUserRegistry, SmartApplicationListener {
private final RedisTemplate redisTemplate;
public RedisSimpUserRegistry(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
[...]
@Override
public void onApplicationEvent(ApplicationEvent event) {
// Maintain Redis collection on event type
// ie. SessionConnectedEvent / SessionDisconnectEvent
}
[...]
}
PS:您的配置 class 上的 @Controller
注释不是必需的,除非您在其中定义了端点。
在有新评论后编辑:
您可以查看 DefaultSimpUserRegistry
实现以了解如何执行此操作。
要拦截应用程序事件,您必须实现 ApplicationListener
接口(在本例中为 SmartApplicationListener
)。
supportsEventType
方法对于定义要拦截的事件类型很重要:
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return AbstractSubProtocolEvent.class.isAssignableFrom(eventType);
}
AbstractSubProtocolEvent
有多个实现。最重要的是 SessionConnectEvent
, SessionDisconnectEvent
.
拦截(参见 onApplicationEvent
方法)这些事件类型将允许您的实现在 Redis 缓存中保持所需的状态。然后您可以存储用户(id 等)。