Partner – Microsoft – NPI (cat= Spring)
announcement - icon

Azure Spring Apps is a fully managed service from Microsoft (built in collaboration with VMware), focused on building and deploying Spring Boot applications on Azure Cloud without worrying about Kubernetes.

And, the Enterprise plan comes with some interesting features, such as commercial Spring runtime support, a 99.95% SLA and some deep discounts (up to 47%) when you are ready for production.

>> Learn more and deploy your first Spring Boot app to Azure.

You can also ask questions and leave feedback on the Azure Spring Apps GitHub page.

1. Overview

Our applications often have to handle file uploads via an HTTP request. Since Spring 5, we can now make these requests reactive.
The added support for Reactive Programming allows us to work in a non-blocking way, using a small number of threads and Backpressure.

In this article, we’ll use WebClient – a non-blocking, reactive HTTP client – to illustrate how to upload a file. WebClient is part of the reactive programming library called Project Reactor. We’ll cover two different approaches to uploading a file using a BodyInserter.

2. Uploading a File with WebClient

In order to use WebClient, we’ll need to add the spring-boot-starter-webflux dependency to our project:

<dependency>
    <groupId>org.springframework.boot</groupId>. 
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

2.1. Uploading a File from a Resource

To start with, we want to declare our URL:

URI url = UriComponentsBuilder.fromHttpUrl(EXTERNAL_UPLOAD_URL).build().toUri();

Let’s say in this example we want to upload a PDF. We’ll use MediaType.APPLICATION_PDF as our ContentType.
Our upload endpoint returns an HttpStatusCode. Since we’re expecting only one result, we’ll wrap it in a 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");
        }
     });

The method consuming this method can also return a Mono, and we can continue until we actually need to access the result. Once we’re ready, we can call the block() method on the Mono object.

The fromResource() method uses the InputStream of the passed resource to write to the output message.

2.2. Uploading a File from Multipart Resource

If our external upload endpoint takes a Multipart form data, we can use the MultiPartBodyBuilder to take care of the parts:

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

Here, we could be adding various parts according to our requirements. The value in the map can be an Object or an HttpEntity.

When we call WebClient, we use BodyInsterter.fromMultipartData and build the object:

.body(BodyInserters.fromMultipartData(builder.build()))

We update the content type to MediaType.MULTIPART_FORM_DATA to reflect the changes.

Let’s look at the entire call:

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. Conclusion

In this tutorial, we’ve shown two ways to upload a file with WebClient using BodyInserters. As always, the code is available over on GitHub.

Course – LS (cat=Spring)

Get started with Spring and Spring Boot, through the Learn Spring course:

>> THE COURSE
res – Junit (guide) (cat=Reactive)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.