Manage upload/download of files using REST and Spring Boot

In this tutorial we will learn how to manage the upload and download of files using Spring Boot REST Services. We will use for this purpose Swagger UI to interact with a REST Controller.

Setting up your Spring Boot project

In order to get started with this tutorial we suggest reading this Intro to REST Services and Swagger UI so that you can bootstrap your project quickly:

Firstly, add a Spring Boot application class to bootstrap your project:

@SpringBootApplication

public class DemoApplication {

  public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
  }

   
}

Next, we will code our main Controller Class which will handle the upload and download of files:

@RestController public class RestFilesController {
   private final Logger logger = LoggerFactory.getLogger(RestFilesController.class);

   // Save the uploaded file to this folder
   private static String UPLOADED_FOLDER = "/tmp/uploads/";

   // Single File upload   
   @PostMapping(value = "/rest/upload", consumes = {
      "multipart/form-data"
   })
   @Operation(summary = "Upload a single File")
   public ResponseEntity < ? > uploadFile(@RequestParam("file") MultipartFile uploadfile) {
      logger.debug("Single file upload!");
      if (uploadfile.isEmpty()) {
         return new ResponseEntity("You must select a file!", HttpStatus.OK);
      }
      try {
         saveUploadedFiles(Arrays.asList(uploadfile));
      } catch (IOException e) {
         return new ResponseEntity < > (HttpStatus.BAD_REQUEST);
      }
      return new ResponseEntity("Successfully uploaded - " + uploadfile.getOriginalFilename(), new HttpHeaders(), HttpStatus.OK);
   }

   // Multiple File upload   
   @PostMapping(value = "/rest/multipleupload", consumes = {
      "multipart/form-data"
   })
   @Operation(summary = "Upload multiple Files")

   public ResponseEntity uploadFiles(@RequestPart String metaData, @RequestPart(required = true) MultipartFile[] uploadfiles) {

      String uploadedFileName = Arrays.stream(uploadfiles).map(x -> x.getOriginalFilename()).filter(x -> !StringUtils.isEmpty(x)).collect(Collectors.joining(" , "));
      if (StringUtils.isEmpty(uploadedFileName)) {
         return new ResponseEntity("please select a file!", HttpStatus.OK);
      }
      try {
         saveUploadedFiles(Arrays.asList(uploadfiles));
      } catch (IOException e) {
         return new ResponseEntity < > (HttpStatus.BAD_REQUEST);
      }
      return new ResponseEntity("Successfully uploaded - " + uploadedFileName, HttpStatus.OK);
   }

   // Single File download
   @RequestMapping(path = "/rest/download", method = RequestMethod.GET)
   @Operation(summary = "Download a File")

   public ResponseEntity < Resource > downloadFile(String fileName) throws IOException {
      File file = new File(UPLOADED_FOLDER + fileName);
      HttpHeaders headers = new HttpHeaders();
      headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName);
      headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
      headers.add("Pragma", "no-cache");
      headers.add("Expires", "0");
      Path path = Paths.get(UPLOADED_FOLDER + fileName);

      ByteArrayResource resource = new ByteArrayResource(Files.readAllBytes(path));

      return ResponseEntity.ok()
         .headers(headers)
         .contentLength(file.length())
         .contentType(MediaType.APPLICATION_OCTET_STREAM)
         .body(resource);

   }

   // save file
   private void saveUploadedFiles(List < MultipartFile > files) throws IOException {
      File folder = new File(UPLOADED_FOLDER);
      if (!folder.exists()) {
         folder.mkdir();
      }
      for (MultipartFile file: files) {
         if (file.isEmpty()) {
            continue;
            // next pls
         }
         byte[] bytes = file.getBytes();
         Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
         Files.write(path, bytes);
      }
   }

}

Our Controller class includes three main methods:

  • uploadFile: which handles the upload of a single File
  • uploadFiles: which handles the upload of a multiple Files
  • downloadFile: that you can use to download a File

All files are uploaded in the UPLOADED_FOLDER path.

Next, to build your project, make sure you have the starter-web and springdoc-openapi-ui dependencies in place:

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

<dependency>
  <groupId>org.springdoc</groupId>
  <artifactId>springdoc-openapi-ui</artifactId>
  <version>1.6.6</version>
</dependency>

We will use the latter dependency to test our Rest Controller with Swagger UI.

Testing the Rest Controller

Next, build and run the application

mvn install spring-boot:run

Finally, reach out Swagger’s UI at http://localhost:8080/swagger-ui/index.html where you can test the application:

spring boot rest upload download

Next, select the method you want to test and “try out”. For example, let’s test file Uploading:

rest file upload download spring boot

Pick up the file you want to upload and click on “Execute”. To verify that the file is available, check the upload path to see if the file is there:

$ ls /tmp/uploads/

swagger1.png

Finally, test File Download using the appropriate REST HTTP GET:

swagger rest file download

Click on Execute and verify that Download starts on your browser. Great! you just managed to Upload / Download files with Spring Boot!

Source code for this tutorial: https://github.com/fmarchioni/masterspringboot/tree/master/rest/upload-download

Jakarta or Java EE User ? Then check this tutorial to learn how to upload and download files with JAX-RS.