Spring boot: uploading and downloading file Azure Blob Store using rest API

Spring boot: uploading and downloading file Azure Blob Store using rest API

If you have landed on this page means either your working with spring boot and trying to upload a file to Azure blob storage. so we know spring boot has gained popularity for its simple approach to bootstrap an application in very less time, Also Azure is gaining a lot of popularity these days as people are looking for an alternative.

So if you're wondering what is Azure Blob, it is another object store just like AWS S3 where you store and retrieve the file using API in pay as you go fashion and eliminating the scalability from your hands.

So now we shall see how to upload and download files from Azure Blob Store using spring boot. but before we need to do a couple of steps prior.

1) Pre Setup Create Storage Account On Azure

2) Fill the above form and click on review and create

3) Next step is to create a Container, a place where are files are store logically. in reality there will different physical locations for a single file.

4) Navigate to storage account > Access Keys and copy the connection string.

Now Create Spring boot application and add these dependencies to your pom.

<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>

the above dependency provides multipart file upload capability to the spring boot application.

<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-storage-blob</artifactId>
<version>12.6.0</version>
</dependency>

the Azure Client Storage is the java SDK provided by Azure themselves. using this we write the wrapper so we can reuse the required feature. So my completed pom looks like this

<?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.3.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>azureblob</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>demo</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>11</java.version>
	</properties>

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

		<dependency>
			<groupId>com.azure</groupId>
			<artifactId>azure-storage-blob</artifactId>
			<version>12.6.0</version>
		</dependency>

		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger2</artifactId>
			<version>2.8.0</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger-ui</artifactId>
			<version>2.8.0</version>
			<scope>compile</scope>
		</dependency>

		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.3.1</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>



</project>

Add the connection String to your property file.

blob.connection-string=<your key from azure portal>
blob.container-name=<container-anme>

Create the Configuration Class returns the  BlobClientBuilder Bean.

package com.example.azureblob;

import com.azure.storage.blob.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AzureStorageBlobClientConfig {

    @Value("${blob.connection-string}")
    String connectionString;

    @Value("${blob.container-name}")
    String containerName;

    @Bean
    public BlobClientBuilder getClient() {
        BlobClientBuilder client = new BlobClientBuilder();
        client.connectionString(connectionString);
        client.containerName(containerName);
        return client;
    }
}

The soul purpose of this class is to make the client builder singleton and to auto-wire it where ever necessary. And also we can change the connection based on a different profile. the bean

Let's write the Adapter Service Class which implements file upload and download logic.

package com.example.azureblob;

import com.azure.storage.blob.BlobClientBuilder;
import com.azure.storage.blob.models.BlobProperties;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.UUID;

@Service
public class AzureBlobAdapter {

    @Autowired
    BlobClientBuilder client;




    public String upload(MultipartFile file, String prefixName) {
        if(file != null && file.getSize() > 0) {
            try {
                //implement your own file name logic.
                String fileName = prefixName+ UUID.randomUUID().toString() +file.getOriginalFilename();
                client.blobName(fileName).buildClient().upload(file.getInputStream(),file.getSize());
                return fileName;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    public byte[] getFile(String name) {
        try {
            File temp = new File("/temp/"+name);
            BlobProperties properties = client.blobName(name).buildClient().downloadToFile(temp.getPath());
            byte[] content = Files.readAllBytes(Paths.get(temp.getPath()));
            temp.delete();
            return content;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public boolean deleteFile(String name) {
        try {
            client.blobName(name).buildClient().delete();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }


}

As we are familiar with the Adapter design pattern we write the middle layer to implement the required feature of the third party client by casting input and output to our fit.

Final Step lets create the controller and implement those.

this is the bonus section for those who are searching google for uploading the file using spring boot's rest controller. also downloading the file without leaving this page :-P

package com.example.azureblob;

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

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@RestController
public class AzureBlobFileController {
    @Autowired
    AzureBlobAdapter azureAdapter;



    @PostMapping(path = "/upload", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
    public Map<String, String> uploadFile(@RequestPart(value = "file", required = true) MultipartFile files)  {
        String name = azureAdapter.upload(files, "prefix");
        Map<String, String> result = new HashMap<>();
        result.put("key", name);
        return result;
    }

    @GetMapping(path = "/download")
    public ResponseEntity<ByteArrayResource> uploadFile(@RequestParam(value = "file") String file) throws IOException {
        byte[] data = azureAdapter.getFile(file);
        ByteArrayResource resource = new ByteArrayResource(data);

        return ResponseEntity
                .ok()
                .contentLength(data.length)
                .header("Content-type", "application/octet-stream")
                .header("Content-disposition", "attachment; filename=\"" + file + "\"")
                .body(resource);

    }
}

I have implemented the file upload and download Rest Urls, which covers major use cases for the fellow developer, also Adapter provides delete feature. i hope that will be easy for anyone to map it to the Rest endpoint.

Also Helpful articles:

AWS S3 with Spring Boot: Uploading and downloading file to Buckets
So if are reading this Article means your a developer and your familiar withspring boot or AWS S3, just for SEO purpose i will brief both,so you can skipthe introduction part and jump into coding part.As a developer Spring boot hasbecome my vital Framework and preferred choice of man developer, i…
Spring boot: uploading and downloading file from Minio object store
If you have landed on this page means either your working with spring boot andtrying to upload an file to a privately hosted minio object store server. so weknow spring boot has gained popularity for its simple approach to bootstrap anapplication in very less time, Also minio is gaining lot of p…
Continuous deployment of spring boot Apps on Azure App service using GIT lab CI
Continuous deployment is an automated process of releasing production code tothe desired infrastructure, Only after Continuous Integration pipelines aresatisfied. CI (Continuous Integration) is making sure every piece of code is tested &validated in an automated fashion whenever code pushed to t…
Tutorial: Upload and download file in spring boot application RESTAPI
Spring boot is as an awesome framework where we could rapidly start our webdevelopment project with in minutes,java based configuration simplifiesbootstrapping time where we could include third party library or other componentinto our applications. and to upload file in spring boot application is…