Up and Download Files with React and Spring Boot

Last Updated:  August 6, 2021 | Published: September 2, 2018

Today I want to share a simple approach for up and downloading files with JavaScript (ES6), React and a Spring Boot backend. This example can be used for any common content type like jpg, pdf, txt, HTML, png, etc., and is not limited to a specific content type.

The sample application uses React 17 with Node 15 and Spring Boot 2.5.0 with Java 11. We won't use any additional npm module for up and downloading files at the client-side and just rely on the Fetch API and plain JavaScript. The backend will store the files in an H2 in-memory database and will randomly return a file.

Implementing the React Frontend

The final application will look like the following:

File up- and download with React and Spring Boot

For a quick setup of our React application, we use Facebook's create-react-app CLI to generate a basic React project.

When running npx create-react-app frontend, we get a new project with the following package.json:

All the code will reside in the default App.js file. The component has the following state:

The file attribute is used for storing the uploaded file, the error attribute for displaying possible error messages and msg  is used for displaying information messages.

The upload related JSX looks like the following:

Any change for the input field will result in setting the uploaded file in the component's state:

For uploading a file, we check if the user tries to upload an actual file and if the file size exceeds 2MB. Our backend will only allow files with a maximum size of 2MB.

If one of the two validations fail, we set the error attribute and stop the upload process.

For a file with less than 2MB of size, we wrap the file in a FormData object, so that the request content type will be multipart/form-data. This is required as otherwise, our backend won't be able to deserialize the request correctly. For sending the request we use the Fetch API and display a message in case of a successful upload.

Downloading a File From the Spring Boot Backend

Next, downloading a random file requires a button and a function:

The downloadRandomImage() function looks like the following:

The response from the backend contains the byte array representation of the random file. To read this byte array in full, we make use of the blob() function of the response. This function returns a Promise that resolves with a Blob. To extract the correct filename, we access the response header Content-Disposition and store the filename in a local variable.

As the browsers currently don't support a standard way of downloading files from an AJAX request, we create an object URL for the incoming Blob and force the browser to download the image with a hidden <a> HTML element.

That's everything for the frontend. You can find the full App.js code on GitHub.

 Implementing the Spring Boot Backend

Next, the backend is a simple Spring Boot application that contains the dependencies for H2, JPA, and Web:

The JPA entity for storing the uploaded files looks like the following:

To upload and download files, we provide an API:/api/files which is accessible via HTTP GET for downloading a random file and HTTP POST for uploading a file.

Moreover, we need to configure CORS to access the Content-Disposition header in the frontend application:

To limit the maximum size of the uploaded file, we added the following configuration to the application.properties file.

Uploading a file is straightforward as we receive an object of the type MultipartFile as @RequestParam("file") and therefore have access to the filename, the size etc.:

Retrieving a Random File from the Database

For downloading a file, we add some logic to select a random file from the database. The endpoint will return a ResponseEntity of type byte[].

The most important part here is setting the correct HttpHeaders for the browser. As we store the content type of the file in the database, we can add the right Content-Type header of the response. In addition, we set the Content-Disposition header to inform the browser about the attached file and its name.

The code logic for retrieving a random file is just optional. We use this to show you that this code works for every common content type. Storing the files in a database might also not be the best solution for production.

Serving the React Application from the Spring Boot Backend

To access our frontend application, someone has to serve the static frontend resources (HTML, JavaScript, etc.). Usually, a web server (e.g. Nginx) hosts the static files which are created after you build the frontend application with npm run build. Nevertheless, for this example, we choose a self-contained system approach.

Our Spring Boot application can also static content next to providing data via REST APIs. To make this work, we have to instruct the application where to find the static content for the React application. Within the build section of the pom.xml we can configure this:

This instructs our Spring Boot application to also include the frontend/build folder for serving public content.

Furthermore to make development more convenient, we're using the frontend-maven-plugin to build the React application with Maven:

Whenever you now run mvn package, Maven will first build the frontend and then backend application in one run. This makes development much more convenient and as long your traffic is moderate, serving the frontend using the Spring Boot backend is feasible.

For more React deep-dive have a look at this excellent book and for Spring at the Essential Developer Resources.

You can find the code on GitHub. Detailed instructions to run this example can be found in the README.md file in the repository.

Keep up-/downloading files with Spring Boot and React,

Phil.

  • Hi Rieckpil,

    what if i want to view the content of the recently uploaded file in browser before download to local drive ?

    do you have example to preview the file and provide the options for print share download options .

  • The upload portion works great but the download portion fails for me. I’m using axios instead of fetch but I don’t see why that would matter. I first got response.header.get is not a function so I hardcoded filename to continue to debug and got I get blob() is not a function. I did had the content disposition annotations to spring. Using react 16.4.2

  • {"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}
    >