How to upload and download a file with Azure Blob Storage and Spring Boot

Azure Blob storage is Microsoft's object storage solution for the cloud. Blob storage is optimized for storing massive amounts of unstructured data. Unstructured data is data that doesn't adhere to a particular data model or definition, such as text or binary data.

How to upload and download a file with Azure Blob Storage and Spring Boot

Hello, I'm Srivastava, in this post we will see how to upload a file to Azure Blob Storage and download the file from the same.

What is Azure Blob Storage?

Azure Blob storage is Microsoft's object storage solution for the cloud. Blob storage is optimized for storing massive amounts of unstructured data. Unstructured data is data that doesn't adhere to a particular data model or definition, such as text or binary data.

Why use Blob Storage?

Blob storage is designed for:

  • Serving images or documents directly to a browser.
  • Storing files for distributed access.
  • Streaming video and audio.
  • Writing to log files.
  • Storing data for backup and restore, disaster recovery, and archiving.
  • Storing data for analysis by an on-premises or Azure-hosted service.

Blob Storage Resources

Blob storage offers three types of resources:

  • The storage account
  • A container in the storage account
  • A blob in a container

The following diagram shows the relationship between these resources.

Storage Accounts

A storage account provides a unique namespace in Azure for your data. Every object that you store in Azure Storage has an address that includes your unique account name. The combination of the account name and the Azure Storage blob endpoint forms the base address for the objects in your storage account.

For example, if your storage account is named mystorageaccount, then the default endpoint for Blob storage is:

Follow the instructions provided here to create storage account. 

The details we need from the storage account are: Account Name, Account Key, Blob Endpoint


A container organizes a set of blobs, similar to a directory in a file system. A storage account can include an unlimited number of containers, and a container can store an unlimited number of blobs.

Note: The container name must be lowercase.


Azure Storage supports three types of blobs:

  • Block blobs store text and binary data. Block blobs are made up of blocks of data that can be managed individually. Block blobs can store up to about 190.7 TiB.
  • Append blobs are made up of blocks like block blobs, but are optimized for append operations. Append blobs are ideal for scenarios such as logging data from virtual machines.
  • Page blobs store random access files up to 8 TiB in size. Page blobs store virtual hard drive (VHD) files and serve as disks for Azure virtual machines.


Creating the Project

Spring Boot provides Spring Initializr, a quick start generator for Spring Projects. Head over to to access this web tool. Include web,azure storage, lombok, devtools and configuration processor dependencies and click generate. A zip file will be downloaded which contains your project related settings and a pom.xml to get dependencies. You can unzip it and import it into your favourite IDE.


Some IDEs such as IntelliJ, STS will allow you to create project right from it that has Spring Initializr.

If you want to manually include the storage dependency, the following dependency should be added to your pom.xml.


Making Changes

Once you boostrapped the project, open and add the following properties to it


I gave uploads directory as my file storage location which would be under our project root path. This would directory will be created when we start our app (of course we will configure it). You can give your own path to be uploaded.

Create few packages inside your main package (e.g. com.fileapi) such as controller, config, property, and service packages.

Add the following code in property package.


import lombok.Getter;
import lombok.Setter;

@ConfigurationProperties(prefix = "file")
public class FileStorageProperties {

    private String uploadDir;


We have used @ConfigurationProperties(prefix = "file") annotation so that it binds all the properties with prefix file to the fields in our class on application startup. If you want to create an additional file property in properties file, all you need to do is to just add a field in our class.

Enabling Configuration Properties

To make @ConfigurationProperties feature work, you need to add @EnableConfigurationProperties to any configuration class. We will add it in our main class. So open src/main/java/com/fileapi/ and add the @EnableConfigurationProperties annoation to it like this:

package com.fileapi;

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

public class SpringBootAzureFileApiApplication {

    public static void main(String[] args) {, args);


Now create a file named and add the following code to it

package com.fileapi.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Locale;

public class AzureBlobStorageConfig {

    private String accountName;

    private String accountKey;

