Как сгенерировать случайную строку и вытолкнуть ее с помощью 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 - я не думаю, что вам понадобятся другие.

Другие вопросы по тегам