Spring Boot with File Upload and Download(2024) Example | CodeUsingJava






















Spring Boot with File Upload and Download(2024) Example

While developing any application, file upload and download plays an important role in it. The developer needs to write the functionality such that the operation of file upload and download becomes easy for the end users.
Spring boot has an amazing interface known as MultipartFile by which one can upload and download the files. One can also get other important properties like file name, size etc by using this interface.
The flow diagram for the file upload and download can be drawn in the following manner-
Spring boot flow digram

Project Structure

The project Structure for our example is as follows-
Spring boot project structure
We need to start by creating a Maven pom.xml(Project Object Model) file. The pom.xml file contains the project configuration details.
	<?xml version="1.0" encoding="UTF-8"?>
	<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
		<modelVersion>4.0.0</modelVersion>
		<parent>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-parent</artifactId>
			<version>2.3.2.RELEASE</version>
			<relativePath/> <!-- lookup parent from repository -->
		</parent>
		<groupId>com.codeusingjava</groupId>
		<artifactId>filedemo</artifactId>
		<version>0.0.1-SNAPSHOT</version>
		<name>fileUploadAndDownload</name>
		<description>Spring Boot file Upload And Download</description>
	
		<properties>
			<java.version>1.8</java.version>
		</properties>
	
		<dependencies>
			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-starter-data-jpa</artifactId>
			</dependency>
			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-starter-web</artifactId>
			</dependency>
	
			<dependency>
				<groupId>mysql</groupId>
				<artifactId>mysql-connector-java</artifactId>
				<scope>runtime</scope>
			</dependency>
			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-starter-test</artifactId>
				<scope>test</scope>
				<exclusions>
					<exclusion>
						<groupId>org.junit.vintage</groupId>
						<artifactId>junit-vintage-engine</artifactId>
					</exclusion>
				</exclusions>
			</dependency>
		</dependencies>
	
		<build>
			<plugins>
				<plugin>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-maven-plugin</artifactId>
				</plugin>
			</plugins>
		</build>
	
	</project>
	
The application.properties file is as follows-
This file contains the configurations related to the database and file that is to be uploaded
		spring.datasource.url= jdbc:mysql://localhost:3306/d1?useSSL=false
		spring.datasource.username= root
		spring.datasource.password= ****
		
		spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
		spring.jpa.hibernate.ddl-auto= update
		
		logging.level.org.hibernate.SQL= DEBUG
		
		spring.servlet.multipart.enabled= true
		
		spring.servlet.multipart.file-size-threshold= 2KB
		
		spring.servlet.multipart.max-file-size= 100MB
		
		spring.servlet.multipart.max-request-size= 125MB
		
	
Creating the File model class as follows with all the JPA annotations mentioned in it-
@GenericGenerator is used for defining a custom generator. It can be a class or a shortcut.
	package com.codeusingjava.fileupload.model;

	import javax.persistence.*;
	
	import org.hibernate.annotations.GenericGenerator;
	
	@Entity
	@Table(name = "files")
	public class Files {
		@Id
		@GeneratedValue(generator = "uuid")
		@GenericGenerator(name = "uuid", strategy = "uuid2")
	   
		private String id;
	
		private String name;
	
		private String type;
	
		@Lob
		private byte[] filecontent;
	
		public String getId() {
			return id;
		}
	
		public void setId(String id) {
			this.id = id;
		}
	
		public String getName() {
			return name;
		}
	
		public void setName(String name) {
			this.name = name;
		}
	
		public String getType() {
			return type;
		}
	
		public void setType(String type) {
			this.type = type;
		}
	
		public byte[] getFilecontent() {
			return filecontent;
		}
	
		public void setFilecontent(byte[] filecontent) {
			this.filecontent = filecontent;
		}
	
		public Files(String name, String type, byte[] filecontent) {
			super();
			this.name = name;
			this.type = type;
			this.filecontent = filecontent;
			// TODO Auto-generated constructor stub
		}
	
		public Files(String id, String name, String type, byte[] filecontent) {
			super();
			this.id = id;
			this.name = name;
			this.type = type;
			this.filecontent = filecontent;
		}
	
		public Files() {
			super();
			// TODO Auto-generated constructor stub
		}
	   
	 }
	
Creating the repository class for the File:-
 
package com.codeusingjava.fileupload.repo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.codeusingjava.fileupload.model.Files;

@Repository
public interface FileRepo extends JpaRepository {
}

Now configuring the Exception class in our program-
The FileNotFoundException will come into picture mainly when the file requested by the user will not be available in the database.
package com.codeusingjava.fileupload.exception;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(HttpStatus.NOT_FOUND)
public class FileNotFoundException extends RuntimeException {

    public FileNotFoundException(String message) {
        super(message);
    }

