java - SimpUserRegistry 不包含任何会话对象
问题描述
我是 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.
所以我创建了一个配置类,如下所示。
@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”,你不应该直接实例化它。
您的 WebSocket Spring 配置是否正确?
- 确保您的应用程序配置良好(即正在扫描您的配置类)。
SimpUserRegistry
由spring-messaging
依赖项导入:确保您的配置类使用@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:@Controller
除非您在其中定义了端点,否则不需要对配置类进行注释。
新评论后编辑:
您可以查看DefaultSimpUserRegistry
实现以了解如何执行此操作。
要拦截应用程序事件,您必须实现ApplicationListener
接口(在本例中SmartApplicationListener
)。该supportsEventType
方法对于定义要拦截的事件类型很重要:
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return AbstractSubProtocolEvent.class.isAssignableFrom(eventType);
}
有AbstractSubProtocolEvent
多种实现。最重要的是SessionConnectEvent
,SessionDisconnectEvent
。
拦截(参见onApplicationEvent
方法)这些事件类型将允许您的实现在 Redis 缓存中保持所需的状态。然后您可以存储用户(ID 等)。
推荐阅读
- javascript - 如何使我的 Electron 应用程序成为打开文件的默认应用程序?
- sql - 如果属性值大于 1,则迭代每一行中的字符串并计算变量
- css - 偏离中心图像的 CSS 定位
- settimeout - 页面延迟后 Div 内容发生变化
- java - 象棋游戏javafx,我不理解骑士移动?
- ios - TableViewCell 中的 PickerView 可以工作但不能更新
- flutter - Flutter 中的本机设备方向问题
- python - 将 4 个图/图形排列成一个网格状
- javascript - 有没有办法在脚本 document.write(''); 中写入文本?成多行?
- elasticsearch - ElasticSearch多词查询,匹配多词比匹配少而多更有价值