Как сгенерировать случайную строку и вытолкнуть ее с помощью Mono для отображения в браузере каждые X секунд или со случайной задержкой через Spring Reactive?
Я бы хотел, чтобы браузер отображал случайно сгенерированную строку в браузере, как только API
генерирует это, используя Spring Reactive
Mono
.
Ниже приведен пример моей программы, которая работает, генерирует случайную строку и каждую секунду отображает ее в браузере, но страница не загружает никаких новых данных и выглядит как статическая загрузка данных.
@RestController
public class LogTailerController {
@GetMapping(path = "/", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Mono<String> feed() {
return Mono.just("foo-" + Math.random()).delayElement(Duration.ofSeconds(1));
}
}
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
1 ответ
Вы можете посмотреть ConnectableFlux
, что похоже на Flux
, но специально разработан для непрерывного излучения элементов. Вы можете создатьWebClient
объект, который по умолчанию создает Mono через свой метод обмена. Затем просто обратитесь к маршруту, который вы создали в своем классе LogRailerController, чтобы вызвать метод подачи.
public void connectFeed() {
ConnectableFlux<String> printEverySecond = WebClient.create("/") // Since your route is "/"
.post()
.body(...)
.exchange() // produces a Mono object
.flatMap(response -> response.bodyToMono(String.class)) // transformed into a Mono<String>
.flux() // now a Flux<String>
.replay(Duration.of(1, ChronoUnit.SECONDS))
.publish(); // now a ConnectableFlux<String>
printEverySecond.subscribe();
printEverySecond.connect();
}
Вместо того, чтобы использовать post().getBody()
...flatMap(...)
, вы также можете просто использовать get() и вызвать .bodyToMono(String.class)
сразу после .exchange
.
Делая это, вы даже размещаете свой feed()
логика в flatMap. Основная проблема с этой стратегией и при использовании@RestController
Кроме того, время ожидания запроса в конечном итоге истечет, что довольно сложно обойти с помощью RxNetty. С учетом сказанного, я бы рекомендовал иметь отдельный класс компонентов, который вызывает ClientClass.printEverySecond(), когда он возвращается после 10 повторов, или каждые 10 секунд, или как вам кажется лучше. Преимущество этой стратегии перед использованием@RestController
именно то, что его можно вызывать из другого класса так же, как вы вызываете любой другой метод компонента.
Обратите внимание, что все темы здесь находятся в рамках начальной зависимости webflux - я не думаю, что вам понадобятся другие.