提交 3b4c7a40 编写于 作者: R Rossen Stoyanchev

Improve docs on @Controller methods in STOMP section

Issue: SPR-16631
上级 c5631792
......@@ -1205,82 +1205,146 @@ kinds of arguments and return values supported.
[[websocket-stomp-handle-annotations]]
=== Handler methods
=== Annotated Controllers
The `@MessageMapping` annotation is supported on methods of `@Controller` classes.
It can be used for mapping methods to message destinations and can also be combined
with the type-level `@MessageMapping` for expressing shared mappings across all
annotated methods within a controller.
Applications can use annotated `@Controller` classes to handle messages from clients.
Such classes can declare `@MessageMapping`, `@SubscribeMapping`, and `@ExceptionHandler`
methods as described next.
By default destination mappings are treated as Ant-style, slash-separated, path
patterns, e.g. "/foo*", "/foo/**". etc. They can also contain template variables,
e.g. "/foo/{id}" that can then be referenced via `@DestinationVariable`-annotated
method arguments.
[NOTE]
[[websocket-stomp-message-mapping]]
==== `@MessageMapping`
The `@MessageMapping` annotation can be used on methods to route messages based on their
destination. It is supported at the method level as well as at the type level. At type
level `@MessageMapping` is used to express shared mappings across all methods in a
controller.
By default destination mappings are expected to be Ant-style, path patterns, e.g. "/foo*",
"/foo/**". The patterns include support for template variables, e.g. "/foo/{id}", that can
be referenced with `@DestinationVariable` method arguments.
[TIP]
====
Applications can also use dot-separated destinations (vs slash).
Applications can choose to switch to a dot-separated destination convention.
See <<websocket-stomp-destination-separator>>.
====
The following method arguments are supported for `@MessageMapping` methods:
* `Message` method argument to get access to the complete message being processed.
* `@Payload`-annotated argument for access to the payload of a message, converted with
a `org.springframework.messaging.converter.MessageConverter`.
The presence of the annotation is not required since it is assumed by default.
Payload method arguments annotated with validation annotations (like `@Validated`) will
be subject to JSR-303 validation.
* `@Header`-annotated arguments for access to a specific header value along with
type conversion using an `org.springframework.core.convert.converter.Converter`
if necessary.
* `@Headers`-annotated method argument that must also be assignable to `java.util.Map`
for access to all headers in the message.
* `MessageHeaders` method argument for getting access to a map of all headers.
* `MessageHeaderAccessor`, `SimpMessageHeaderAccessor`, or `StompHeaderAccessor`
for access to headers via typed accessor methods.
* `@DestinationVariable`-annotated arguments for access to template
variables extracted from the message destination. Values will be converted to
the declared method argument type as necessary.
* `java.security.Principal` method arguments reflecting the user logged in at
the time of the WebSocket HTTP handshake.
A return value from an `@MessageMapping` method will be converted with a
`org.springframework.messaging.converter.MessageConverter` and used as the body
of a new message that is then sent, by default, to the `"brokerChannel"` with
the same destination as the client message but using the prefix `"/topic"` by
default. An `@SendTo` message level annotation can be used to specify any
other destination instead. It can also be set a class-level to share a common
`@MessageMapping` methods can have flexible signatures with the following arguments:
[cols="1,2", options="header"]
|===
| Method argument | Description
| `Message`
| For access to the complete message.
| `MessageHeaders`
| For access to the headers within the `Message`.
| `MessageHeaderAccessor`, `SimpMessageHeaderAccessor`, `StompHeaderAccessor`
| For access to the headers via typed accessor methods.
| `@Payload`
| For access to the payload of the message, converted (e.g. from JSON) via a configured
`MessageConverter`.
The presence of this annotation is not required since it is assumed by default if no
other argument is matched.
Payload arguments may be annotated with `@javax.validation.Valid` or Spring's `@Validated`
in order to be automatically validated.
| `@Header`
| For access to a specific header value along with type conversion using an
`org.springframework.core.convert.converter.Converter` if necessary.
| `@Headers`
| For access to all headers in the message. This argument must be assignable to
`java.util.Map`.
| `@DestinationVariable`
| For access to template variables extracted from the message destination.
Values will be converted to the declared method argument type as necessary.
| `java.security.Principal`
| Reflects the user logged in at the time of the WebSocket HTTP handshake.
|===
When an `@MessageMapping` method returns a value, by default the value is serialized to
a payload through a configured `MessageConverter`, and then 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"`.
You can use the `@SendTo` method annotation to customize the destination to send
the payload to. `@SendTo` can also be used at the class level to share a default target
destination to send messages to. `@SendToUser` is an variant for sending messages only to
the user associated with a message. See <<websocket-stomp-user-destination>> for details.
The return value from an `@MessageMapping` method may be wrapped with `ListenableFuture`,
`CompletableFuture`, or `CompletionStage` in order to produce the payload asynchronously.
As an alternative to returning a payload from an `@MessageMapping` method you can also
send messages using the `SimpMessagingTemplate`, which is also how return values are
handled under the covers. See <<websocket-stomp-handle-send>>.
[[websocket-stomp-subscribe-mapping]]
==== `@SubscribeMapping`
The `@SubscribeMapping` annotation is used in combination with `@MessageMapping` in order
to narrow the mapping to subscription messages. In such scenarios, the `@MessageMapping`
annotation specifies the destination while `@SubscribeMapping` indicates interest in
subscription messages only.
An `@SubscribeMapping` method is generally no different from any `@MessageMapping`
method with respect to mapping and input arguments. For example you can combine it with a
type-level `@MessageMapping` to express a shared destination prefix, and you can use the
same <<websocket-stomp-message-mapping,method arguments>> as on any @MessageMapping` method.
The key difference with `@SubscribeMapping` is that the return value of the method is
serialized as a payload and sent, not to the "brokerChannel" but to the
"clientOutboundChannel", effectively replying directly to the client rather than
broadcasting through the broker. This is useful for implementing one-off, request-reply
message exchanges, and never holding on to the subscription. A common scenario for this
pattern is application initialization when data must be loaded and presented.
A `@SubscribeMapping` method can also be annotated with `@SendTo` in which case the
return value is sent to the `"brokerChannel"` with the explicitly specified target
destination.
A response message may also be provided asynchronously via a `ListenableFuture`
or `CompletableFuture`/`CompletionStage` return type signature, analogous to
deferred results in an MVC handler method.
A `@SubscribeMapping` annotation can be used to map subscription requests to
`@Controller` methods. It is supported on the method level, but can also be
combined with a type level `@MessageMapping` annotation that expresses shared
mappings across all message handling methods within the same controller.
[[websocket-stomp-exception-handler]]
==== `@MessageExceptionHandler`
By default the return value from an `@SubscribeMapping` method is sent as a
message directly back to the connected client and does not pass through the
broker. This is useful for implementing request-reply message interactions; for
example, to fetch application data when the application UI is being initialized.
Or alternatively an `@SubscribeMapping` method can be annotated with `@SendTo`
in which case the resulting message is sent to the `"brokerChannel"` using
the specified target destination.
An application can use `@MessageExceptionHandler` methods to handle exceptions from
`@MessageMapping` methods. Exceptions of interest can be declared in the annotation
itself, or through a method argument if you want to get access to the exception instance:
[NOTE]
====
In some cases a controller may need to be decorated with an AOP proxy at runtime.
One example is if you choose to have `@Transactional` annotations directly on the
controller. When this is the case, for controllers specifically, we recommend
using class-based proxying. This is typically the default choice with controllers.
However if a controller must implement an interface that is not a Spring Context
callback (e.g. `InitializingBean`, `*Aware`, etc), you may need to explicitly
configure class-based proxying. For example with `<tx:annotation-driven />`,
change to `<tx:annotation-driven proxy-target-class="true" />`.
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@Controller
public class MyController {
// ...
@MessageExceptionHandler
public ApplicationError handleException(MyException exception) {
// ...
return appError;
}
}
----
`@MessageExceptionHandler` methods support flexible method signatures and support the same
method argument types and return values as <<websocket-stomp-message-mapping>> methods.
Typically `@MessageExceptionHandler` methods apply within the `@Controller` class (or
class hierarchy) they are declared in. 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 <<web.adoc#mvc-ann-controller-advice,similar support>> in Spring MVC.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册