使用者目的地

應用可以傳送針對特定使用者的訊息,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 配置中的 MessageBrokerRegistryuserDestinationBroadcast 屬性以及 XML 中 message-broker 元素的 user-destination-broadcast 屬性來完成。