如何将Flux<DataBuffer>转换为Spring控制器中的StreamingResponseBody

huangapple go评论106阅读模式
英文:

How to convert a Flux<DataBuffer> into a StreamingResponseBody in a Spring Controller

问题

我在我的Spring Controller中有一个DataBuffer的Flux,并希望将其附加到StreamingResponseBody作为流。我已经阅读了许多类似方法的答案,但没有完全符合这个情况。我不想将整个文件加载到内存中,我想要流式传输。

  1. @GetMapping(value="/attachment")
  2. public ResponseEntity<StreamingResponseBody> get(@PathVariable long attachmentId) {
  3. Flux<DataBuffer> dataBuffer = this.myService.getFile(attachmentId);
  4. StreamingResponseBody stream = out -> {
  5. // 在这里要做什么?
  6. }
  7. return ResponseEntity.ok()
  8. .contentType(MediaType.APPLICATION_OCTET_STREAM)
  9. .body(stream);
  10. }

EDIT: myService.getFile()

  1. public Flux<DataBuffer> getFile(long attachmentId) {
  2. return this.webClient.get()
  3. .uri("https://{host}/attachments/{attachmentId}", host, attachmentId)
  4. .attributes(clientRegistrationId("attachmentClient"))
  5. .accept(MediaType.ALL)
  6. .exchangeToFlux(clientResponse -> clientResponse.bodyToFlux(DataBuffer.class));
  7. }

希望这有所帮助。

英文:

I have a Flux of DataBuffer in my Spring Controller and I want to attach it to the StreamingResponseBody as a stream. I have read many answers for similar approaches, but nothing quite matches this. I do not want to load the entire file in memory. I want it streamed.

  1. @GetMapping(value=&quot;/attachment&quot;)
  2. public ResponseEntity&lt;StreamingResponseBody&gt; get(@PathVariable long attachmentId) {
  3. Flux&lt;DataBuffer&gt; dataBuffer = this.myService.getFile(attachmentId);
  4. StreamingResponseBody stream = out -&gt; {
  5. // what do do here?
  6. }
  7. return ResponseEntity.ok()
  8. .contentType(MediaType.APPLICATION_OCTET_STREAM)
  9. .body(stream);
  10. }
  11. }

EDIT: myService.getFile()

  1. public Flux&lt;DataBuffer&gt; gteFile(long attachmentId) {
  2. return this.webClient.get()
  3. .uri(&quot;https://{host}/attachments/{attachmentId}&quot;, host, attachmentId)
  4. .attributes(clientRegistrationId(&quot;attachmentClient&quot;))
  5. .accept(MediaType.ALL)
  6. .exchangeToFlux(clientResponse -&gt; clientResponse.bodyToFlux(DataBuffer.class));
  7. }

答案1

得分: 1

如果您使用WebFlux,就不需要返回StreamingResponseBody,可以直接返回Flux&lt;DataBuffer&gt;,这样它就会进行流式传输并且是非阻塞的。

如果您想要添加一些标头/自定义您的响应,那么可以返回Mono&lt;ResponseEntity&lt;Flux&lt;DataBuffer&gt;&gt;&gt;

  1. @GetMapping("/attachment/{attachmentId}")
  2. public Mono<ResponseEntity<Flux<DataBuffer>>> get(@PathVariable long attachmentId) {
  3. Flux<DataBuffer> dataBuffers = this.myService.getFile(attachmentId);
  4. ContentDisposition contentDisposition = ContentDisposition.inline()
  5. .filename("example.txt")
  6. .build();
  7. HttpHeaders headers = new HttpHeaders();
  8. headers.setContentDisposition(contentDisposition);
  9. return Mono.just(ResponseEntity.ok()
  10. .headers(headers)
  11. .contentType(MediaType.APPLICATION_OCTET_STREAM)
  12. .body(dataBuffers));
  13. }

如果您想要使用StreamingResponseBody(这意味着您正在使用阻塞的Spring MVC在Web层),那么您可以执行以下操作:

  1. StreamingResponseBody stream = outputStream ->
  2. Mono.create(sink -> DataBufferUtils.write(dataBuffers, outputStream)
  3. .subscribe(DataBufferUtils::release, sink::error, sink::success)
  4. ).block();

然后从您的控制器返回它。

英文:

If you're using WebFlux there's no need to return StreamingResponseBody, you can just return Flux&lt;DataBuffer&gt; directly, so it will be streaming and also non-blocking.

If you want to add some headers/customize your response, the you can return Mono&lt;ResponseEntity&lt;Flux&lt;DataBuffer&gt;&gt;&gt; :

<!-- language: java -->
@GetMapping("/attachment/{attachmentId}")
public Mono<ResponseEntity<Flux<DataBuffer>>> get(@PathVariable long attachmentId) {

  1. Flux&lt;DataBuffer&gt; dataBuffers = this.myService.getFile(attachmentId);
  2. ContentDisposition contentDisposition = ContentDisposition.inline()
  3. .filename(&quot;example.txt&quot;)
  4. .build();
  5. HttpHeaders headers = new HttpHeaders();
  6. headers.setContentDisposition(contentDisposition);
  7. return Mono.just(ResponseEntity.ok()
  8. .headers(headers)
  9. .contentType(MediaType.APPLICATION_OCTET_STREAM)
  10. .body(dataBuffers));
  11. }

If you want to use StreamingResponseBody (which means you're using blocking Spring MVC on web-layer), then you can do the following:

<!-- language: java -->

  1. StreamingResponseBody stream = outputStream -&gt;
  2. Mono.create(sink -&gt; DataBufferUtils.write(dataBuffers, outputStream)
  3. .subscribe(DataBufferUtils::release, sink::error, sink::success)
  4. ).block();

and then return it from your controller

huangapple
  • 本文由 发表于 2023年7月14日 03:48:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/76682781.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定