Google Cloud Storage + Spring Boot - File Upload, Download, and Delete
In this section, we will learn how to create a simple spring boot application to perform different file operations such as upload, download, list, and delete files from the Google Cloud Storage.
1. A little bit of Background
Google Cloud Storage
Spring Boot
2. Create a GCP Project
First, Sign into the Google console at https://console.cloud.google.com.
You can create a new project by first selecting the project dropdown in the top left and selecting "New Project".
Then Click on the "CREATE" button.
Copy "Project ID" and keep it for future purposes.
3. Create a Google Cloud Storage bucket
From cloud console, search for "Cloud Storage" like below and click on "Cloud Storage" button.
Next, click on "CREATE" button,
After that, enter "Bucket name", "Region" etc...
Copy "Bucket name" and keep it for future purposes.
Then click on "CREATE" button,
4. Create a service account key
First choose "IAM & Admin" and then click on "Service accounts".
After that, click on "CREATE SERVICE ACCOUNT".
Then, enter service account details like "Service account name", and "Service account ID" and click on "CREATE AND CONTINUE".
Then, grant basic role Editor.
Finally click on "DONE" button.
Then, from "Actions" click on "Manage keys".
Then, click on "Create new key".
Then, choose "Key type" as JSON and click on "CREATE" button.
Service account keys in JSON format will be download. Keep the file safe for future purposes.
5. Creating a simple spring boot web application
First, open the Spring initializr https://start.spring.io/
Then, Provide the Group and Artifact name. We have provided Group name com.knf.dev.demo and Artifact spring-boot-gcp-cloud-storage-file-upload-download-delete. Here I selected the Maven project - language Java 17 - Spring Boot 3.0.4 and add Spring web dependency, and GCP Storage.
Then, click on the Generate button. When we click on the Generate button, it starts packing the project in a .zip(spring-boot-gcp-cloud-storage-file-upload-download-delete) file and downloads the project. Then, Extract the Zip file.
Then, import the project on your favourite IDE.
Final Project directory:
Note: Place service account key JSON file in resources folder (Not recommended in production environment).
Complete pom.xml
<?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>3.0.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.knf.dev.demo</groupId>
<artifactId>spring-boot-gcp-cloud-storage-file-upload-download-delete</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-gcp-cloud-storage-file-upload-download-delete</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
<spring-cloud-gcp.version>4.1.1</spring-cloud-gcp.version>
<spring-cloud.version>2022.0.1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>spring-cloud-gcp-starter-storage</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>spring-cloud-gcp-dependencies</artifactId>
<version>${spring-cloud-gcp.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
<?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>3.0.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.knf.dev.demo</groupId>
<artifactId>spring-boot-gcp-cloud-storage-file-upload-download-delete</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-gcp-cloud-storage-file-upload-download-delete</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
<spring-cloud-gcp.version>4.1.1</spring-cloud-gcp.version>
<spring-cloud.version>2022.0.1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>spring-cloud-gcp-starter-storage</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>spring-cloud-gcp-dependencies</artifactId>
<version>${spring-cloud-gcp.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties
Add the following configuration to application.properties file:Specify project id, credential's location, and bucket name.spring.cloud.gcp.project-id=knf-gcp-demo-project-123
spring.cloud.gcp.credentials.location=classpath:knf-gcp-demo-project-123-9bf47abde11f.json
gcp.bucket.name=knf-sample-bucket
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB
spring.cloud.gcp.project-id=knf-gcp-demo-project-123
spring.cloud.gcp.credentials.location=classpath:knf-gcp-demo-project-123-9bf47abde11f.json
gcp.bucket.name=knf-sample-bucket
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB
Note: In this example, we placed service account key JSON file in resources folder (Not recommended in production environment).
More secure way is place JSON in somewhere in server or docker image, then create environment variable "GOOGLE_APPLICATION_CREDENTIALS" and give the location to your JSON FILE.
If your application is running on Google App Engine or Google Compute Engine, in most cases you should omit the "spring.cloud.gcp.credentials.location" property and instead, let Spring Cloud GCP Core Starter find the correct credentials for those environments.
Create File Service- FileService.java
package com.knf.dev.demo.service;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
public interface FileService {
List<String> listOfFiles();
ByteArrayResource downloadFile(String fileName);
boolean deleteFile(String fileName);
void uploadFile(MultipartFile file) throws IOException;
}
package com.knf.dev.demo.service;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
public interface FileService {
List<String> listOfFiles();
ByteArrayResource downloadFile(String fileName);
boolean deleteFile(String fileName);
void uploadFile(MultipartFile file) throws IOException;
}
Create FileServiceImpl.java
package com.knf.dev.demo.service;
import com.google.api.gax.paging.Page;
import com.google.cloud.storage.Blob;
import com.google.cloud.storage.BlobId;
import com.google.cloud.storage.BlobInfo;
import com.google.cloud.storage.Storage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@Service
public class FileServiceImpl implements FileService {
@Value("${gcp.bucket.name}")
private String bucketName;
@Autowired
Storage storage;
@Override
public List<String> listOfFiles() {
List<String> list = new ArrayList<>();
Page<Blob> blobs = storage.list(bucketName);
for (Blob blob : blobs.iterateAll()) {
list.add(blob.getName());
}
return list;
}
@Override
public ByteArrayResource downloadFile(String fileName) {
Blob blob = storage.get(bucketName, fileName);
ByteArrayResource resource = new ByteArrayResource(
blob.getContent());
return resource;
}
@Override
public boolean deleteFile(String fileName) {
Blob blob = storage.get(bucketName, fileName);
return blob.delete();
}
@Override
public void uploadFile(MultipartFile file) throws IOException {
BlobId blobId = BlobId.of(bucketName, file.getOriginalFilename());
BlobInfo blobInfo = BlobInfo.newBuilder(blobId).
setContentType(file.getContentType()).build();
Blob blob = storage.create(blobInfo,file.getBytes());
}
}
Create File Controller- FileController.java
package com.knf.dev.demo.controller;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.google.api.gax.paging.Page;
import com.google.cloud.storage.*;
import com.knf.dev.demo.service.FileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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;
/**
* A REST Controller that exposes upload, download,
* list, and delete file operations on Google Cloud Storage.
*/
@RestController
@RequestMapping("/api/v1/files")
public class FileController {
@Autowired
FileService fileService;
//List all file name
@GetMapping
public ResponseEntity<List<String>> listOfFiles() {
List<String> files = fileService.listOfFiles();
return ResponseEntity.ok(files);
}
//Upload file
@PostMapping("upload")
public ResponseEntity<String> uploadFile(
@RequestParam MultipartFile file) throws IOException {
fileService.uploadFile(file);
return ResponseEntity.ok("File uploaded successfully");
}
//Delete file
@DeleteMapping("delete")
public ResponseEntity<String> deleteFile(
@RequestParam String fileName) {
fileService.deleteFile(fileName);
return ResponseEntity.ok(" File deleted successfully");
}
//Download file
@GetMapping("download")
public ResponseEntity<Resource> downloadFile(
@RequestParam String fileName) {
ByteArrayResource resource = fileService.downloadFile(fileName);
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + fileName + "\"");
return ResponseEntity.ok().
contentType(MediaType.APPLICATION_OCTET_STREAM).
headers(headers).body(resource);
}
}
package com.knf.dev.demo.controller;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.google.api.gax.paging.Page;
import com.google.cloud.storage.*;
import com.knf.dev.demo.service.FileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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;
/**
* A REST Controller that exposes upload, download,
* list, and delete file operations on Google Cloud Storage.
*/
@RestController
@RequestMapping("/api/v1/files")
public class FileController {
@Autowired
FileService fileService;
//List all file name
@GetMapping
public ResponseEntity<List<String>> listOfFiles() {
List<String> files = fileService.listOfFiles();
return ResponseEntity.ok(files);
}
//Upload file
@PostMapping("upload")
public ResponseEntity<String> uploadFile(
@RequestParam MultipartFile file) throws IOException {
fileService.uploadFile(file);
return ResponseEntity.ok("File uploaded successfully");
}
//Delete file
@DeleteMapping("delete")
public ResponseEntity<String> deleteFile(
@RequestParam String fileName) {
fileService.deleteFile(fileName);
return ResponseEntity.ok(" File deleted successfully");
}
//Download file
@GetMapping("download")
public ResponseEntity<Resource> downloadFile(
@RequestParam String fileName) {
ByteArrayResource resource = fileService.downloadFile(fileName);
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + fileName + "\"");
return ResponseEntity.ok().
contentType(MediaType.APPLICATION_OCTET_STREAM).
headers(headers).body(resource);
}
}
Run the application - Application.java
package com.knf.dev.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Application is the entry point that sets up the Spring Boot application. The @SpringBootApplication annotation enables auto-configuration and component scanning.
package com.knf.dev.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Step1: Download or clone the source code from GitHub to a local machine - Click here!
Step 2: mvn clean install
Step 3: Run the Spring Boot application - mvn spring-boot:run
OR
Run this Spring boot application from
- IntelliJ IDEA IDE by right click - Run 'Application.main()'
- Eclipse/STS - You can right click the project or the Application.java file and run as java application or Spring boot application.
Step1: Download or clone the source code from GitHub to a local machine - Click here!
Step 2: mvn clean install
Step 3: Run the Spring Boot application - mvn spring-boot:run
OR
Run this Spring boot application from
- IntelliJ IDEA IDE by right click - Run 'Application.main()'
- Eclipse/STS - You can right click the project or the Application.java file and run as java application or Spring boot application.
Upload File:
Get all file name:
Delete File:
Download File: