DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • How To Build Web Service Using Spring Boot 2.x
  • Extending Swagger and Springdoc Open API
  • Java 11 HTTP Client API to Consume Restful Web Service Created Using Spring Boot
  • How Spring Boot Starters Integrate With Your Project

Trending

  • How Large Tech Companies Architect Resilient Systems for Millions of Users
  • AI’s Role in Everyday Development
  • Unmasking Entity-Based Data Masking: Best Practices 2025
  • AI-Based Threat Detection in Cloud Security
  1. DZone
  2. Coding
  3. Frameworks
  4. Java Spring Boot Rest API to Upload/Download File on Server

Java Spring Boot Rest API to Upload/Download File on Server

This article demonstrates how to use a Spring Boot application and MySQL to maintain a database of uploaded files and their metadata.

By 
Yogesh Parate user avatar
Yogesh Parate
·
May. 01, 20 · Tutorial
Likes (16)
Comment
Save
Tweet
Share
170.5K Views

Join the DZone community and get the full member experience.

Join For Free

I will be using Spring Initialzr to generate my Spring Boot application, include dependencies while creating a project. Also, I will be using the MySQL database to keep track of files uploaded and their metadata.

This API will be helpful for those who are registering new users to their business/application and want users to upload documents for verification.

Spring Boot dependencies

Spring Boot dependencies


Set up application.properties file with the database, upload the directory, and other details:

Properties files
 




x
24


 
1
spring.datasource.url = jdbc:mysql://127.0.0.1:8889/merchant
2
spring.datasource.username = root
3
spring.datasource.password = root
4
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
5
 
          
6
spring.jpa.hibernate.ddl-auto=update
7
spring.jpa.database-platform=org.hibernate.dialect.MySQL57Dialect
8
spring.jpa.generate-ddl=true
9
spring.jpa.show-sql=true
10
 
          
11
spring.application.name=media-service
12
server.port=8083
13
 
          
14
## MULTIPART (MultipartProperties)
15
# Enable multipart uploads
16
spring.servlet.multipart.enabled=true
17
# Threshold after which files are written to disk.
18
spring.servlet.multipart.file-size-threshold=2KB
19
# Max file size.
20
spring.servlet.multipart.max-file-size=200MB
21
# Max Request Size
22
spring.servlet.multipart.max-request-size=215MB
23
# All files uploaded through the REST API will be stored in this directory
24
file.upload-dir=/home/yogesh/media/upload


