Upload form data and download files in Spring Boot

In the previous tutorial, you learnt to create APIs in Spring Boot to get, insert, update, and delete MYSQL data and tested the APIs using ARC chrome extension. 

In this tutorial, we are going to extend the insert and update functionalities to allow form data with file upload. Also, you learn to add download functionality to the app.

Open the springtutorial/ProductController.java to update the post and put handler methods to receive form data with file. In Java Spring Boot, you are able to access an uploaded file using MultipartFile. Add saveFile() method to store uploaded files in product_images folder. A MultipartFile object provides getInputStream() method to read byte data from the multipart file object. The byte data is written to the local storage using convenient copy method of Files class. 

.........................
@PostMapping("/add") // POST Requests
  public @ResponseBody Product addPro (
    @RequestParam("name") String name,
    @RequestParam("price") String price,  
    @RequestParam(value = "file", required = false) MultipartFile multipartFile) {

    String fileName = "";
    if(multipartFile!=null) {
      fileName=StringUtils.cleanPath(multipartFile.getOriginalFilename());
      String fileCode = String.valueOf(System.currentTimeMillis());
      try {

        fileName=fileCode+"_"+fileName;
        String result=saveFile(fileName, multipartFile);
        System.out.print("result="+result);

      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
 
    Product p=new Product();
    p.setName(name);
    p.setPrice(Float.parseFloat(price));
    p.setThumbnail(fileName);
    productRepository.save(p);

    return p;
  }
 
  @PutMapping("/update/{id}") // PUT Requests
  public @ResponseBody Product updatePro (
    @PathVariable int id,
    @RequestParam("name") String name,
    @RequestParam("price") String price,  
@RequestParam(value="thumbnail", required = false) String thumbnail,
    @RequestParam(value = "file", required = false) MultipartFile multipartFile
  ) {
   
    String fileName = thumbnail;
    if(multipartFile!=null) {
      fileName=StringUtils.cleanPath(multipartFile.getOriginalFilename());
      String fileCode = String.valueOf(System.currentTimeMillis());
      try {
        fileName=fileCode+"_"+fileName;
        String result=saveFile(fileName, multipartFile);
        System.out.print("result="+result);
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }

    Product p=new Product();
    p.setId(id);
    p.setName(name);
    p.setPrice(Float.parseFloat(price));
    p.setThumbnail(fileName);
    productRepository.save(p);
 
    return p;
  }
// save uploaded file in product_images folder
public  String saveFile(String fileName, MultipartFile multipartFile)
            throws IOException {

        Path uploadPath = Paths.get("product_images");
         
        if (!Files.exists(uploadPath)) {
            Files.createDirectories(uploadPath);
        }
 
       
         
        try (InputStream inputStream = multipartFile.getInputStream()) {

            Path filePath = uploadPath.resolve(fileName);
            Files.copy(inputStream, filePath, StandardCopyOption.REPLACE_EXISTING);

        } catch (IOException ioe) {      
           
            return "failed to save the file";
        }
         
        return fileName;
    }
...............

Make sure MYSQL Server is running. Run the project. Then open ARC to test the APIs.
Add a new product with image file:



To update the product with id 1, select method PUT and the Request Uri is http://localhost:8080/products/update/1. 

Download files

To allow the uploaded image files to be downloaded, in the springtutorial/controllers, create FileDownloadController.java. We allow files to be downloaded from the /image/{filename} path. The ResponseEntity has ok method to create a BodyBuilder object to embed data stream of an image file using body() method. The contentType and header specify content type and header name and value to sent along with the data stream. By returning the BodyBuilder object, a client app is able to receive the image file.

Add the following code to the FileDownloadController.java:

package com.dev.springtutorial.controllers;

import java.io.File;
import java.io.IOException;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import org.springframework.core.io.UrlResource;
 
@RestController
public class FileDownloadController {
    private Path foundFile;

    @GetMapping("/image/{filename}")
    public ResponseEntity<?> downloadFile(@PathVariable("filename") String filename) {
             
        Resource resource = null;
        try {
            resource = getImageAsResource(filename);
        } catch (IOException e) {
            return ResponseEntity.internalServerError().build();
        }
         
        if (resource == null) {
            return new ResponseEntity<>("File not found", HttpStatus.NOT_FOUND);
        }
         
        String contentType = "application/octet-stream";
        String headerValue = "attachment; filename=\"" + resource.getFilename() + "\"";

        return ResponseEntity.ok()
                .contentType(MediaType.parseMediaType(contentType))
                .header(HttpHeaders.CONTENT_DISPOSITION, headerValue)
                .body(resource);      
    }
   
   
    public Resource getImageAsResource(String filename) throws IOException {
       
        File file=new File("product_images"+File.separator+filename);
        return  new UrlResource(file.toURI());
     
    }
}


Save the project. Then, from your browser, access http://localhost:8080/image/filename. Replace filename with the image file name to be downloaded.
  

Comments