    public FileNotFoundException(String message, Throwable cause) {
        super(message, cause);
    }
}

Another Exception class is the FileStorageException.
This class will come into picture when any exception regarding the input/output format or size of the file would be violated and file is not able to save into the database.
	package com.codeusingjava.fileupload.exception;
public class FileStorageException extends RuntimeException {

    public FileStorageException(String message) {
        super(message);
    }

    public FileStorageException(String message, Throwable cause) {
        super(message, cause);
    }
}

Creating the Service class for the File.
This class contains some of the essential functions like storing the file in the database or fetching the file from the database.
	package com.codeusingjava.fileupload.service;


	import com.codeusingjava.fileupload.exception.FileStorageException;
	import com.codeusingjava.fileupload.exception.FileNotFoundException;
	import com.codeusingjava.fileupload.model.Files;
	import com.codeusingjava.fileupload.repo.FileRepo;
	
	import org.springframework.beans.factory.annotation.Autowired;
	import org.springframework.stereotype.Service;
	import org.springframework.util.StringUtils;
	import org.springframework.web.multipart.MultipartFile;
	
	import java.io.IOException;
	
	@Service
	public class FileStorageService {
	
		@Autowired
		private FileRepo fileRepo;
	
		public Files storeFile(MultipartFile file) {
			String fileName = StringUtils.cleanPath(file.getOriginalFilename());
	
			try {
				if(fileName.contains("..")) {
					throw new FileStorageException("Sorry! Filename contains invalid path sequenth " + fileName);
				}
	
				Files dbFile = new Files(fileName, file.getContentType(), file.getBytes());
	
				return fileRepo.save(dbFile);
	
			} catch (IOException ex) {
				throw new FileStorageException("Could not store file " + fileName + ". Please try again!", ex);
			}
		}
	
		public Files getFile(String fileId) {
			return fileRepo.findById(fileId)
					.orElseThrow(() -> new FileNotFoundException("File you requested not found with id " + fileId));
		}
	}
	
The FileUploadResponse class contains the parameters that are generated in the response when the file is successfully saved in the database.
	package com.codeusingjava.fileupload.payload;

public class FileUploadResponse {
    private String fileName;
    private String fileDownloadUri;
    private String fileType;
    private Long size;

    public FileUploadResponse(String fileName, String fileDownloadUri, String fileType, Long size) {
        this.fileName = fileName;
        this.fileDownloadUri = fileDownloadUri;
        this.fileType = fileType;
        this.size = size;
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public String getFileDownloadUri() {
        return fileDownloadUri;
    }

    public void setFileDownloadUri(String fileDownloadUri) {
        this.fileDownloadUri = fileDownloadUri;
    }

    public String getFileType() {
        return fileType;
    }

    public void setFileType(String fileType) {
        this.fileType = fileType;
    }

    public Long getSize() {
        return size;
    }

    public void setSize(Long size) {
        this.size = size;
    }
}

The controller class can be configured as folllows-
This class contains the api's that are needed to be executed for the purpose of File Upload And Download.
  
	package com.codeusingjava.fileupload.controller;

import com.codeusingjava.fileupload.model.Files;
import com.codeusingjava.fileupload.payload.FileUploadResponse;
import com.codeusingjava.fileupload.service.FileStorageService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

@RestController
public class FileController {

    @Autowired
    private FileStorageService fileStorageService;

    @PostMapping("/fileupload")
    public FileUploadResponse uploadFile(@RequestParam("file") MultipartFile file) {
       Files files = fileStorageService.storeFile(file);

        String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
                .path("/filedownload/")
                .path(files.getId())
                .toUriString();

        return new FileUploadResponse(files.getName(), fileDownloadUri,
                file.getContentType(), file.getSize());
    }



    @GetMapping("/filedownload/{fileId}")
    public ResponseEntity downloadFile(@PathVariable String fileId) {
        Files dbFile = fileStorageService.getFile(fileId);

        return ResponseEntity.ok()
                .contentType(MediaType.parseMediaType(dbFile.getType()))
                .header(HttpHeaders.CONTENT_DISPOSITION, "/attachment; filename=\"" + dbFile.getName() + "\"")
                .body(new ByteArrayResource(dbFile.getFilecontent()));
    }
}

The main class for the fileUploadAndDownload can be written a follows-
	package com.codeusingjava.fileupload;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class FileUploadAndDownloadApplication {

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

}

Run the applications
We run the Application as Spring Boot Application.
Now, we open the Advance Request Client for testing the Application. The output for the fileupload url is as follows-
Spring boot fileupload

We see that a download link is generated in the response.
When we click on that link, again the image we uploaded is displayed.
Spring boot filedownload

Downloads-

Spring Boot + File Upload and Download Example