Create an entity class, DocumnentStorageProperties.java, to save information about a file uploaded and to avoid the duplication of files (you can skip this if you don't want to keep metadata).

Here I am keeping my database name as merchant and table name as merchant_documents. There's no need to create the table manually as I have set up spring.jpa.generate-ddl=true in properties. It will fire the DDL command when the application starts to create a table according to the Entity class defined in Java.

Java
 




x


 
1
@ConfigurationProperties(prefix = "file")
2
@Entity
3
@Table(name = "merchant_documents")
4
public class DocumnentStorageProperties {
5
    @Id
6
    @GeneratedValue(strategy = GenerationType.AUTO)
7
    @Column(name = "document_id")
8
    private Integer documentId;
9
    
10
    @Column(name = "user_id")
11
    private Integer UserId;
12
    
13
    @Column(name = "file_name")
14
    private String fileName;
15
    
16
    @Column(name = "document_type")
17
    private String documentType;
18
    
19
    @Column(name = "document_format")
20
    private String documentFormat;
21
    
22
    @Column(name = "upload_dir")
23
    private String uploadDir;
24
  // Getter and Setter


In the above entity class, the upload_dir variable will get initialized by the value which we have set in application.properties(file.upload-dir).

Create a repository interface for the above entity to get built-in CRUD operations method support. Add our own new method to check whether a particular file is present for that user or not.

Java
 




xxxxxxxxxx
1
14


 
1
import org.springframework.data.jpa.repository.JpaRepository;
2
import org.springframework.data.jpa.repository.Query;
3
import com.pocketutility.mediaservice.file.DocumnentStorageProperties;
4
 
          
5
public interface DocumentStoragePropertiesRepo extends JpaRepository<DocumnentStorageProperties, Integer> {
6
    
7
    @Query("Select a from DocumnentStorageProperties a where user_id = ?1 and document_type = ?2")
8
    DocumnentStorageProperties checkDocumentByUserId(Integer userId, String docType);
9
    
10
    @Query("Select fileName from DocumnentStorageProperties a where user_id = ?1 and document_type = ?2")
11
    String getUploadDocumnetPath(Integer userId, String docType);
12
}


Create a Service class to store and download files on the server, and to store information in the database. Here I have used a few more new classes which I will be explaining in a later section of this article, so if you get any compilation issues, ignore them for the moment.

Java
 




xxxxxxxxxx
1
96


 
1
import org.springframework.beans.factory.annotation.Autowired;
2
import org.springframework.core.io.Resource;
3
import org.springframework.core.io.UrlResource;
4
import org.springframework.stereotype.Service;
5
import org.springframework.util.StringUtils;
6
import org.springframework.web.multipart.MultipartFile;
7
import java.io.FileNotFoundException;
8
import java.io.IOException;
9
import java.net.MalformedURLException;
10
import java.nio.file.Files;
11
import java.nio.file.Path;
12
import java.nio.file.Paths;
13
import java.nio.file.StandardCopyOption;
14
 
          
15
@Service
16
public class DocumentStorageService {
17
 
          
18
    private final Path fileStorageLocation;
19
    
20
    @Autowired
21
    DocumentStoragePropertiesRepo docStorageRepo;
22
 
          
23
    @Autowired
24
    public DocumentStorageService(DocumnentStorageProperties fileStorageProperties) {
25
        this.fileStorageLocation = Paths.get(fileStorageProperties.getUploadDir())
26
                .toAbsolutePath().normalize();
27
 
          
28
        try {
29
            Files.createDirectories(this.fileStorageLocation);
30
        } catch (Exception ex) {
31
            throw new DocumentStorageException("Could not create the directory where the uploaded files will be stored.", ex);
32
        }
33
    }
34
 
          
35
    public String storeFile(MultipartFile file, Integer userId, String docType) {
36
        // Normalize file name
37
        String originalFileName = StringUtils.cleanPath(file.getOriginalFilename());
38
        String fileName = "";
39
 
          
40
        try {
41
            // Check if the file's name contains invalid characters
42
            if(originalFileName.contains("..")) {
43
                throw new DocumentStorageException("Sorry! Filename contains invalid path sequence " + originalFileName);
44
            }
45
 
          
46
            String fileExtension = "";
47
            try {
48
            fileExtension = originalFileName.substring(originalFileName.lastIndexOf("."));
49
            } catch(Exception e) {
50
                fileExtension = "";
51
            }
52
            fileName = userId + "_" + docType + fileExtension;
53
         // Copy file to the target location (Replacing existing file with the same name)
54
            Path targetLocation = this.fileStorageLocation.resolve(fileName);
55
            Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);
56
            
57
            DocumnentStorageProperties doc = docStorageRepo.checkDocumentByUserId(userId, docType);
58
            if(doc != null) {
59
                doc.setDocumentFormat(file.getContentType());
60
                doc.setFileName(fileName);
61
                docStorageRepo.save(doc);
62
                
63
            } else {
64
                DocumnentStorageProperties newDoc = new DocumnentStorageProperties();
65
                newDoc.setUserId(userId);
66
                newDoc.setDocumentFormat(file.getContentType());
67
                newDoc.setFileName(fileName);
68
                newDoc.setDocumentType(docType);
69
                docStorageRepo.save(newDoc);
70
            }
71
 
          
72
            return fileName;
73
        } catch (IOException ex) {
74
            throw new DocumentStorageException("Could not store file " + fileName + ". Please try again!", ex);
75
        }
76
    }
77
 
          
78
    public Resource loadFileAsResource(String fileName) throws Exception {
79
        try {
80
            Path filePath = this.fileStorageLocation.resolve(fileName).normalize();
81
            Resource resource = new UrlResource(filePath.toUri());
82
            if(resource.exists()) {
83
                return resource;
84
            } else {
85
                throw new FileNotFoundException("File not found " + fileName);
86
            }
87
        } catch (MalformedURLException ex) {
88
            throw new FileNotFoundException("File not found " + fileName);
89
        }
90
    }
91
 
          
92
    public String getDocumentName(Integer userId, String docType) {
93
        return docStorageRepo.getUploadDocumnetPath(userId, docType);
94
        
95
    }
96
}


There are two important methods in the Service class; one is  storeFile, which will store the file at the required location and save the file details in the database. Before storing the file, we will check whether a user has already given the type of file available, and if it is available, then replace the latest file on a server and update the database with the latest information. Otherwise, it will create a new entry in the database and save the file at the required location. We will be keeping the file name as  <userId>_<docType>.<extension> just to avoid ambiguity in the file name.

The second method is  loadFileAsResource which returns the file as a Resource on the basis of file name given.

Also, we have an autowired repository object to this service which we have created in thr previous step and autowired  fileStorageLocation  on basis of upload-dir properties.

Now let's create a controller that will handle the HTTP request and send the proper response back.

Java
 




xxxxxxxxxx
1
71


 
1
import org.springframework.beans.factory.annotation.Autowired;
2
import org.springframework.core.io.Resource;
3
import org.springframework.http.HttpHeaders;
4
import org.springframework.http.MediaType;
5
import org.springframework.http.ResponseEntity;
6
import org.springframework.web.bind.annotation.*;
7
import org.springframework.web.multipart.MultipartFile;
8
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
9
import com.pocketutility.mediaservice.file.UploadFileResponse;
10
import com.pocketutility.mediaservice.service.DocumentStorageService;
11
import javax.servlet.http.HttpServletRequest;
12
import java.io.IOException;
13
import java.util.Arrays;
14
import java.util.List;
15
import java.util.stream.Collectors;
16
 
          
17
@RestController
18
public class DocumentController {
19
    
20
    @Autowired
21
    private DocumentStorageService documneStorageService;
22
    
23
    @PostMapping("/uploadFile")
24
    public UploadFileResponse uploadFile(@RequestParam("file") MultipartFile file, 
25
            @RequestParam("userId") Integer UserId,
26
            @RequestParam("docType") String docType) {
27
        String fileName = documneStorageService.storeFile(file, UserId, docType);
28
 
          
29
        String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
30
                .path("/downloadFile/")
31
                .path(fileName)
32
                .toUriString();
33
 
          
34
        return new UploadFileResponse(fileName, fileDownloadUri,
35
                file.getContentType(), file.getSize());
36
    }
37
    @GetMapping("/downloadFile")
38
    public ResponseEntity<Resource> downloadFile(@RequestParam("userId") Integer userId,
39
            @RequestParam("docType") String docType,
40
            HttpServletRequest request) {
41
        
42
        String fileName = documneStorageService.getDocumentName(userId, docType);
43
        Resource resource = null;
44
        if(fileName !=null && !fileName.isEmpty()) {
45
        try {
46
            resource = documneStorageService.loadFileAsResource(fileName);
47
        } catch (Exception e) {
48
            e.printStackTrace();
49
        }
50
        // Try to determine file's content type
51
        String contentType = null;
52
        try {
53
            contentType = request.getServletContext().getMimeType(resource.getFile().getAbsolutePath());
54
        } catch (IOException ex) {
55
            //logger.info("Could not determine file type.");
56
        }
57
        // Fallback to the default content type if type could not be determined
58
        if(contentType == null) {
59
            contentType = "application/octet-stream";
60
        }
61
 
          
62
        return ResponseEntity.ok()
63
                .contentType(MediaType.parseMediaType(contentType))
64
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
65
                .body(resource);
66
    } else {
67
        return ResponseEntity.notFound().build();
68
    }
69
        
70
    }   
71
}


So the above controller has two mappings:

  1. For uploading file
    • Request URL: /uploadFile
    • Request Parameters: Actual file, userId, docType
    • Response: Will return JSON having file information(Shown in last part of this article)
  2.  For downloading file
    • Request URL: /downloadFile
    • Request Parameters: userId and docType
    • Response: Will return the file in attachment along with content-type and other details. (If file not found for that user it will return 404 Not found code)

Other Classes which we have used are:

 UploadFileResponse: To send the response back when the upload is successful.

Java
 




xxxxxxxxxx
1
13


 
1
public class UploadFileResponse {
2
    private String fileName;
3
    private String fileDownloadUri;
4
    private String fileType;
5
    private long size;
6
 
          
7
    public UploadFileResponse(String fileName, String fileDownloadUri, String fileType, long size) {
8
        this.fileName = fileName;
9
        this.fileDownloadUri = fileDownloadUri;
10
        this.fileType = fileType;
11
        this.size = size;
12
    }
13
// Getter and Setter


 DocumentStorageException: Our own Custom exception type

Java
 




xxxxxxxxxx
1


 
1
public class DocumentStorageException extends RuntimeException {
2
    public DocumentStorageException(String message) {
3
        super(message);
4
    }
5
 
          
6
    public DocumentStorageException(String message, Throwable cause) {
7
        super(message, cause);
8
    }
9
}


In order to secure your API with Spring Basic Auth add below the class. Update the required user name and password (use online Bcrypt encoder to encode your password).

Java
 




x


 
1
import javax.sql.DataSource;
2
import org.springframework.beans.factory.annotation.Autowired;
3
import org.springframework.context.annotation.Bean;
4
import org.springframework.context.annotation.Configuration;
5
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
6
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
7
import org.springframework.security.config.annotation.web.builders.WebSecurity;
8
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
9
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
10
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
11
import org.springframework.security.crypto.password.PasswordEncoder;
12
import org.springframework.security.provisioning.JdbcUserDetailsManager;
13
 
          
14
@Configuration
15
@EnableWebSecurity
16
public class ApiSecurity extends WebSecurityConfigurerAdapter {
17
 
          
18
    @Bean
19
    public BCryptPasswordEncoder encoder() {
20
        return new BCryptPasswordEncoder();
21
    }
22
 
          
23
        @Override
24
        protected void configure(HttpSecurity http) throws Exception {
25
            http.csrf().disable();
26
            http.authorizeRequests().anyRequest().fullyAuthenticated().and()
27
             .httpBasic();
28
        }
29
        @Autowired
30
         public void configureGlobal(AuthenticationManagerBuilder authenticationMgr)
31
         throws Exception {
32
         authenticationMgr.inMemoryAuthentication().withUser("username")
33
            .password("$6y$13$9OzrtK7X4mad/te8m7uhysjfaihjsdfZdJ/fDZFaOJjrfFbYzYtzky").roles("ADMIN");
34
         }
35
    }
36
 
          


Testing using Postman:

Post request to upload a file:

Request to upload a file

Request to upload a file


GET request to download the file:

Request to dowload file

Request to dowload file


Database screenshot:

Database screenshot

Database screenshot


Verify that file is visible at the required location.

Spring Framework API Java (programming language) Spring Boot

Opinions expressed by DZone contributors are their own.

Related

  • How To Build Web Service Using Spring Boot 2.x
  • Extending Swagger and Springdoc Open API
  • Java 11 HTTP Client API to Consume Restful Web Service Created Using Spring Boot
  • How Spring Boot Starters Integrate With Your Project

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!