order
This paper mainly studies the example of spring webflux returning application/stream+json
maven
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency>
controller
/** * curl -i localhost:8080/stream * @return */ @GetMapping(value = "/stream",produces = MediaType.APPLICATION_STREAM_JSON_VALUE) public Flux<Price> priceStream(){ return Flux.interval(Duration.ofMillis(500)) .map(l -> new Price(System.currentTimeMillis(),ThreadLocalRandom.current().nextInt(100, 125))) .log(); }
Notice here that produces = MediaType.APPLICATION_STREAM_JSON_VALUE If it is not application/stream+json, the caller cannot scroll to get the result, and will be blocked waiting for the end of the data stream or timeout.
output
- Background output
2018-02-08 21:36:49.701 INFO 1270 --- [ctor-http-nio-2] reactor.Flux.Map.1 : onSubscribe(FluxMap.MapSubscriber) 2018-02-08 21:36:49.702 INFO 1270 --- [ctor-http-nio-2] reactor.Flux.Map.1 : request(1) 2018-02-08 21:36:50.208 INFO 1270 --- [ parallel-2] reactor.Flux.Map.1 : onNext(Price(timestamp=1518097010208, value=120.0)) 2018-02-08 21:36:50.229 INFO 1270 --- [ctor-http-nio-2] reactor.Flux.Map.1 : request(31) 2018-02-08 21:36:50.708 INFO 1270 --- [ parallel-2] reactor.Flux.Map.1 : onNext(Price(timestamp=1518097010708, value=124.0)) 2018-02-08 21:36:51.208 INFO 1270 --- [ parallel-2] reactor.Flux.Map.1 : onNext(Price(timestamp=1518097011208, value=119.0)) 2018-02-08 21:36:51.707 INFO 1270 --- [ parallel-2] reactor.Flux.Map.1 : onNext(Price(timestamp=1518097011707, value=120.0)) 2018-02-08 21:36:52.207 INFO 1270 --- [ parallel-2] reactor.Flux.Map.1 : onNext(Price(timestamp=1518097012207, value=109.0)) 2018-02-08 21:36:52.707 INFO 1270 --- [ parallel-2] reactor.Flux.Map.1 : onNext(Price(timestamp=1518097012707, value=101.0)) 2018-02-08 21:36:53.208 INFO 1270 --- [ parallel-2] reactor.Flux.Map.1 : onNext(Price(timestamp=1518097013208, value=114.0)) 2018-02-08 21:36:53.707 INFO 1270 --- [ parallel-2] reactor.Flux.Map.1 : onNext(Price(timestamp=1518097013707, value=113.0)) 2018-02-08 21:36:54.206 INFO 1270 --- [ parallel-2] reactor.Flux.Map.1 : onNext(Price(timestamp=1518097014206, value=105.0)) 2018-02-08 21:36:54.708 INFO 1270 --- [ parallel-2] reactor.Flux.Map.1 : onNext(Price(timestamp=1518097014708, value=103.0)) 2018-02-08 21:36:55.208 INFO 1270 --- [ parallel-2] reactor.Flux.Map.1 : onNext(Price(timestamp=1518097015207, value=123.0)) 2018-02-08 21:36:55.212 INFO 1270 --- [ctor-http-nio-2] reactor.Flux.Map.1 : cancel()
- Caller output
curl -i localhost:8080/stream HTTP/1.1 200 OK transfer-encoding: chunked Content-Type: application/stream+json;charset=UTF-8 {"timestamp":1518097010208,"value":120.0} {"timestamp":1518097010708,"value":124.0} {"timestamp":1518097011208,"value":119.0} {"timestamp":1518097011707,"value":120.0} {"timestamp":1518097012207,"value":109.0} {"timestamp":1518097012707,"value":101.0} {"timestamp":1518097013208,"value":114.0} {"timestamp":1518097013707,"value":113.0} {"timestamp":1518097014206,"value":105.0} ^C
You can see that the transfer-encoding returned is chunked due to the use of application/stream+json, so the caller can achieve scrolling output.
paging
After using webflux, you may be curious about previous paging calls. reactive-streams use data as data streams, so spring data reactive does not support returning Page, but calling parameters can pass Pageable parameters.
public interface StocDao extends ReactiveCrudRepository<Stock, String> { Flux<Stock> findByName(String name,Pageable pageable); }
Note that Flux < Stock > is returned here, not Page < Stock > That's equivalent to losing total count.
Summary
For the flow data of Flux returned by webflux, we need to cooperate with the return of MediaType.APPLICATION_STREAM_JSON_VALUE, and the caller also needs to be able to support this media type (WebClient support), so as to enable the effect of reactive streams.