限制特定浏览器选项卡上的@SendToUser 广播
Limit a @SendToUser broadcast on a specific browser tab
我在 Springboot 上使用 STOMP websocket
并想限制对特定页面的广播。这是我的过程:
User
将消息填入 HTML 输入。
- 浏览器将通过 STOMP 客户端发送消息。
- 服务器接收消息并验证它。如果消息有效,它将向用户处理的所有选项卡广播
User
已发送消息。如果它无效,它会发回错误消息 仅发送到发送消息的特定浏览器选项卡 而不是其他选项卡,即使这些选项卡具有相同的 User
记录英寸
虽然我不能限制将错误消息发送到特定选项卡,但我已经使它的某些部分起作用,它总是将错误消息广播到共享相同 User
的所有选项卡。这是我的初始代码:
@MessageMapping("/api/secure/message")
@SendToUser("/api/secure/broadcast")
public HttpEntity createMessage(Message message, Authentication authentication) throws Exception {
Set<String> errors = TreeSet<String>();
// Process Message message and add every exceptions encountered to Set errors.
boolean valid = (errors.size() > 0);
if(valid) {
// Broadcast to all.
return new ResponseEntity(message, HttpStatus.OK);
}
else {
// Send the message to that particular tab only.
return new ResponseEntity(errors, HttpStatus.UNPROCESSABLE_ENTITY);
}
}
这可以通过 websocket
实现吗?或者我应该 return 回到 XHR
?
对于每个选项卡,您都将创建一个新的 websocket 会话,因此您的 stomp session-id 也会有所不同。因此我们可以决定是发送到特定会话还是特定用户的所有会话。
@Autowired
private SimpMessagingTemplate template;
....
@MessageMapping(...)
public void sendMessage(Message<?> message...) {
.....
StompHeaderAccessor headerAccessor =
StompHeaderAccessor.wrap(message);
String sessionId = headerAccessor.getSessionId();
....
if(valid) {
//Not specifying session Id so sends all users of
<user_name>
template.cnvertAndSendToUser(<user_name>,
<destination>, <payload>)
}
else {
SimpMessageHeaderAccessor headerAccessor =
SimpMessagingHeaderAccessor.create(SimpMessageType.MESSAGE);
headerAccessor.setSessionId(sessionId);
//This will send it to particular session.
template.convertAndSendToUser(<user_name>,
<destination>, <payload>,
headerAccessor.getMessageHeaders());
}
}
有用的参考资料:
用户@Srinivas 提供了一个很好的起始参考点。我已经用我的工作代码修改了问题中的代码块:
// inject the [messagingTemplate] bean.
// class org.springframework.messaging.simp.SimpMessagingTemplate
@Autowired
private SimpMessagingTemplate messagingTemplate;
@MessageMapping("/api/secure/message")
// Remove the @SendToUser annotation and change return type to void.
// @SendToUser("/api/secure/broadcast")
// public HttpEntity createMessage(Message message…
public void createMessage(Message message, Authentication authentication) throws Exception {
Set<String> errors = TreeSet<String>();
// Process Message message and add every exceptions encountered to Set errors.
boolean valid = (errors.size() > 0);
if(valid) {
// Broadcast to all.
// Instead of returning to send the message, use the [messagingTemplate] instead.
// return new ResponseEntity(message, HttpStatus.OK);
messagingTemplate.convertAndSendToUser("/api/secure/broadcast", errors);
}
else {
// Send the message to that particular tab only.
// Each STOMP WebSocket connection has a unique ID that effectively differentiate
// it to the other browser tabs. Retrieve that ID so we can target that specific
// tab to send our error message with.
// class org.springframework.messaging.simp.stomp.StompHeaderAccessor
StompHeaderAccessor stompHeaderAccessor = StompHeaderAccessor.wrap(message);
String sessionId = stompHeaderAccessor.getSessionId();
// class org.springframework.messaging.simp.SimpMessageHeaderAccessor
// class org.springframework.messaging.simp.SimpMessageType
// class org.springframework.util.MimeType
// class java.nio.charset.StandardCharsets
SimpMessageHeaderAccessor simpHeaderAccessor =
SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE);
simpHeaderAccessor.setSessionId(sessionId);
simpHeaderAccessor.setContentType(new MimeType("application", "json",
StandardCharsets.UTF_8));
simpHeaderAccessor.setLeaveMutable(true);
// Instead of returning to send the message, use the [messagingTemplate] instead.
// It will ensure that it will only broadcast the message to the specific
// STOMP WebSocket sessionId.
// return new ResponseEntity(errors, HttpStatus.UNPROCESSABLE_ENTITY);
messagingTemplate.convertAndSendToUser(sessionId, "/api/secure/broadcast",
errors, simpHeaderAccessor.getMessageHeaders());
}
}
如果您在控制器方法参数上使用 @ResponseBody @Valid
,则必须将逻辑行移动到 ControllerAdvice
exceptionHandler()
.
我在 Springboot 上使用 STOMP websocket
并想限制对特定页面的广播。这是我的过程:
User
将消息填入 HTML 输入。- 浏览器将通过 STOMP 客户端发送消息。
- 服务器接收消息并验证它。如果消息有效,它将向用户处理的所有选项卡广播
User
已发送消息。如果它无效,它会发回错误消息 仅发送到发送消息的特定浏览器选项卡 而不是其他选项卡,即使这些选项卡具有相同的User
记录英寸
虽然我不能限制将错误消息发送到特定选项卡,但我已经使它的某些部分起作用,它总是将错误消息广播到共享相同 User
的所有选项卡。这是我的初始代码:
@MessageMapping("/api/secure/message")
@SendToUser("/api/secure/broadcast")
public HttpEntity createMessage(Message message, Authentication authentication) throws Exception {
Set<String> errors = TreeSet<String>();
// Process Message message and add every exceptions encountered to Set errors.
boolean valid = (errors.size() > 0);
if(valid) {
// Broadcast to all.
return new ResponseEntity(message, HttpStatus.OK);
}
else {
// Send the message to that particular tab only.
return new ResponseEntity(errors, HttpStatus.UNPROCESSABLE_ENTITY);
}
}
这可以通过 websocket
实现吗?或者我应该 return 回到 XHR
?
对于每个选项卡,您都将创建一个新的 websocket 会话,因此您的 stomp session-id 也会有所不同。因此我们可以决定是发送到特定会话还是特定用户的所有会话。
@Autowired
private SimpMessagingTemplate template;
....
@MessageMapping(...)
public void sendMessage(Message<?> message...) {
.....
StompHeaderAccessor headerAccessor =
StompHeaderAccessor.wrap(message);
String sessionId = headerAccessor.getSessionId();
....
if(valid) {
//Not specifying session Id so sends all users of
<user_name>
template.cnvertAndSendToUser(<user_name>,
<destination>, <payload>)
}
else {
SimpMessageHeaderAccessor headerAccessor =
SimpMessagingHeaderAccessor.create(SimpMessageType.MESSAGE);
headerAccessor.setSessionId(sessionId);
//This will send it to particular session.
template.convertAndSendToUser(<user_name>,
<destination>, <payload>,
headerAccessor.getMessageHeaders());
}
}
有用的参考资料:
用户@Srinivas 提供了一个很好的起始参考点。我已经用我的工作代码修改了问题中的代码块:
// inject the [messagingTemplate] bean.
// class org.springframework.messaging.simp.SimpMessagingTemplate
@Autowired
private SimpMessagingTemplate messagingTemplate;
@MessageMapping("/api/secure/message")
// Remove the @SendToUser annotation and change return type to void.
// @SendToUser("/api/secure/broadcast")
// public HttpEntity createMessage(Message message…
public void createMessage(Message message, Authentication authentication) throws Exception {
Set<String> errors = TreeSet<String>();
// Process Message message and add every exceptions encountered to Set errors.
boolean valid = (errors.size() > 0);
if(valid) {
// Broadcast to all.
// Instead of returning to send the message, use the [messagingTemplate] instead.
// return new ResponseEntity(message, HttpStatus.OK);
messagingTemplate.convertAndSendToUser("/api/secure/broadcast", errors);
}
else {
// Send the message to that particular tab only.
// Each STOMP WebSocket connection has a unique ID that effectively differentiate
// it to the other browser tabs. Retrieve that ID so we can target that specific
// tab to send our error message with.
// class org.springframework.messaging.simp.stomp.StompHeaderAccessor
StompHeaderAccessor stompHeaderAccessor = StompHeaderAccessor.wrap(message);
String sessionId = stompHeaderAccessor.getSessionId();
// class org.springframework.messaging.simp.SimpMessageHeaderAccessor
// class org.springframework.messaging.simp.SimpMessageType
// class org.springframework.util.MimeType
// class java.nio.charset.StandardCharsets
SimpMessageHeaderAccessor simpHeaderAccessor =
SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE);
simpHeaderAccessor.setSessionId(sessionId);
simpHeaderAccessor.setContentType(new MimeType("application", "json",
StandardCharsets.UTF_8));
simpHeaderAccessor.setLeaveMutable(true);
// Instead of returning to send the message, use the [messagingTemplate] instead.
// It will ensure that it will only broadcast the message to the specific
// STOMP WebSocket sessionId.
// return new ResponseEntity(errors, HttpStatus.UNPROCESSABLE_ENTITY);
messagingTemplate.convertAndSendToUser(sessionId, "/api/secure/broadcast",
errors, simpHeaderAccessor.getMessageHeaders());
}
}
如果您在控制器方法参数上使用 @ResponseBody @Valid
,则必须将逻辑行移动到 ControllerAdvice
exceptionHandler()
.