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());

在这里,根据需求,我们可以添加各种部分。映射中的值可以是ObjectHttpEntity

当我们调用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上找到。