1、概览 {#1概览}
文件上传是现在应用中很常见的需求,从 Spring 5 开始可以通过响应式上传文件。有了响应式编程的加持,能够使用较少的线程和背压(Backpressure)机制,以非阻塞的方式进行上传。
本文将带你了解使用 WebClient
(一种非阻塞、响应式的 HTTP 客户端)通过 BodyInserters
上传文件的两种不同方法。WebClient
是名为 Project Reactor
的响应式编程库的一部分。
2、使用 WebClient 上传文件 {#2使用-webclient-上传文件}
首先,在项目中添加 spring-boot-starter-webflux
依赖:
<dependency>
<groupId>org.springframework.boot</groupId>.
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
2.1、上传单个文件 {#21上传单个文件}
首先,声明上传地址的 URL:
URI url = UriComponentsBuilder.fromHttpUrl(EXTERNAL_UPLOAD_URL).build().toUri();
比方说,在本例中要上传 PDF。因此使用 MediaType.APPLICATION_PDF
作为 ContentType
。上传端点会返回一个 HttpStatus
。由于只希望得到一个结果,所以将其封装在一个 Mono
中:
Mono<HttpStatus> httpStatusMono = webClient.post()
.uri(url)
.contentType(MediaType.APPLICATION_PDF)
.body(BodyInserters.fromResource(resource))
.exchangeToMono(response -> {
if (response.statusCode().equals(HttpStatus.OK)) {
return response.bodyToMono(HttpStatus.class).thenReturn(response.statusCode());
} else {
throw new ServiceException("Error uploading file");
}
});
调用这个方法的方法也可以返回一个 Mono
,可以一直进行下去,直到真正需要访问结果为止。就绪后,可以在 Mono
对象上调用 block()
方法。
fromResource()
会读取 Resource
的 InputStream
,并将其写入到输出。
2.2、上传 Multipart 文件 {#22上传-multipart-文件}
如果上传端点采用 Multipart Form Data,则可以使用 MultiPartBodyBuilder
来处理这些 Part:
MultipartBodyBuilder builder = new MultipartBodyBuilder();
builder.part("file", multipartFile.getResource());
如上,可以根据自己的需求添加不同的 Part。Map
中的值可以是 Object
或 HttpEntity
。
使用 BodyInsterter.fromMultipartData
来构建请求体对象:
.body(BodyInserters.fromMultipartData(builder.build()))
还要将 Content Type 更新为 MediaType.MULTIPART_FORM_DATA
。
完整的请求示例如下:
Mono<HttpStatus> httpStatusMono = webClient.post()
.uri(url)
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(BodyInserters.fromMultipartData(builder.build()))
.exchangeToMono(response -> {
if (response.statusCode().equals(HttpStatus.OK)) {
return response.bodyToMono(HttpStatus.class).thenReturn(response.statusCode());
} else {
throw new ServiceException("Error uploading file");
}
});
3、总结 {#3总结}
本文介绍了使用 WebClient
通过 BodyInserters
上传文件的两种方法。
总的来说就是,使用 BodyInserters.fromResource
通过普通请求一次上传单个文件资源,使用 BodyInserters.fromMultipartData
通过 multipart/form-data
请求一次上传多个文件资源。需要注意使用不同的 Content-Type
。
Ref:https://www.baeldung.com/spring-webclient-upload-file