    public BlobServiceClient getBlobServiceClient() {
        return new BlobServiceClientBuilder()
                .endpoint(String.format(Locale.ROOT, "", accountName))
                .credential(new StorageSharedKeyCredential(accountName, accountKey))

We created the configuration to get the BlobServiceClient bean. It uses the storage account name and account key.

Service for upload and download

Create a file in service package and add the following code to it.

package com.fileapi.service;

import lombok.NonNull;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class FileService {

    private final Path fileStorageLocation;
    private final BlobServiceClient blobServiceClient;

    public FileService(@NonNull FileStorageProperties fileStorageProperties, BlobServiceClient blobServiceClient) {
        // get the path of the upload directory
        fileStorageLocation = Path.of(fileStorageProperties.getUploadDir());
        this.blobServiceClient = blobServiceClient;
        try {
            // creates directory/directories, if directory already exists, it will not throw exception
        } catch (IOException e) {
            log.error("Could not create the directory where the uploaded files will be stored.", e);

    public Path getFileStorageLocation() {
        try {
        } catch (IOException e) {
            log.error("Could not create the directory where the uploaded file will be stored.", e);
        return fileStorageLocation;

    public Boolean uploadAndDownloadFile(@NonNull MultipartFile file, String containerName) {
        boolean isSuccess = true;
        BlobContainerClient blobContainerClient = getBlobContainerClient(containerName);
        String filename = file.getOriginalFilename();
        BlockBlobClient blockBlobClient = blobContainerClient.getBlobClient(filename).getBlockBlobClient();
        try {
            // delete file if already exists in that container
            if (blockBlobClient.exists()) {
            // upload file to azure blob storage
            blockBlobClient.upload(new BufferedInputStream(file.getInputStream()), file.getSize(), true);
            String tempFilePath = fileStorageLocation + "/" + filename;
            // download file from azure blob storage to a file
            blockBlobClient.downloadToFile(new File(tempFilePath).getPath());
        } catch (IOException e) {
            isSuccess = false;
            log.error("Error while processing file {}", e.getLocalizedMessage());
        return isSuccess;

    private @NonNull BlobContainerClient getBlobContainerClient(@NonNull String containerName) {
        // create container if not exists
        BlobContainerClient blobContainerClient = blobServiceClient.getBlobContainerClient(containerName);
        if (!blobContainerClient.exists()) {
        return blobContainerClient;

In the above service there are a couple of important things going on. In the getBlobContainerClient() method, we are creating the container if not exists. Remember we created bean to get BlobServiceClient and now we have autorwired in the service. And we are building BlockBlobClient passing file to it. If the same file exists in the container, we are deleting it. Finally we upload the file to azure blob storage. As we already have the reference to the to the uploaded file, we are calling the method downloadToFile() and storing it in our file storage location.

Controller for REST API

Create a file in controller package and add the following code to it.

package com.fileapi.controller;

import com.fileapi.service.FileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.nio.file.Files;
import java.nio.file.Paths;

public class FileController {

    private final FileService fileService;

    public FileController(FileService fileService) {
        this.fileService = fileService;

    @PostMapping(value = "/", produces = {MediaType.IMAGE_PNG_VALUE, MediaType.IMAGE_JPEG_VALUE})
    public ResponseEntity<?> uploadAndDownload(@RequestParam("file") MultipartFile file) {
        try {
            if (fileService.uploadAndDownloadFile(file, "files")) {
                final ByteArrayResource resource = new ByteArrayResource(Files.readAllBytes(Paths.get(fileService
                        .getFileStorageLocation() + "/" + file.getOriginalFilename())));
                return ResponseEntity.status(HttpStatus.OK).contentLength(resource.contentLength()).body(resource);
            return ResponseEntity.ok("Error while processing file");
        } catch (Exception e) {
            return ResponseEntity.ok("Error while processing file");

For the purpose of this example, I have used only images (png and jpeg) to upload and download. I have given the container name as "files".

Testing the API

You can also find the source code at github.

Thanks for reading!