Location>code7788 >text

Solon's STOMP

Popularity:982 ℃/2024-10-23 21:43:02

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.@ToThe 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!"})
});