Как преобразовать MultiPartFile в Mono<FilePart>

У меня есть реактивный API, который принимает Mono в качестве аргумента, как показано ниже.

Mono<FileType> processAndReturnType(Mono<FilePart> partFlux)

Мне нужно вызвать это из другого API, который принимает файл как getType(MultipartFile partFile)

Вызов API не является реактивным, и как я могу преобразовать MultipartFile в FilePart.

Один из способов приведен ниже, который работает нормально, но вызывает проблемы безопасности/проблемы сонара, поскольку файл доступен во временном каталоге –

Мне интересно, что может быть лучшим способом справиться с этим. Если я смогу напрямую транслировать. Любое предложение поможет

package com.maersk.clm.naas.tenderfile.convertor;

import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.lang.NonNull;
import reactor.core.scheduler.Schedulers;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;

/**
 * Implementation of {@link FilePart} that wraps a {@link MultipartFile}.
 */
public class MultipartFilePart implements FilePart {

    private final MultipartFile file;

    public MultipartFilePart(MultipartFile file) {
        this.file = file;
    }

    @Override
    @NonNull
    public Flux<DataBuffer> content() {
        try {
            Path tempFile = Files.createTempFile("upload", "temp");
            file.transferTo(tempFile);
            return DataBufferUtils.read(tempFile, new DefaultDataBufferFactory(), (int) file.getSize());
        } catch (IOException e) {
            return Flux.error(e);
        }
    }

    @Override
    @NonNull
    public String filename() {
        return Objects.requireNonNull(file.getOriginalFilename());
    }

    @Override
    @NonNull
    public String name() {
        return file.getName();
    }

    @Override
    @NonNull
    public Mono<Void> transferTo(@NonNull Path dest) {
        return DataBufferUtils.write(content(), dest)
                .then()
                .publishOn(Schedulers.boundedElastic())
                .doFinally(signalType -> {
                    try {
                        Files.deleteIfExists(dest);
                    } catch (IOException e) {
                        throw new UncheckedIOException(e);
                    }
                });
    }

    @Override
    @NonNull
    public HttpHeaders headers() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.parseMediaType(Objects.requireNonNull(file.getContentType())));
        return headers;
    }
}

Я пробовал разные способы конвертации, но не нашел лучшего решения.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
66
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Можно обойтись и без временного файла. MultipartFile имеет два других способа получить доступ к своему содержимому: getBytes() возвращает byte[] и getInputStream() возвращает InputStream. Вы можете использовать оба, чтобы получить Flux.

DataBufferUtils есть метод readInputStream, который прост в использовании:

return DataBufferUtils.readInputStream(
        file::getInputStream,
        new DefaultDataBufferFactory(),
        (int) file.getSize());

С помощью getBytes() вы можете использовать фабрику напрямую:

return Flux.just(new DefaultDataBufferFactory().wrap(file.getBytes());

Из этих трёх вариантов я бы выбрал readInputStream. Временный файл включает дисковый ввод-вывод, и файл необходимо удалить, а вы забыли это сделать. Опция byte[] должна синхронно прочитать все содержимое в памяти, прежде чем его можно будет обернуть. С другой стороны, опция readInputStream может работать даже с меньшим размером буфера.


Как только вы это заработаете, я посмотрю, можно ли создать многоразовый DataBufferFactory. DefaultDataBufferFactory.sharedInstanceможет быть вариант.

Другие вопросы по теме