6.26.2 Using @ClientWebSocket
The @ClientWebSocket annotation can be used with the WebSocketClient interface to define WebSocket clients.
You can inject a reference to a WebSocketClient using the @Client annotation:
@Inject
@Client("http://localhost:8080")
RxWebSocketClient webSocketClient;
This lets you use the same service discovery and load balancing features for WebSocket clients.
Once you have a reference to the WebSocketClient interface you can use the connect
method to obtain a connected instance of a bean annotated with @ClientWebSocket.
For example consider the following implementation:
WebSocket Chat Example
import io.micronaut.http.HttpRequest;
import io.micronaut.websocket.WebSocketSession;
import io.micronaut.websocket.annotation.ClientWebSocket;
import io.micronaut.websocket.annotation.OnMessage;
import io.micronaut.websocket.annotation.OnOpen;
import org.reactivestreams.Publisher;
import io.micronaut.core.async.annotation.SingleResult;
import java.util.Collection;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Future;
@ClientWebSocket("/chat/{topic}/{username}") (1)
public abstract class ChatClientWebSocket implements AutoCloseable { (2)
private WebSocketSession session;
private HttpRequest request;
private String topic;
private String username;
private Collection<String> replies = new ConcurrentLinkedQueue<>();
@OnOpen
public void onOpen(String topic, String username,
WebSocketSession session, HttpRequest request) { (3)
this.topic = topic;
this.username = username;
this.session = session;
this.request = request;
}
public String getTopic() {
return topic;
}
public String getUsername() {
return username;
}
public Collection<String> getReplies() {
return replies;
}
public WebSocketSession getSession() {
return session;
}
public HttpRequest getRequest() {
return request;
}
@OnMessage
public void onMessage(String message) {
replies.add(message); (4)
}
WebSocket Chat Example
import io.micronaut.http.HttpRequest
import io.micronaut.websocket.WebSocketSession
import io.micronaut.websocket.annotation.ClientWebSocket
import io.micronaut.websocket.annotation.OnMessage
import io.micronaut.websocket.annotation.OnOpen
import org.reactivestreams.Publisher
import reactor.core.publisher.Mono
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.Future
import io.micronaut.core.async.annotation.SingleResult
@ClientWebSocket("/chat/{topic}/{username}") (1)
abstract class ChatClientWebSocket implements AutoCloseable { (2)
private WebSocketSession session
private HttpRequest request
private String topic
private String username
private Collection<String> replies = new ConcurrentLinkedQueue<>()
@OnOpen
void onOpen(String topic, String username,
WebSocketSession session, HttpRequest request) { (3)
this.topic = topic
this.username = username
this.session = session
this.request = request
}
String getTopic() {
topic
}
String getUsername() {
username
}
Collection<String> getReplies() {
replies
}
WebSocketSession getSession() {
session
}
HttpRequest getRequest() {
request
}
@OnMessage
void onMessage(String message) {
replies << message (4)
}
WebSocket Chat Example
import io.micronaut.http.HttpRequest
import io.micronaut.websocket.WebSocketSession
import io.micronaut.websocket.annotation.ClientWebSocket
import io.micronaut.websocket.annotation.OnMessage
import io.micronaut.websocket.annotation.OnOpen
import reactor.core.publisher.Mono
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.Future
@ClientWebSocket("/chat/{topic}/{username}") (1)
abstract class ChatClientWebSocket : AutoCloseable { (2)
var session: WebSocketSession? = null
private set
var request: HttpRequest<*>? = null
private set
var topic: String? = null
private set
var username: String? = null
private set
private val replies = ConcurrentLinkedQueue<String>()
@OnOpen
fun onOpen(topic: String, username: String,
session: WebSocketSession, request: HttpRequest<*>) { (3)
this.topic = topic
this.username = username
this.session = session
this.request = request
}
fun getReplies(): Collection<String> {
return replies
}
@OnMessage
fun onMessage(message: String) {
replies.add(message) (4)
}
1 | The class is abstract (more on that later) and is annotated with @ClientWebSocket |
2 | The client must implement AutoCloseable and you should ensure that the connection is closed at some point. |
3 | You can use the same annotations as on the server, in this case @OnOpen to obtain a reference to the underlying session. |
4 | The @OnMessage annotation defines the method that receives responses from the server. |
You can also define abstract methods that start with either send
or broadcast
and these methods will be implemented for you at compile time. For example:
WebSocket Send Methods
public abstract void send(String message);
Note by returning void
this tells Micronaut that the method is a blocking send. You can instead define methods that return either futures or a Publisher:
WebSocket Send Methods
public abstract reactor.core.publisher.Mono<String> send(String message);
The above example defines a send method that returns a reactor:Mono[].
WebSocket Send Methods
public abstract java.util.concurrent.Future<String> sendAsync(String message);
The above example defines a send method that executes asynchronously and returns a Future to access the results.
Once you have defined a client class you can connect to the client socket and start sending messages:
Connecting a Client WebSocket
ChatClientWebSocket chatClient = webSocketClient
.connect(ChatClientWebSocket.class, "/chat/football/fred")
.blockFirst();
chatClient.send("Hello World!");
For illustration purposes we use blockFirst() to obtain the client. It is however possible to combine connect (which returns a reactor:Flux[]) to perform non-blocking interaction via WebSocket. |
Using the CLI If you created your project using the Micronaut CLI and the default (
|