使用 WebClient 上传文件

1、概览

文件上传是现在应用中很常见的需求,从 Spring 5 开始可以通过响应式上传文件。有了响应式编程的加持,能够使用较少的线程和背压(Backpressure)机制,以非阻塞的方式进行上传。

本文将带你了解使用 WebClient(一种非阻塞、响应式的 HTTP 客户端)通过 BodyInserters 上传文件的两种不同方法。WebClient 是名为 Project Reactor 的响应式编程库的一部分。

2、使用 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 作为 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() 会读取 ResourceInputStream,并将其写入到输出。

2.2、上传 Multipart 文件

如果上传端点采用 Multipart Form Data,则可以使用 MultiPartBodyBuilder 来处理这些 Part:

MultipartBodyBuilder builder = new MultipartBodyBuilder();
builder.part("file", multipartFile.getResource());

如上,可以根据自己的需求添加不同的 Part。Map 中的值可以是 ObjectHttpEntity

使用 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、总结

本文介绍了使用 WebClient 通过 BodyInserters 上传文件的两种方法。

总的来说就是,使用 BodyInserters.fromResource 通过普通请求一次上传单个文件资源,使用 BodyInserters.fromMultipartData 通过 multipart/form-data 请求一次上传多个文件资源。需要注意使用不同的 Content-Type


Ref:https://www.baeldung.com/spring-webclient-upload-file