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
в качестве 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
, и мы можем продолжать до тех пор, пока нам действительно не понадобится доступ к результату. Когда мы будем готовы, мы можем вызвать метод block()
для объекта Mono .
Метод fromResource()
использует InputStream
переданного ресурса для записи в выходное сообщение.
2.2. Загрузка файла из составного ресурса
Если наша внешняя конечная точка загрузки принимает данные формы 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<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
с помощью BodyInserter
s. Как всегда, код доступен на GitHub .