使用者目的地
應用可以傳送針對特定使用者的訊息,Spring 的 STOMP 支援為此目的識別以 /user/
為字首的目的地。例如,客戶端可以訂閱 /user/queue/position-updates
這個目的地。UserDestinationMessageHandler
會處理這個目的地,並將其轉換為使用者會話獨有的目的地(例如 /queue/position-updates-user123
)。這提供了訂閱通用命名目的地的便利,同時確保不會與訂閱同一目的地的其他使用者發生衝突,從而使每個使用者都能接收到獨特的股票倉位更新。
使用使用者目的地時,請務必按照啟用 STOMP 中所示配置 broker 和應用目的地字首,否則 broker 將處理本應只由 UserDestinationMessageHandler 處理的以 "/user" 為字首的訊息。 |
在傳送端,可以將訊息傳送到 /user/{username}/queue/position-updates
這樣的目的地,這隨後會被 UserDestinationMessageHandler
轉換成一個或多個目的地,使用者關聯的每個會話對應一個。這使得應用中的任何元件都可以傳送針對特定使用者的訊息,而無需知道除了使用者名稱和通用目的地以外的任何資訊。這也透過註解和訊息模板得到支援。
訊息處理方法可以透過 @SendToUser
註解向與正在處理的訊息關聯的使用者傳送訊息(該註解也支援在類級別使用以共享通用目的地),如下例所示:
@Controller
public class PortfolioController {
@MessageMapping("/trade")
@SendToUser("/queue/position-updates")
public TradeResult executeTrade(Trade trade, Principal principal) {
// ...
return tradeResult;
}
}
如果使用者有多個會話,預設情況下,訂閱了給定目的地的所有會話都會成為目標。然而,有時可能只需針對傳送正在處理訊息的會話。可以透過將 broadcast
屬性設定為 false 來實現這一點,如下例所示:
@Controller
public class MyController {
@MessageMapping("/action")
public void handleAction() throws Exception{
// raise MyBusinessException here
}
@MessageExceptionHandler
@SendToUser(destinations="/queue/errors", broadcast=false)
public ApplicationError handleException(MyBusinessException exception) {
// ...
return appError;
}
}
雖然使用者目的地通常意味著一個認證使用者,但這並不是嚴格要求。未關聯認證使用者的 WebSocket 會話也可以訂閱使用者目的地。在這種情況下,@SendToUser 註解的行為與 broadcast=false 完全相同(即只針對傳送正在處理訊息的會話)。 |
你可以從任何應用元件向用戶目的地傳送訊息,例如,透過注入由 Java 配置或 XML 名稱空間建立的 SimpMessagingTemplate
。(如果需要使用 @Qualifier
進行限定,bean 名稱為 brokerMessagingTemplate
。)下例展示瞭如何做到:
@Service
public class TradeServiceImpl implements TradeService {
private final SimpMessagingTemplate messagingTemplate;
@Autowired
public TradeServiceImpl(SimpMessagingTemplate messagingTemplate) {
this.messagingTemplate = messagingTemplate;
}
// ...
public void afterTradeExecuted(Trade trade) {
this.messagingTemplate.convertAndSendToUser(
trade.getUserName(), "/queue/position-updates", trade.getResult());
}
}
當使用外部訊息 broker 與使用者目的地結合時,你應該查閱 broker 文件瞭解如何管理非活躍佇列,以便在使用者會話結束後,所有獨有的使用者佇列都會被移除。例如,當你使用 /exchange/amq.direct/position-updates 這樣的目的地時,RabbitMQ 會建立自動刪除佇列。因此,在這種情況下,客戶端可以訂閱 /user/exchange/amq.direct/position-updates 。類似地,ActiveMQ 也有用於清除非活躍目的地的配置選項。 |
在多應用伺服器場景中,使用者目的地可能因為使用者連線到不同的伺服器而無法解析。在這種情況下,你可以配置一個目的地來廣播未解析的訊息,以便其他伺服器有機會嘗試。這可以透過 Java 配置中的 MessageBrokerRegistry
的 userDestinationBroadcast
屬性以及 XML 中 message-broker
元素的 user-destination-broadcast
屬性來完成。