註解控制器
應用程式可以使用帶有 @Controller
註解的類別來處理來自客户端的訊息。此類類別可以宣告 @MessageMapping
、@SubscribeMapping
和 @ExceptionHandler
方法,如下列主題所述
@MessageMapping
您可以使用 @MessageMapping
來註解根據目的地路由訊息的方法。它在方法層級和型別層級都受到支援。在型別層級,@MessageMapping
用於表達控制器中所有方法共用的對應。
預設情況下,對應值是 Ant 樣式的路徑模式(例如 /thing*
、/thing/**
),包括對範本變數的支援(例如,/thing/{id}
)。這些值可以透過 @DestinationVariable
方法引數來參考。應用程式也可以切換到以點分隔的目的地慣例來進行對應,如點作為分隔符號中所述。
支援的方法引數
下表描述了方法引數
方法引數 | 描述 |
---|---|
|
用於存取完整訊息。 |
|
用於存取 |
|
用於透過型別化的存取器方法存取標頭。 |
|
用於存取訊息的酬載,由組態的 由於預設情況下,如果沒有其他引數匹配,則會假定存在此註解,因此不需要存在此註解。 您可以使用 |
|
用於存取特定的標頭值,並在必要時使用 |
|
用於存取訊息中的所有標頭。此引數必須可指派給 |
|
用於存取從訊息目的地擷取的範本變數。值會根據需要轉換為宣告的方法引數型別。 |
|
反映 WebSocket HTTP 握手時登入的使用者。 |
傳回值
預設情況下,@MessageMapping
方法的傳回值會透過匹配的 MessageConverter
序列化為酬載,並作為 Message
傳送到 brokerChannel
,然後從那裡廣播給訂閱者。輸出訊息的目的地與輸入訊息的目的地相同,但以 /topic
為前綴。
您可以使用 @SendTo
和 @SendToUser
註解來自訂輸出訊息的目的地。@SendTo
用於自訂目標目的地或指定多個目的地。@SendToUser
用於將輸出訊息僅導向到與輸入訊息相關聯的使用者。請參閱使用者目的地。
您可以同時在同一個方法上使用 @SendTo
和 @SendToUser
,並且兩者都在類別層級受到支援,在這種情況下,它們充當類別中方法的預設值。但是,請記住,任何方法層級的 @SendTo
或 @SendToUser
註解都會覆寫類別層級的任何此類註解。
訊息可以非同步處理,而 @MessageMapping
方法可以傳回 ListenableFuture
、CompletableFuture
或 CompletionStage
。
請注意,@SendTo
和 @SendToUser
僅僅是一種便利,相當於使用 SimpMessagingTemplate
來傳送訊息。如有必要,對於更進階的場景,@MessageMapping
方法可以退回到直接使用 SimpMessagingTemplate
。這可以取代或可能除了傳回值之外完成。請參閱傳送訊息。
@SubscribeMapping
@SubscribeMapping
類似於 @MessageMapping
,但將對應範圍縮小到僅限訂閱訊息。它支援與 @MessageMapping
相同的方法引數。但是對於傳回值,預設情況下,訊息會直接傳送到客户端(透過 clientOutboundChannel
,以回應訂閱),而不是傳送到 Broker(透過 brokerChannel
,作為對匹配訂閱的廣播)。新增 @SendTo
或 @SendToUser
會覆寫此行為,並改為傳送到 Broker。
這在什麼時候有用?假設 Broker 對應到 /topic
和 /queue
,而應用程式控制器對應到 /app
。在此設定中,Broker 儲存所有針對 /topic
和 /queue
的訂閱,這些訂閱旨在用於重複廣播,並且應用程式無需介入。客户端也可以訂閱某些 /app
目的地,而控制器可以傳回一個值以回應該訂閱,而無需 Broker 參與,也無需再次儲存或使用該訂閱(有效地說是一次性的請求-回覆交換)。這種情況的一個用例是在啟動時使用初始資料填充 UI。
這在什麼時候沒有用?除非您希望 Broker 和控制器都獨立處理訊息(包括訂閱),否則請勿嘗試將 Broker 和控制器對應到相同的目的地前綴。傳入訊息是平行處理的。無法保證 Broker 或控制器哪個先處理給定的訊息。如果目標是在儲存訂閱並準備好進行廣播時收到通知,則如果伺服器支援回條,客户端應要求回條(簡單 Broker 不支援)。例如,使用 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...
});
伺服器端選項是註冊 ExecutorChannelInterceptor
在 brokerChannel
上,並實作 afterMessageHandled
方法,該方法在訊息(包括訂閱)處理完畢後調用。
@MessageExceptionHandler
應用程式可以使用 @MessageExceptionHandler
方法來處理來自 @MessageMapping
方法的例外。您可以在註解本身中宣告例外,或者如果您想存取例外實例,可以透過方法引數來宣告。以下範例透過方法引數宣告例外
@Controller
public class MyController {
// ...
@MessageExceptionHandler
public ApplicationError handleException(MyException exception) {
// ...
return appError;
}
}
@MessageExceptionHandler
方法支援彈性的方法簽章,並支援與 @MessageMapping
方法相同的方法引數型別和傳回值。
通常,@MessageExceptionHandler
方法在其宣告的 @Controller
類別(或類別階層)中應用。如果您希望這些方法更全域地應用(跨控制器),則可以在標記為 @ControllerAdvice
的類別中宣告它們。這與 Spring MVC 中提供的類似支援相當。