I. Introduction to STOMP
Using WebSocket directly would be very tiresome, like writing a web application in Socket. The lack of a high-level interaction protocol requires us to define the semantics of the messages sent between applications, and we also need to make sure that both ends of the connection follow those semantics.
Just as HTTP adds a request-response model layer on top of TCP sockets, STOMP provides a frame-based wire format layer on top of WebSocket to define the semantics of messages.
Similar to HTTP requests and responses, a STOMP frame consists of a command, one or more headers, and a load. A STOMP frame, such as the one below, is one that sends data:
SEND
transaction:tx-0
destination:/app/hello
content-length:20
{"message":"Hello!"}
In this example, the STOMP command is send, indicating that something will be sent. This is followed by three headers: one indicating the transaction mechanism of the message, one indicating the destination to which the message is to be sent, and one containing the size of the load. Then, followed by a blank line, the STOMP frame ends with the contents of the load.
II. Server-side implementation
1、Enable STOMP function
STOMP messages are categorized into three types depending on the prefix. As follows, to/app
messages can be routed to methods annotated with @Mapping; messages beginning with/topic
Messages that start with a/user
The beginning of a message reroutes the message to some user-unique destination.
Adding Dependencies
<dependency>
<groupId></groupId>
<artifactId>solon-net-stomp</artifactId>
</dependency>
Add an endpoint listener and set the broker destination prefix
@ServerEndpoint("/demo")
public class DemoStompBroker extends StompBroker {
public DemoStompBroker() {
("/topic/");
}
}
2、Processing STOMP messages from clients
The server handles STOMP messages from the client, mainly using the@Mapping
annotations (as with MVC development), or you can add the@Message
The way limit is annotated. The following:
@Message //If you don't add,coincide http and other requests
@Mapping("/app/marco")
@To("*:/topic/marco")
public Shout greeting(Shout shout) throws Exception {
("Receive message:" + ());
Shout s = new Shout();
("Polo!");
return s;
}
2.1 @Mapping
Specify that the destination is/app/marco
(which we have agreed to be the destination prefix of the application).
2.2 method takes a Shout parameter because Solon's executor automatically converts the load of a STOMP message to a Shout object depending on the content type.
2.3 In particular, note that this handler method has a return value, which is not returned to the client but forwarded to the message broker, and if the client wants this return value, it can only subscribe to it from the message broker.@To
annotation overrides the destination of the message broker if it is not specified.@To
The destination to which the frame is sent will be the same as the destination that triggered the processor method.
2.4 What if the client just wants the server to return the message directly? Doesn't that sound like something HTTP would do? Even so, STOMP still provides support for this kind of one-time response, using the@Mapping
Note that unlike HTTP, this request-response model is asynchronous...
@Message
@Mapping("/app/getShout")
public Shout getShout(){
Shout shout = new Shout();
("Hello STOMP");
return shout;
}
3、Send a message to the client
3.1 Sending messages anywhere in the application
Using the StompEmitter interface, you can realize the freedom to send messages to any destination.
@Inject
private StompEmitter stompEmitter;
/**
* pass (a bill or inspection etc) http connector,broadcast message
*/
@Http
@Mapping("/broadcastShout")
public void broadcast(Context ctx, Shout shout) {
String json = (shout); //Rendering data
("/topic/shouts", json);
}
3.2 More ways to send messages
What if the message only wants to be sent to a specific user? Or to the current user? Or to all subscribed users? solon-net-stomp gives two ways to accomplish this:
- One is the sendTo method of the StompEmitter interface.
- One is based on the @To annotation.
StompEmitter Interface | corresponding@To explain with notes |
clarification |
---|---|---|
@To("target:destination?") |
To annotation expression (valid for stomp requests) | |
sendToSession |
@To(".:/...") maybe@To(".")
|
Send to current client subscriber |
sendToUser |
@To("user:/...") maybe@To("user")
|
Send to specific user subscribers |
sendTo |
@To("*:/...") maybe@To("*")
|
Send to agent, then forward to all subscribers |
4. Handling message exceptions
When processing a message, it is possible to make an error and throw an exception. Because of the asynchronous nature of STOMP messages, the sender may never know that an error has occurred. Endpoint listening can be adjusted by adding a StompListener implementation.
@ServerEndpoint("/demo")
public class DemoStompBroker extends StompBroker implements StompListener{
public DemoStompBroker(){
//selectable:Adding an authentication listener(this example,Use this class to implement listening)
(this);
("/topic/");
}
@Override
public void onError(StompSession session, Throwable error) {
//selectable:If something goes wrong,Feedback to the client(for example, with "/user/app/errors")
getEmitter().sendToSession(session,
"/user/app/errors",
new Message(()));
}
}
III. Clients
STOMP can be used . Interface Reference:/api-docs/latest/classes/
1. Create a connection and subscribe
let stomp = new ({
brokerURL: "ws://127.0.0.1:8080/demo?user=user01",
onConnect: function (frame) {
("/topic/marco", function (message) {
let obj = ();
("Subscribed server-side messages:" + );
});
("/app/getShout", function (message) {
let obj = ();
("Subscribed server-side should win messages:" + );
});
("/user/app/errors", function (message) {
("Exception messages returned by subscribed servers:" + );
});
}
});
2、Send a message
({
destination: "/app/marco",
headers: {"content-type": "text/json"},
body: ({"message": "Marco!"})
});