1. Обзор
В этой статье мы создадим краткий пример использования нового API WebSockets Spring 5 вместе с реактивными функциями, предоставляемыми Spring WebFlux.
WebSocket-это хорошо известный протокол, который обеспечивает полнодуплексную связь между клиентом и сервером, обычно используемый в веб-приложениях, где клиент и сервер должны обмениваться событиями с высокой частотой и с низкой задержкой.
Spring Framework 5 модернизировал поддержку WebSockets в рамках, добавив реактивные возможности в этот канал связи.
Мы можем найти больше на Spring Web Flux здесь .
2. Зависимости Maven
Мы собираемся использовать зависимости spring-boot-starters для spring-boot-integration и spring-boot-starter-web flux , доступные в настоящее время в репозитории Spring Milestone .
В этом примере мы используем последнюю доступную версию 2.0.0.M7, но всегда следует получать последнюю версию, доступную в репозитории Maven:
org.springframework.boot spring-boot-starter-integration org.springframework.boot spring-boot-starter-webflux
3. Конфигурация WebSocket весной
Наша конфигурация довольно проста: мы введем WebSocketHandler для обработки сеанса сокета в нашем приложении Spring WebSocket.
@Autowired private WebSocketHandler webSocketHandler;
Кроме того, давайте создадим метод Handler Mapping bean-аннотированный метод, который будет отвечать за сопоставление между запросами и объектами обработчика:
@Bean public HandlerMapping webSocketHandlerMapping() { Mapmap = new HashMap<>(); map.put("/event-emitter", webSocketHandler); SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping(); handlerMapping.setOrder(1); handlerMapping.setUrlMap(map); return handlerMapping; }
URL-адрес, к которому мы можем подключиться, будет: ws://localhost:/event-emitter.
4. Обработка сообщений WebSocket весной
Наш класс Reactive WebSocketHandler будет отвечать за управление сеансом WebSocket на стороне сервера.
Он реализует интерфейс WebSocketHandler , поэтому мы можем переопределить метод handle , который будет использоваться для отправки сообщения клиенту WebSocket:
@Component public class ReactiveWebSocketHandler implements WebSocketHandler { // private fields ... @Override public Monohandle(WebSocketSession webSocketSession) { return webSocketSession.send(intervalFlux .map(webSocketSession::textMessage)) .and(webSocketSession.receive() .map(WebSocketMessage::getPayloadAsText) .log()); } }
5. Создание простого реактивного клиента WebSocket
Теперь давайте создадим клиент Spring Reactive WebSocket, который сможет подключаться и обмениваться информацией с нашим сервером WebSocket.
5.1. Зависимость Maven
Во-первых, зависимости Maven.
org.springframework.boot spring-boot-starter-webflux
Здесь мы используем тот же самый поток spring-boot-starter-web, который использовался ранее для настройки нашего реактивного серверного приложения WebSocket.
5.2. Клиент WebSocket
Теперь давайте создадим класс Reactive Client WebSocket , ответственный за запуск связи с сервером:
public class ReactiveJavaClientWebSocket { public static void main(String[] args) throws InterruptedException { WebSocketClient client = new ReactorNettyWebSocketClient(); client.execute( URI.create("ws://localhost:8080/event-emitter"), session -> session.send( Mono.just(session.textMessage("event-spring-reactive-client-websocket"))) .thenMany(session.receive() .map(WebSocketMessage::getPayloadAsText) .log()) .then()) .block(Duration.ofSeconds(10L)); } }
В приведенном выше коде мы видим , что мы используем клиент Reactor Netty WebSocket , который является реализацией WebSocket Client для использования с Reactor Netty.
Кроме того, клиент подключается к серверу WebSocket через URL-адрес ws://localhost:8080/eventemitter, устанавливая сеанс, как только он подключен к серверу.
Мы также видим, что отправляем сообщение на сервер (” event-spring-reactive-client-websocket “) вместе с запросом на подключение.
Кроме того, вызывается метод send , ожидающий в качестве параметра переменную типа Publisher, которая в нашем случае является Publisher /Mono и T представляет собой простую строку “ event-me-from-reactive-java-client-websocket “.
Более того, метод then Many(…) ожидает Вызывается поток типа String . Метод receive() получает поток входящих сообщений, которые позже преобразуются в строки.
Наконец, метод block() заставляет клиента отключиться от сервера через заданное время (10 секунд в нашем примере).
5.3. Запуск Клиента
Чтобы запустить его, убедитесь, что реактивный сервер WebSocket запущен и работает. Затем запустите класс Reactive Java Client WebSocket , и мы увидим в sysout журнал событий, которые будут выданы:
[reactor-http-nio-4] INFO reactor.Flux.Map.1 - onNext({"eventId":"6042b94f-fd02-47a1-911d-dacf97f12ba6", "eventDt":"2018-01-11T23:29:26.900"})
Мы также можем видеть в журнале с нашего реактивного сервера WebSocket сообщение, отправленное клиентом во время попытки подключения:
[reactor-http-nio-2] reactor.Flux.Map.1: onNext(event-me-from-reactive-java-client)
Кроме того, мы можем видеть сообщение о прекращении соединения после того, как клиент завершил свои запросы (в нашем случае через 10 секунд):
[reactor-http-nio-2] reactor.Flux.Map.1: onComplete()
6. Создание клиента WebSocket браузера
Давайте создадим простой HTML/Javascript клиентский WebSocket для использования нашего реактивного серверного приложения WebSocket.
При запущенном сервере WebSocket, открывающем этот HTML-файл в браузере (например, Chrome, Internet Explorer, Mozilla Firefox и т.д.), Мы должны видеть события, печатаемые на экране, с задержкой в 1 секунду на событие, как определено на нашем сервере WebSocket.
{"eventId":"c25975de-6775-4b0b-b974-b396847878e6","eventDt":"2018-01-11T23:56:09.780"} {"eventId":"ac74170b-1f71-49d3-8737-b3f9a8a352f9","eventDt":"2018-01-11T23:56:09.781"} {"eventId":"40d8f305-f252-4c14-86d7-ed134d3e10c6","eventDt":"2018-01-11T23:56:09.782"}
7. Заключение
Здесь мы представили пример того, как создать связь WebSocket между сервером и клиентом с помощью платформы Spring 5, реализующей новые реактивные функции, предоставляемые Spring Webflux.
Как всегда, полный пример можно найти в нашем репозитории GitHub .