【发布时间】:2019-07-23 13:44:57
【问题描述】:
我目前有一个带有 STOMP 设置的简单 WebSocket,其中客户端连接到一个主题(带有一个 ID)。控制器立即响应所要求的内容,并设置一个变量来指示客户端订阅的内容。一个带有@Scheduled 注释的方法现在每隔几秒就会向客户端发送它所请求的内容。
在客户端第一次连接之前,调度的方法不会做任何事情。但是,在第一次订阅后,无论客户端是否订阅,它都会继续发布。
@Controller
public class ServiceWebSocketController {
@Autowired
private ServiceService serviceService;
@Autowired
WebSocketSessionController webSocketSessionController;
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
private Set<Long> services = new HashSet<>();
@SubscribeMapping("/service/{serviceId}")
public ServiceDTO subscribe(@DestinationVariable("serviceId") final Long serviceId) throws SQLException {
System.out.println("Subscribed to Service with ID: " + serviceId);
services.add(serviceId);
return serviceService.getServiceWithProperties(serviceId).orElseThrow(() -> new ResourceNotFoundException("Service", "id", serviceId));
}
@Scheduled(fixedDelay = 2000)
public void service() throws SQLException {
services.removeIf(serviceId -> !webSocketSessionController.hasSubscriptionTo("/topic/service/" + serviceId));
// Publish specified Service data to each anonymously subscribed client.
services.forEach(serviceId -> {
try {
System.out.println("Publishing Service with ID: " + serviceId);
// We don't use .convertAndSendToUser here, because all our clients are anonymous.
simpMessagingTemplate.convertAndSend("/topic/service/" + serviceId, serviceService.getServiceWithProperties(serviceId));
} catch (SQLException e) {
e.printStackTrace();
}
});
}
}
如何判断客户是否退订?如果存在类似于@UnsubscribeMapping 的东西,我可以简单地将currentSubscriptionServiceId 变量再次设置为null,从而阻止预定方法连续发布数据。
【问题讨论】:
-
我对 STOMP 支持不够熟悉,无法告诉您正确的方法,但我可以说您正在存储 全局状态(ID)的事实共享控制器内部表明存在整体设计问题。
-
@chrylis 你是完全正确的。我是一个新手程序员,刚开始使用 Spring/WebSockets,所以我还在学习。我最终使用
ConcurrentHashMap<String, Long>来存储哪些客户订阅了哪些服务。使用下面@Bertrand Pestre 的答案,我能够实现我想要的:) -
很高兴有帮助。请注意,如果您不清除它,它将存储状态 forever,因此在生产系统中,您通常会执行一些操作,例如将该信息存储在 Redis 或类似的键值后端中过期记录。
-
@chrylis 我更新了我的答案以反映您的建议。我监视连接/断开连接/订阅/取消订阅(使用
ApplicationListeners,正如下面 Bertrand Pestre 的回答所建议的那样)以确定哪些客户端已连接并订阅了特定服务。如果客户取消订阅/断开连接,我会删除他们的订阅并停止发布数据。
标签: javascript java spring-boot websocket stomp