在 Spring Websocket 消息传递的调度方法中获取主体



想要使用 websocket 向特定客户端发送通知。具有用于发送通知的计划任务,但无法在该任务中获取主体。找到了这篇文章,但据我所知,Spring 调度方法必须是无参数的。

@Scheduled(fixedDelay=5000)
public void sendMessages(Principal principal)
messagingTemplate
    .convertAndSendToUser(principal.getName(), "/queue/horray", "Horray, " + principal.getName() + "!");
}

这可能吗?如何在计划方法中获取 websocket 主体?

你不能在调度方法中获取主体,因为方法调用不是由用户发起的。

您可以遵循以下方法:

1) 创建一个 websocket 端点 "/app/events"

2)让所有用户订阅该端点

3) 获取要发送通知的所有用户 ID

4) 向单个用户发送通知

simpMessagingTemplate.convertAndSendToUser("userId", "/app/events", "messageEntity"); 
userId: can be actual user id if authenticated or it can be websocket session id.

我为这种情况编写了一个解决方法。首先,我为 websockets 事件创建一个侦听器。在订阅请求的情况下,我保留请求中的userId并保留在ConcurrentHashMap中。另一方面,当客户端断开连接或发送取消订阅请求时,我会从该映射中删除他的 userId。

我的侦听器类:

@Service
public class MyEventListener {
  @Autowired
  private NotificationPublisher notificationPublisher;
  @EventListener({SessionSubscribeEvent.class})
  public void onWebSocketSubscribeEvent(SessionSubscribeEvent event) {
      notificationPublisher.subscribedUsers.put(event.getUser().getName(), Calendar.getInstance().getTimeInMillis());
  }
  @EventListener({SessionUnsubscribeEvent.class})
  public void onWebSocketUnsubscribeEvent(SessionUnsubscribeEvent event) {
      notificationPublisher.subscribedUsers.remove(event.getUser().getName());
  }
  @EventListener({SessionDisconnectEvent.class})
  public void onWebSocketDisconnectEvent(SessionDisconnectEvent event) {
      notificationPublisher.subscribedUsers.remove(event.getUser().getName());
  }
}

运行实际作业的通知发布者类:

public class NotificationPublisher {
  public final Map<String, Long> subscribedUsers = new ConcurrentHashMap<>();
  @Autowired
  private SimpMessagingTemplate messagingTemplate;
  @Autowired
  private MyService myService;
  @Value("${task.notifications.publisher.websocket_timeout_seconds}")
  private int websocketSessionTimeout;
  public void sendDataUpdates() {
    SocketResponseCount count = null;
    for(String key: subscribedUsers.keySet()) {
        long subscribeTime = subscribedUsers.get(key);
        if(Calendar.getInstance().getTimeInMillis() - subscribeTime > websocketSessionTimeout*1000) {
            subscribedUsers.remove(key);
            continue;
        }
        count = myService.getNotificationsCount(key);
        this.messagingTemplate.convertAndSendToUser(key, "/queue/publish",count);
    }
  }
}

也许它会帮助某人

我的解决方案:我得到所有用户会话

@Autowired
private SimpMessagingTemplate template;
@Autowired
private MyRepository myRepository;
@Autowired
private SessionRegistry sessionRegistry;

@Scheduled(fixedRate = 5000)
public void greeting() {
    List<SessionInformation> activeSessions = new ArrayList<>();
    for (Object principal : sessionRegistry.getAllPrincipals() )
    {
        activeSessions.addAll( sessionRegistry.getAllSessions( principal, false ) );
    }
    for (SessionInformation session : activeSessions )
    {
        Object principalObj = session.getPrincipal();
        if ( principalObj instanceof CurrentUser)
        {
            CurrentUser user = (CurrentUser) principalObj;
            this.template.convertAndSendToUser(user.getUsername().toUpperCase(),"/queue/reply2",myRepository.findAll());
        }
    }
}

最新更新