Annotated Controllers
@MessageMapping 注释允许控制器映射消息目标,而 @SubscribeMapping 专门用于处理订阅。@MessageExceptionHandler 方法捕获并处理 @MessageMapping 方法中的异常。通过这些注释和方法参数,应用程序可以定制消息处理、返回值和异常处理。
应用程序可以使用带注释的 @Controller
类来处理来自客户端的消息。此类可以声明 @MessageMapping
、@SubscribeMapping
和 @ExceptionHandler
方法,如以下主题中所述:
Applications can use annotated @Controller
classes to handle messages from clients.
Such classes can declare @MessageMapping
, @SubscribeMapping
, and @ExceptionHandler
methods, as described in the following topics:
@MessageMapping
您可以使用 @MessageMapping
为基于目标路由消息的方法加上注释。它在方法级别和类型级别都受支持。在类型级别,@MessageMapping
用于表示控制器中所有方法的共享映射。
You can use @MessageMapping
to annotate methods that route messages based on their
destination. It is supported at the method level as well as at the type level. At the type
level, @MessageMapping
is used to express shared mappings across all methods in a
controller.
默认情况下,映射值是 Ant 样式的路径模式(例如 /thing*
、/thing/**
),包括对模板变量的支持(例如,/thing/{id}
)。可通过 `@DestinationVariable`方法参数来引用这些值。应用程序也可以切换至点分隔的目标约定进行映射,如 Dots as Separators中所述。
By default, the mapping values are Ant-style path patterns (for example /thing*
, /thing/**
),
including support for template variables (for example, /thing/{id}
). The values can be
referenced through @DestinationVariable
method arguments. Applications can also switch to
a dot-separated destination convention for mappings, as explained in
Dots as Separators.
Supported Method Arguments
下表描述了方法参数:
The following table describes the method arguments:
Method argument | Description |
---|---|
|
For access to the complete message. |
|
For access to the headers within the |
|
For access to the headers through typed accessor methods. |
|
For access to the payload of the message, converted (for example, from JSON) by a configured
The presence of this annotation is not required since it is, by default, assumed if no other argument is matched. You can annotate payload arguments with |
|
For access to a specific header value — along with type conversion using an
|
|
For access to all headers in the message. This argument must be assignable to
|
|
For access to template variables extracted from the message destination. Values are converted to the declared method argument type as necessary. |
|
Reflects the user logged in at the time of the WebSocket HTTP handshake. |
Return Values
默认情况下,@MessageMapping
方法的返回值将通过匹配的 MessageConverter
序列化为有效负载,并作为 Message
发送到 brokerChannel
,再从中广播给订阅者。传出消息的目标与传入消息的目标相同,但前缀为 /topic
。
By default, the return value from a @MessageMapping
method is serialized to a payload
through a matching MessageConverter
and sent as a Message
to the brokerChannel
,
from where it is broadcast to subscribers. The destination of the outbound message is the
same as that of the inbound message but prefixed with /topic
.
您可以使用 @SendTo`和 `@SendToUser`注释来自定义输出邮件的目标。
@SendTo`用于自定义目标或指定多个目标。`@SendToUser`用于将输出邮件仅定向到与输入邮件关联的用户。请参阅 User Destinations。
You can use the @SendTo
and @SendToUser
annotations to customize the destination of
the output message. @SendTo
is used to customize the target destination or to
specify multiple destinations. @SendToUser
is used to direct the output message
to only the user associated with the input message. See User Destinations.
你可以在同一个方法上同时使用`@SendTo`和`@SendToUser`,而且它们都可以在类级别支持,在这种情况下,它们充当类中方法的默认值。但是,请记住,任何方法级的`@SendTo`或`@SendToUser`注释都会覆盖类级别的此类注释。
You can use both @SendTo
and @SendToUser
at the same time on the same method, and both
are supported at the class level, in which case they act as a default for methods in the
class. However, keep in mind that any method-level @SendTo
or @SendToUser
annotations
override any such annotations at the class level.
消息可以异步处理,并且`@MessageMapping`方法可以返回`ListenableFuture`、CompletableFuture`或`CompletionStage
。
Messages can be handled asynchronously and a @MessageMapping
method can return
ListenableFuture
, CompletableFuture
, or CompletionStage
.
请注意,@SendTo`和 `@SendToUser`只是方便起见,相当于使用 `SimpMessagingTemplate`来发送邮件。如有必要,对于更高级的场景,
@MessageMapping`方法可以回退至直接使用 SimpMessagingTemplate
。可以执行此操作来代替返回一个值,或者在返回一个值之外执行此操作。请参阅 Sending Messages。
Note that @SendTo
and @SendToUser
are merely a convenience that amounts to using the
SimpMessagingTemplate
to send messages. If necessary, for more advanced scenarios,
@MessageMapping
methods can fall back on using the SimpMessagingTemplate
directly.
This can be done instead of, or possibly in addition to, returning a value.
See Sending Messages.
@SubscribeMapping
@SubscribeMapping`与
@MessageMapping`类似,但仅将映射范围缩小到订阅消息。它支持与`@MessageMapping`相同的method arguments。然而,对于返回值,默认情况下,消息直接发送到客户端(通过`clientOutboundChannel`,以响应订阅),而不是发送到代理(通过`brokerChannel`,作为广播以匹配订阅)。添加`@SendTo`或`@SendToUser`会覆盖此行为,并改为发送到代理。
@SubscribeMapping
is similar to @MessageMapping
but narrows the mapping to
subscription messages only. It supports the same
method arguments as @MessageMapping
. However
for the return value, by default, a message is sent directly to the client (through
clientOutboundChannel
, in response to the subscription) and not to the broker (through
brokerChannel
, as a broadcast to matching subscriptions). Adding @SendTo
or
@SendToUser
overrides this behavior and sends to the broker instead.
什么时候这很有用?假设代理映射到`/topic`和`/queue`,而应用程序控制器映射到`/app`。在此设置中,代理存储所有订阅到`/topic`和`/queue`以用于重复广播,并且应用程序无需参与。客户端还可以订阅一些`/app`目的地,并且控制器可以返回一个值以响应该订阅,而无需涉及代理,无需再次存储或使用该订阅(实际上是一次性请求-响应交换)。一个用例是在启动时使用初始数据填充UI。
When is this useful? Assume that the broker is mapped to /topic
and /queue
, while
application controllers are mapped to /app
. In this setup, the broker stores all
subscriptions to /topic
and /queue
that are intended for repeated broadcasts, and
there is no need for the application to get involved. A client could also subscribe to
some /app
destination, and a controller could return a value in response to that
subscription without involving the broker without storing or using the subscription again
(effectively a one-time request-reply exchange). One use case for this is populating a UI
with initial data on startup.
这样的情况有什么用?除非你想让代理和控制器独立处理消息(包括订阅),否则不要尝试将代理和控制器映射到同一个目标前缀。入站消息会以并行方式进行处理。无法保证代理或控制器会优先处理哪条消息。如果目的是在存储并准备广播订阅时收到通知,那么客户端应该要求回执(如果服务器支持此操作,简单代理不支持)。例如,对于 Java STOMP client,你可以执行以下操作来添加回执:
When is this not useful? Do not try to map broker and controllers to the same destination prefix unless you want both to independently process messages, including subscriptions, for some reason. Inbound messages are handled in parallel. There are no guarantees whether a broker or a controller processes a given message first. If the goal is to be notified when a subscription is stored and ready for broadcasts, a client should ask for a receipt if the server supports it (simple broker does not). For example, with the Java STOMP client, you could do the following to add a receipt:
@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`方法。
A server side option is to register an
ExecutorChannelInterceptor
on the brokerChannel
and implement the afterMessageHandled
method that is invoked after messages, including subscriptions, have been handled.
@MessageExceptionHandler
应用程序可以使用`@MessageExceptionHandler`方法来处理`@MessageMapping`方法中的异常。你可以在注释本身中声明异常,或者通过方法参数来声明,如果你想访问异常实例。以下示例通过方法参数声明异常:
An application can use @MessageExceptionHandler
methods to handle exceptions from
@MessageMapping
methods. You can declare exceptions in the annotation
itself or through a method argument if you want to get access to the exception instance.
The following example declares an exception through a method argument:
@Controller
public class MyController {
// ...
@MessageExceptionHandler
public ApplicationError handleException(MyException exception) {
// ...
return appError;
}
}
@MessageExceptionHandler
方法支持灵活的方法签名,并且支持与 xref:web/websocket/stomp/handle-annotations.adoc#websocket-stomp-message-mapping[@MessageMapping
方法相同的方法参数类型和返回值。
@MessageExceptionHandler
methods support flexible method signatures and support
the same method argument types and return values as
@MessageMapping
methods.
通常情况下,`@MessageExceptionHandler`方法适用于其所属的 `@Controller`类(或类层次结构)中。如果你希望此类方法应用于更广的范围(跨控制器),可以在用 `@ControllerAdvice`标记的类中声明这些方法。这与 Spring MVC 中可用的 similar support类似。
Typically, @MessageExceptionHandler
methods apply within the @Controller
class
(or class hierarchy) in which they are declared. If you want such methods to apply
more globally (across controllers), you can declare them in a class marked with
@ControllerAdvice
. This is comparable to the
similar support available in Spring MVC.