我的第一个问题是,为什么在已经成功集成了使用Stomp的WebSockets后,你还要尝试向REST控制器发送HTTP请求呢?如果我正确理解你的用例,那么目前我可以想到三种解决方案。
解决方案1 (socket session ↔ product id)
您可以通过打开的Websocket连接直接从客户端向服务器发送请求。Spring会确定哪个Websocket会话发出了该调用,并且您可以实现您的业务逻辑。您需要激活另一个代理程序名为"/queue",并指定当订阅不是广播时所需的用户目标前缀。在客户端上,您还必须更改您的订阅路径。最后,您必须创建一个带有@Controller注释的类,其中包含来自连接的客户端的消息映射以接收消息。
服务器配置
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/queue", "/product");
registry.setApplicationDestinationPrefixes("/app");
registry.setUserDestinationPrefix("/user");
}
}
服务器控制器
@Controller
public class WebSocketContoller{
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
@MessageMapping("/product/register")
public void register(@Payload Long productId, @Header("simpSessionId") String sessionId) {
String response = "This could also be one of your product objects of type Product";
SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE);
headerAccessor.setSessionId(sessionId);
headerAccessor.setLeaveMutable(true);
messagingTemplate.convertAndSendToUser(sessionId,"/queue/product/changes", response, headerAccessor.getMessageHeaders());
}
}
客户订阅更改
stompClient.subscribe('/user/queue/product/changes', function (scoredata) {
});
如需详细信息,请查看此答案:https://stackoverflow.com/a/26288475/11133168
解决方案2(主要是产品ID)
但是,如果您确实想考虑使用rest控制器来开始注册进程,或者它不能满足您的要求,那么您应该查看下面的链接。Spring还能够通过公开的SimpUserRegistry bean跟踪活动的websocket会话及其用户。但是,根据您应用程序的安全性,您将需要为客户端输入通道配置自定义ChannelInterceptor适配器以确定用户。
有关详细信息和代码示例,请参见此答案:https://dev59.com/fKPia4cB1Zd3GeqP4dMw#45359294
解决方案3(产品ID主题)
您也可以订阅特定的产品ID主题,这样您甚至不需要知道哪个用户想要被通知更改特定产品。
客户端订阅更改
stompClient.subscribe('/product/changes/5', function (scoredata) {
});
服务器服务示例
@Service
public class WebSocketProductService{
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
public void sendProductChange(String product, String productId) {
this.simpMessagingTemplate.convertAndSend("/product/changes/"+productId, product);
}
}
服务器控制器
如果您想管理产品ID订阅列表,则需要该控制器。如解决方案1中所述,您需要一个带有@ Controller注释的类,其中包含一个带有@ SubscribeMapping注释的方法。如果客户端尝试订阅指定路径,则会调用此方法。
@Controller
public class WebSocketContoller{
@SubscribeMapping("/product/changes/{productId}")
public void productIdSubscription(@DestinationVariable Long productId) {
}
}