帶註解的控制器

應用程式可以使用帶註解的 @Controller 類來處理來自客戶端的訊息。此類可以宣告 @MessageMapping@SubscribeMapping@ExceptionHandler 方法,如下所述:

@MessageMapping

您可以使用 @MessageMapping 註解方法,根據訊息目的地路由訊息。它支援方法級別和型別級別。在型別級別上,@MessageMapping 用於表示控制器中所有方法共享的對映。

預設情況下,對映值是 Ant 風格的路徑模式(例如 /thing*/thing/**),包括支援模板變數(例如 /thing/{id})。這些值可以透過 @DestinationVariable 方法引數引用。應用程式還可以切換到以點分隔的目的地約定進行對映,如作為分隔符的點中所述。

支援的方法引數

下表描述了方法引數:

方法引數 描述

Message

用於訪問完整訊息。

MessageHeaders

用於訪問 Message 中的頭部。

MessageHeaderAccessorSimpMessageHeaderAccessorStompHeaderAccessor

透過型別化訪問器方法訪問頭部。

@Payload

用於訪問訊息負載,透過配置的 MessageConverter 進行轉換(例如,從 JSON)。

此註解不是必需的,因為它在預設情況下,如果沒有其他引數匹配,則假定存在。

您可以使用 @jakarta.validation.Valid 或 Spring 的 @Validated 註解負載引數,以便自動驗證負載引數。

@Header

用於訪問特定頭部值 — 必要時,透過 org.springframework.core.convert.converter.Converter 進行型別轉換。

@Headers

用於訪問訊息中的所有頭部。此引數必須可賦值給 java.util.Map

@DestinationVariable

用於訪問從訊息目的地提取的模板變數。必要時,將值轉換為宣告的方法引數型別。

java.security.Principal

反映 WebSocket HTTP 握手時登入的使用者。

返回值

預設情況下,@MessageMapping 方法的返回值透過匹配的 MessageConverter 序列化為負載,並作為 Message 傳送到 brokerChannel,然後從那裡廣播給訂閱者。出站訊息的目的地與入站訊息的目的地相同,但字首為 /topic

您可以使用 @SendTo@SendToUser 註解自定義輸出訊息的目的地。@SendTo 用於自定義目標目的地或指定多個目的地。@SendToUser 用於將輸出訊息僅傳送給與輸入訊息關聯的使用者。請參閱使用者目的地

您可以在同一方法上同時使用 @SendTo@SendToUser,並且它們都支援在類級別使用,在這種情況下,它們充當類中方法的預設值。但是,請記住,任何方法級別的 @SendTo@SendToUser 註解都會覆蓋類級別的任何此類註解。

訊息可以非同步處理,@MessageMapping 方法可以返回 ListenableFutureCompletableFutureCompletionStage

請注意,@SendTo@SendToUser 僅僅是方便用法,相當於使用 SimpMessagingTemplate 傳送訊息。如果需要,對於更高階的場景,@MessageMapping 方法可以直接使用 SimpMessagingTemplate。這可以代替或可能額外返回一個值。請參閱傳送訊息

@SubscribeMapping

@SubscribeMapping 類似於 @MessageMapping,但將對映範圍縮小到僅訂閱訊息。它支援與 @MessageMapping 相同的方法引數。但是對於返回值,預設情況下,訊息直接傳送到客戶端(透過 clientOutboundChannel,作為對訂閱的響應),而不是傳送到代理(透過 brokerChannel,作為對匹配訂閱的廣播)。新增 @SendTo@SendToUser 會覆蓋此行為,並改為傳送到代理。

這何時有用?假設代理對映到 /topic/queue,而應用程式控制器對映到 /app。在這種設定下,代理儲存所有旨在重複廣播的 /topic/queue 訂閱,應用程式無需參與。客戶端也可以訂閱某個 /app 目的地,控制器可以響應該訂閱返回一個值,而無需涉及代理,也無需再次儲存或使用該訂閱(實際上是一次性請求-回覆交換)。一個用例是在啟動時用初始資料填充 UI。

這何時無用?除非您希望代理和控制器都以某種原因獨立處理訊息(包括訂閱),否則不要嘗試將它們對映到相同的字首。入站訊息是並行處理的。無法保證代理或控制器首先處理給定訊息。如果目標是在訂閱儲存並準備好進行廣播時收到通知,如果伺服器支援(簡單代理不支援),客戶端應該請求收據。例如,使用 Java STOMP 客戶端,您可以執行以下操作來新增收據:

@Autowired
private TaskScheduler messageBrokerTaskScheduler;

// During initialization..
stompClient.setTaskScheduler(this.messageBrokerTaskScheduler);

// When subscribing..
StompHeaders headers = new StompHeaders();
headers.setDestination("/topic/...");
headers.setReceipt("r1");
FrameHandler handler = ...;
stompSession.subscribe(headers, handler).addReceiptTask(receiptHeaders -> {
	// Subscription ready...
});

伺服器端選項是在 brokerChannel註冊一個 ExecutorChannelInterceptor 並實現 afterMessageHandled 方法,該方法在訊息(包括訂閱)處理後呼叫。

@MessageExceptionHandler

應用程式可以使用 @MessageExceptionHandler 方法來處理來自 @MessageMapping 方法的異常。您可以在註解本身中宣告異常,或者如果您想訪問異常例項,可以透過方法引數宣告。以下示例透過方法引數宣告異常:

@Controller
public class MyController {

	// ...

	@MessageExceptionHandler
	public ApplicationError handleException(MyException exception) {
		// ...
		return appError;
	}
}

@MessageExceptionHandler 方法支援靈活的方法簽名,並支援與 @MessageMapping 方法相同的方法引數型別和返回值。

通常,@MessageExceptionHandler 方法適用於它們宣告的 @Controller 類(或類層次結構)中。如果您希望這些方法更全域性地應用(跨控制器),您可以在用 @ControllerAdvice 標記的類中宣告它們。這與 Spring MVC 中可用的類似支援相當。

© . This site is unofficial and not affiliated with VMware.