![Google Cloud Storage Spring Boot Integration](https://engineervoice.in/wp-content/uploads/2024/05/Google-Cloud-Storage-Spring-Boot-Integration-1024x557.png)
Google Cloud Storage Spring Boot integration can significantly enhance your project’s capabilities and your skills as a developer by enabling robust data storage and retrieval functionalities. In this article, I’ll walk you through the process of configuring Google Cloud with Spring Boot, covering authentication using Google Application Credentials and showing how to upload and download files to and from Google Cloud Storage. Before we move forward, I assume you have a basic understanding of Spring Boot, Java, and GCP.
Google cloud platform Setup
- Go to the Google Cloud Console.
- Create a new project or select an existing one.
- Enable the Google Cloud Storage JSON API.
- Navigate to IAM & Admin > Service Accounts.
- Select an existing one or create a new service account.
- Grant the service account the Storage Admin role.
- Generate a JSON key for the service account and download it.
- Set the
GOOGLE_APPLICATION_CREDENTIALS
environment variable to point to the JSON key file:
GOOGLE_APPLICATION_CREDENTIALS="/path/to/your-service-account-file.json"
Spring Boot Project Setup
- Go to Spring Initializr to generate a new Spring Boot project and import it into Intellij.
- Include the following dependencies:
- Spring Web
- Spring Boot DevTools
- Google Cloud Storage
- In
pom.xml
, add the following dependency:
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-storage</artifactId>
<version>2.1.5</version>
</dependency>
Authentication Configuration
Create a class GoogleHttpRequestInitializer.java
to handle authentication.
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestInitializer;
import java.io.IOException;
import java.util.Arrays;
public class GoogleHttpRequestInitializer implements HttpRequestInitializer {
private GoogleCredentials credentials;
private HttpCredentialsAdapter adapter;
@Override
public void initialize(HttpRequest httpRequest) throws IOException {
credentials = GoogleCredentials.getApplicationDefault()
.createScoped(Arrays.asList("https://www.googleapis.com/auth/cloud-platform"));
adapter = new HttpCredentialsAdapter(credentials);
adapter.initialize(httpRequest);
httpRequest.setConnectTimeout(60000); // 1 minute connect timeout
httpRequest.setReadTimeout(60000); // 1 minute read timeout
}
public GoogleCredentials getCredentials() {
return credentials;
}
public void setCredentials(GoogleCredentials credentials) {
this.credentials = credentials;
}
public HttpCredentialsAdapter getAdapter() {
return adapter;
}
public void setAdapter(HttpCredentialsAdapter adapter) {
this.adapter = adapter;
}
}
- GoogleCredentials.getApplicationDefault(): This method retrieves the default credentials from the environment variable
GOOGLE_APPLICATION_CREDENTIALS
. - createScoped(): It sets the scope for the credentials, allowing access to the Google Cloud Platform.
- HttpCredentialsAdapter: This adapter integrates credentials with HTTP requests.
Storage Client Adapter Implementation
You need to create another class GoogleStorageClientAdapter.java
to handle file operations.
- uploadFile:
- Creates a
StorageObject
with a file name and path. - Converts the
MultipartFile
to anInputStream
. - Use
storage.objects().insert
to upload the file to Google Cloud Storage.
- Creates a
- readFile:
- Checks if the file exists using
existFile
. - Retrieves the
StorageObject
from Google Cloud Storage. - Builds a GET request to download the file using the object’s media link.
- Checks if the file exists using
import com.google.api.client.http.AbstractInputStreamContent;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.InputStreamContent;
import com.google.api.services.storage.Storage;
import com.google.api.services.storage.model.StorageObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@Component
@Slf4j
public class GoogleStorageClientAdapter {
@Autowired
private Storage storage;
public Boolean uploadFile(String bucketName, String path, MultipartFile file) {
log.info("GoogleStorageClientAdapter uploadFile with bucketName={} and path={}", bucketName, path);
StorageObject object = new StorageObject();
object.setName(path + file.getOriginalFilename());
try (InputStream targetStream = new ByteArrayInputStream(file.getBytes())) {
storage.objects().insert(bucketName, object,
new AbstractInputStreamContent(path + file.getOriginalFilename()) {
@Override
public long getLength() {
return file.getSize();
}
@Override
public boolean retrySupported() {
return false;
}
@Override
public InputStream getInputStream() throws IOException {
return targetStream;
}
}).execute();
} catch (IOException e) {
log.error("Exception GoogleStorageClientAdapter uploadFile: ", e);
e.printStackTrace();
return false;
}
log.info("GoogleStorageClientAdapter uploadFile done successfully");
return true;
}
public InputStream readFile(String bucketName, String path, String fileName) {
log.info("GoogleStorageClientAdapter readFile with bucketName={} path={} and fileName={}", bucketName, path, fileName);
if (!existFile(bucketName, path, fileName)) {
log.info("Cannot find details with bucketName={} path={} and fileName={}", bucketName, path, fileName);
return null;
}
try {
StorageObject object = storage.objects().get(bucketName, path + fileName).execute();
return storage.getRequestFactory().buildGetRequest(new GenericUrl(object.getMediaLink()))
.execute().getContent();
} catch (IOException e) {
log.error("Exception GoogleStorageClientAdapter readFile: ", e);
e.printStackTrace();
return null;
}
}
private boolean existFile(String bucketName, String path, String fileName) {
try {
StorageObject object = storage.objects().get(bucketName, path + fileName).execute();
return object != null;
} catch (IOException e) {
log.error("Exception in existFile: ", e);
return false;
}
}
}
Storage Client Adapter in a Controller
Finally, one class FileController.java
to manage file upload and download requests.
- uploadFileToBucket:
- Handle POST requests to
/files/upload
. - It calls
uploadFile
on theGoogleStorageClientAdapter
. - Return a success or error response based on the outcome.
- Handle POST requests to
- downloadFileFromBucket:
- Handles GET requests to
/files/download
. - Calls
readFile
on theGoogleStorageClientAdapter
. - Returns the file stream or a “file not found” message.
- Handles GET requests to
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("/files")
public class FileController {
@Autowired
private GoogleStorageClientAdapter googleStorageClientAdapter;
@PostMapping("/upload")
public ResponseEntity<String> uploadFileToBucket(@RequestParam("file") MultipartFile file //file to be stored
@RequestParam("path") String path, // bucket path
@RequestParam("bucketName") String bucketName // bucket name) {
boolean isUploaded = googleStorageClientAdapter.uploadFile(bucketName, path, file);
if (isUploaded) {
return new ResponseEntity<>("File uploaded successfully", HttpStatus.OK);
} else {
return new ResponseEntity<>("Failed to upload file", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@GetMapping("/download")
public ResponseEntity<?> downloadFileFromBucket() {
// pass the bucket name, path, filename
InputStream fileStream = googleStorageClientAdapter.readFile(bucketName, path, fileName);
if (fileStream != null) {
return ResponseEntity.ok().body(fileStream);
}else {
return new ResponseEntity<>("File not found", HttpStatus.NOT_FOUND);
}
}
}
Conclusion
Google Cloud Storage Spring Boot integration is a straight-forward process. Through configuring Google Application Credentials and utilizing the GoogleHttpRequestInitializer for authentication, you can seamlessly interact with Google Cloud Storage. Additionally, the GoogleStorageClientAdapter shows how to upload and read files from Google Cloud Storage, rendering it a valuable tool for your Spring Boot applications. Consequently, adhere to the above process to seamlessly integrate Google Cloud Storage into your Spring Boot project, thereby ensuring efficient and secure file management capabilities.