英文:
How to convert a Flux<DataBuffer> into a StreamingResponseBody in a Spring Controller
问题
我在我的Spring Controller中有一个DataBuffer的Flux,并希望将其附加到StreamingResponseBody作为流。我已经阅读了许多类似方法的答案,但没有完全符合这个情况。我不想将整个文件加载到内存中,我想要流式传输。
@GetMapping(value="/attachment")
public ResponseEntity<StreamingResponseBody> get(@PathVariable long attachmentId) {
Flux<DataBuffer> dataBuffer = this.myService.getFile(attachmentId);
StreamingResponseBody stream = out -> {
// 在这里要做什么?
}
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(stream);
}
EDIT: myService.getFile()
public Flux<DataBuffer> getFile(long attachmentId) {
return this.webClient.get()
.uri("https://{host}/attachments/{attachmentId}", host, attachmentId)
.attributes(clientRegistrationId("attachmentClient"))
.accept(MediaType.ALL)
.exchangeToFlux(clientResponse -> clientResponse.bodyToFlux(DataBuffer.class));
}
希望这有所帮助。
英文:
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.
@GetMapping(value="/attachment")
public ResponseEntity<StreamingResponseBody> get(@PathVariable long attachmentId) {
Flux<DataBuffer> dataBuffer = this.myService.getFile(attachmentId);
StreamingResponseBody stream = out -> {
// what do do here?
}
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(stream);
}
}
EDIT: myService.getFile()
public Flux<DataBuffer> gteFile(long attachmentId) {
return this.webClient.get()
.uri("https://{host}/attachments/{attachmentId}", host, attachmentId)
.attributes(clientRegistrationId("attachmentClient"))
.accept(MediaType.ALL)
.exchangeToFlux(clientResponse -> clientResponse.bodyToFlux(DataBuffer.class));
}
答案1
得分: 1
如果您使用WebFlux,就不需要返回StreamingResponseBody
,可以直接返回Flux<DataBuffer>
,这样它就会进行流式传输并且是非阻塞的。
如果您想要添加一些标头/自定义您的响应,那么可以返回Mono<ResponseEntity<Flux<DataBuffer>>>
:
@GetMapping("/attachment/{attachmentId}")
public Mono<ResponseEntity<Flux<DataBuffer>>> get(@PathVariable long attachmentId) {
Flux<DataBuffer> dataBuffers = this.myService.getFile(attachmentId);
ContentDisposition contentDisposition = ContentDisposition.inline()
.filename("example.txt")
.build();
HttpHeaders headers = new HttpHeaders();
headers.setContentDisposition(contentDisposition);
return Mono.just(ResponseEntity.ok()
.headers(headers)
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(dataBuffers));
}
如果您想要使用StreamingResponseBody
(这意味着您正在使用阻塞的Spring MVC在Web层),那么您可以执行以下操作:
StreamingResponseBody stream = outputStream ->
Mono.create(sink -> DataBufferUtils.write(dataBuffers, outputStream)
.subscribe(DataBufferUtils::release, sink::error, sink::success)
).block();
然后从您的控制器返回它。
英文:
If you're using WebFlux there's no need to return StreamingResponseBody
, you can just return Flux<DataBuffer>
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<ResponseEntity<Flux<DataBuffer>>>
:
<!-- language: java -->
@GetMapping("/attachment/{attachmentId}")
public Mono<ResponseEntity<Flux<DataBuffer>>> get(@PathVariable long attachmentId) {
Flux<DataBuffer> dataBuffers = this.myService.getFile(attachmentId);
ContentDisposition contentDisposition = ContentDisposition.inline()
.filename("example.txt")
.build();
HttpHeaders headers = new HttpHeaders();
headers.setContentDisposition(contentDisposition);
return Mono.just(ResponseEntity.ok()
.headers(headers)
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(dataBuffers));
}
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 -->
StreamingResponseBody stream = outputStream ->
Mono.create(sink -> DataBufferUtils.write(dataBuffers, outputStream)
.subscribe(DataBufferUtils::release, sink::error, sink::success)
).block();
and then return it from your controller
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论