How to upload multiple files using Webflux?

11,187

Solution 1

I already found some solutions. Let's suppose that we send an http POST request with an parameter files which contains our files.

Note responses are arbitrary

  1. RestController with RequestPart

    @PostMapping("/upload")
    public Mono<String> process(@RequestPart("files") Flux<FilePart> filePartFlux) {
        return filePartFlux.flatMap(it -> it.transferTo(Paths.get("/tmp/" + it.filename())))
            .then(Mono.just("OK"));
    }
    
  2. RestController with ModelAttribute

    @PostMapping("/upload-model")
    public Mono<String> processModel(@ModelAttribute Model model) {
        model.getFiles().forEach(it -> it.transferTo(Paths.get("/tmp/" + it.filename())));
        return Mono.just("OK");
    }
    
    class Model {
        private List<FilePart> files;
        //getters and setters
    }
    
  3. Functional way with HandlerFunction

    public Mono<ServerResponse> upload(ServerRequest request) {
        Mono<String> then = request.multipartData().map(it -> it.get("files"))
            .flatMapMany(Flux::fromIterable)
            .cast(FilePart.class)
            .flatMap(it -> it.transferTo(Paths.get("/tmp/" + it.filename())))
            .then(Mono.just("OK"));
    
        return ServerResponse.ok().body(then, String.class);
    }
    

Solution 2

You can iterate hashmap with Flux and return Flux

Flux.fromIterable(hashMap.entrySet())
            .map(o -> hashmap.get(o));

and it will be send as an array with filepart

Solution 3

the key is use toParts instead of toMultipartData, which is more simpler. Here is the example that works with RouterFunctions.

private Mono<ServerResponse> working2(final ServerRequest request) {
    final Flux<Void> voidFlux = request.body(BodyExtractors.toParts())
        .cast(FilePart.class)
        .flatMap(filePart -> {
            final String extension = FilenameUtils.getExtension(filePart.filename());
            final String baseName = FilenameUtils.getBaseName(filePart.filename());
            final String format = LocalDateTime.now().format(DateTimeFormatter.BASIC_ISO_DATE);

            final Path path = Path.of("/tmp", String.format("%s-%s.%s", baseName, format, extension));
            return filePart.transferTo(path);
        });

    return ServerResponse
        .ok()
        .contentType(APPLICATION_JSON_UTF8)
        .body(voidFlux, Void.class);
}
Share:
11,187

Related videos on Youtube

Vladlen Gladis
Author by

Vladlen Gladis

Software developer at Esempla Systems. Interested in Java Kotlin Angular Spring Boot RESTful Web Services Google(FCM, Static Map, Geocoding etc.) JSP, Thymeleaf Amazon Web Services(S3, SQS, EC2, RDS, Elastic Beanstalk) DevOps(Terraform, Jenkins) Developing plugins for VMware vRO &amp; integration with vRA, Symantic Netbackup, Symantic ObsCenter

Updated on September 16, 2022

Comments

  • Vladlen Gladis
    Vladlen Gladis over 1 year

    How to upload multiple files using Webflux?

    I send request with content type: multipart/form-data and body contains one part which value is a set of files.

    To process single file I do it as follow:

    Mono<MultiValueMap<String, Part> body = request.body(toMultipartData());
    body.flatMap(map -> FilePart part = (FilePart) map.toSingleValueMap().get("file"));
    

    But how to done it for multiple files?

    PS. Is there another way to upload a set of files in webflux ?

  • Saveriu CIANELLI
    Saveriu CIANELLI over 4 years
    Hi! This code seems to work for an array of files sent by the client. How can we do with a client that sent a flux of files? Thanks!
  • deHaar
    deHaar over 4 years
    Post an explanation in English, please…