1. 概述
我们的应用程序经常需要通过HTTP请求处理文件上传。自Spring 5以来,我们现在可以使用反应式编程来处理这些请求。对反应式编程的支持让我们能够以非阻塞的方式工作,使用少量线程并利用回压。
在这篇文章中,我们将使用WebClient——一个非阻塞的反应式HTTP客户端——来展示如何上传文件。WebClient是名为Project Reactor的反应式编程库的一部分。我们将介绍两种使用BodyInserter进行文件上传的不同方法。
2. 使用WebClient上传文件
为了使用WebClient,我们需要在项目中添加spring-boot-starter-webflux
依赖:
<dependency>
<groupId>org.springframework.boot</groupId>.
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
2.1. 从资源上传文件
首先,我们声明URL:
URI url = UriComponentsBuilder.fromHttpUrl(EXTERNAL_UPLOAD_URL).build().toUri();
假设在这个例子中,我们要上传一个PDF文件。我们将使用MediaType.APPLICATION_PDF
作为内容类型。我们的上传端点返回一个HttpStatusCode
。由于我们只期望一个结果,我们将它封装在一个Mono
中:
Mono<HttpStatusCode> 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()
方法使用传递资源的InputStream
向输出消息写入数据。
2.2. 从Multipart资源上传文件
如果外部上传端点接受Multipart表单数据,我们可以使用MultiPartBodyBuilder
来处理部分数据:
MultipartBodyBuilder builder = new MultipartBodyBuilder();
builder.part("file", multipartFile.getResource());
在这里,根据需求,我们可以添加各种部分。映射中的值可以是Object
或HttpEntity
。
当我们调用WebClient时,我们使用BodyInsterter.fromMultipartData
构建对象:
.body(BodyInserters.fromMultipartData(builder.build()))
我们将内容类型更新为MediaType.MULTIPART_FORM_DATA
,以反映更改。
让我们看看完整的调用:
Mono<HttpStatusCode> 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. 总结
在这篇教程中,我们展示了使用WebClient和BodyInserter的两种方式上传文件。如往常一样,代码可在GitHub上找到。