对于最新的稳定版本,请使用 Spring Framework 7.0.6!spring-doc.cadn.net.cn

用户目的地

应用程序可以发送针对特定用户的消息,Spring 的 STOMP 支持会识别以 /user/ 开头的目标地址。 例如,客户端可能会订阅 /user/queue/position-updates 目标地址。 UserDestinationMessageHandler 会处理此目标地址,并将其转换为与用户会话唯一的目标地址(例如 /queue/position-updates-user123)。 这提供了订阅通用名称目标地址的便利性,同时确保与其他订阅相同目标地址的用户不会发生冲突,从而确保每个用户都能收到唯一的股票持仓更新。spring-doc.cadn.net.cn

在处理用户目标时,需要按照 启用 STOMP 中所示配置代理和应用程序目标前缀,否则代理会处理本应由 UserDestinationMessageHandler 处理的 "/user" 前缀消息。

在发送端,消息可以发送到如/user/{username}/queue/position-updates这样的目标,该目标又通过UserDestinationMessageHandler转换为一个或多个目标,每个目标对应与用户相关联的一个会话。这使得应用程序中的任何组件都可以发送针对特定用户的消息,而无需知道除了用户名和通用目标之外的其他信息。这也通过注解和消息模板得到支持。spring-doc.cadn.net.cn

一个消息处理方法可以通过<code>0</code>注解(也支持在类级别上使用,以共享一个共同的目标)将消息发送给与正在处理的消息相关联的用户,如下例所示:spring-doc.cadn.net.cn

@Controller
public class PortfolioController {

	@MessageMapping("/trade")
	@SendToUser("/queue/position-updates")
	public TradeResult executeTrade(Trade trade, Principal principal) {
		// ...
		return tradeResult;
	}
}

如果用户有多个会话,默认情况下,所有订阅到给定目标的会话都会被定位。但是,有时可能需要仅定位正在处理的消息发送的会话。你可以通过将 broadcast 属性设置为 false 来实现,如下例所示:spring-doc.cadn.net.cn

@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命名空间创建的<code>0</code>,将消息发送到用户目标。 (如果需要与<code>2</code>进行限定,bean名称为<code>1</code>。)下面的示例显示了如何操作:spring-doc.cadn.net.cn

@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());
	}
}
当您使用外部消息代理的用户目标时,应查看代理的文档,了解如何管理不活跃的队列,以便在用户会话结束时删除所有唯一的用户队列。例如,RabbitMQ 在使用诸如 /exchange/amq.direct/position-updates 的目标时会创建自动删除的队列。 因此,在这种情况下,客户端可以订阅 /user/exchange/amq.direct/position-updates。 同样,ActiveMQ 也有 配置选项 用于清除不活跃的目标。

在多应用程序服务器的场景中,由于用户连接到不同的服务器,用户目标可能无法解析。在这种情况下,您可以配置一个目标以广播未解析的消息,以便其他服务器有机会尝试。这可以通过Java配置中的userDestinationBroadcast属性和XML中的message-broker元素的user-destination-broadcast属性来完成。spring-doc.cadn.net.cn