Skip to content

Commit f0fb5f9

Browse files
committed
migrate web s3 to azure blob storage
1 parent 8d0748a commit f0fb5f9

File tree

4 files changed

+62
-84
lines changed

4 files changed

+62
-84
lines changed

asset-manager/web/pom.xml

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,14 @@
3131
<artifactId>spring-boot-starter-amqp</artifactId>
3232
</dependency>
3333
<dependency>
34-
<groupId>software.amazon.awssdk</groupId>
35-
<artifactId>s3</artifactId>
34+
<groupId>com.azure</groupId>
35+
<artifactId>azure-storage-blob</artifactId>
36+
<version>12.29.0</version>
37+
</dependency>
38+
<dependency>
39+
<groupId>com.azure</groupId>
40+
<artifactId>azure-identity</artifactId>
41+
<version>1.14.2</version>
3642
</dependency>
3743
<dependency>
3844
<groupId>org.springframework.boot</groupId>
@@ -69,9 +75,9 @@
6975
<dependencyManagement>
7076
<dependencies>
7177
<dependency>
72-
<groupId>software.amazon.awssdk</groupId>
73-
<artifactId>s3</artifactId>
74-
<version>${aws-sdk.version}</version>
78+
<groupId>com.azure</groupId>
79+
<artifactId>azure-storage-blob-batch</artifactId>
80+
<version>12.25.0</version>
7581
</dependency>
7682
</dependencies>
7783
</dependencyManagement>
Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,23 @@
11
package com.microsoft.migration.assets.config;
22

3+
import com.azure.identity.DefaultAzureCredentialBuilder;
4+
import com.azure.storage.blob.BlobServiceClient;
5+
import com.azure.storage.blob.BlobServiceClientBuilder;
36
import org.springframework.beans.factory.annotation.Value;
47
import org.springframework.context.annotation.Bean;
58
import org.springframework.context.annotation.Configuration;
69

7-
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
8-
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
9-
import software.amazon.awssdk.regions.Region;
10-
import software.amazon.awssdk.services.s3.S3Client;
11-
1210
@Configuration
1311
public class AwsS3Config {
1412

15-
@Value("${aws.accessKey}")
16-
private String accessKey;
17-
18-
@Value("${aws.secretKey}")
19-
private String secretKey;
20-
21-
@Value("${aws.region}")
22-
private String region;
13+
@Value("${azure.storage.account-name}")
14+
private String accountName;
2315

2416
@Bean
25-
public S3Client s3Client() {
26-
AwsBasicCredentials awsCredentials = AwsBasicCredentials.create(accessKey, secretKey);
27-
28-
return S3Client.builder()
29-
.region(Region.of(region))
30-
.credentialsProvider(StaticCredentialsProvider.create(awsCredentials))
31-
.build();
17+
public BlobServiceClient blobServiceClient() {
18+
return new BlobServiceClientBuilder()
19+
.endpoint("https://" + accountName + ".blob.core.windows.net")
20+
.credential(new DefaultAzureCredentialBuilder().build())
21+
.buildClient();
3222
}
3323
}

asset-manager/web/src/main/java/com/microsoft/migration/assets/service/AwsS3Service.java

Lines changed: 37 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
package com.microsoft.migration.assets.service;
22

3+
import com.azure.identity.DefaultAzureCredentialBuilder;
4+
import com.azure.storage.blob.BlobServiceClient;
5+
import com.azure.storage.blob.BlobServiceClientBuilder;
6+
import com.azure.storage.blob.models.BlobHttpHeaders;
7+
import com.azure.storage.blob.models.BlobItem;
8+
import com.azure.storage.blob.options.BlobParallelUploadOptions;
39
import com.microsoft.migration.assets.model.ImageMetadata;
410
import com.microsoft.migration.assets.model.ImageProcessingMessage;
511
import com.microsoft.migration.assets.model.S3StorageItem;
@@ -10,9 +16,6 @@
1016
import org.springframework.context.annotation.Profile;
1117
import org.springframework.stereotype.Service;
1218
import org.springframework.web.multipart.MultipartFile;
13-
import software.amazon.awssdk.core.sync.RequestBody;
14-
import software.amazon.awssdk.services.s3.S3Client;
15-
import software.amazon.awssdk.services.s3.model.*;
1619

1720
import java.io.IOException;
1821
import java.io.InputStream;
@@ -28,37 +31,31 @@
2831
@Profile("!dev") // Active when not in dev profile
2932
public class AwsS3Service implements StorageService {
3033

31-
private final S3Client s3Client;
34+
private final BlobServiceClient blobServiceClient;
3235
private final RabbitTemplate rabbitTemplate;
3336
private final ImageMetadataRepository imageMetadataRepository;
3437

35-
@Value("${aws.s3.bucket}")
36-
private String bucketName;
38+
@Value("${azure.storage.blob.container-name}")
39+
private String containerName;
3740

3841
@Override
3942
public List<S3StorageItem> listObjects() {
40-
ListObjectsV2Request request = ListObjectsV2Request.builder()
41-
.bucket(bucketName)
42-
.build();
43-
44-
ListObjectsV2Response response = s3Client.listObjectsV2(request);
45-
46-
return response.contents().stream()
47-
.map(s3Object -> {
43+
return blobServiceClient.getBlobContainerClient(containerName).listBlobs().stream()
44+
.map(blobItem -> {
4845
// Try to get metadata for upload time
4946
Instant uploadedAt = imageMetadataRepository.findAll().stream()
50-
.filter(metadata -> metadata.getS3Key().equals(s3Object.key()))
47+
.filter(metadata -> metadata.getS3Key().equals(blobItem.getName()))
5148
.map(metadata -> metadata.getUploadedAt().atZone(java.time.ZoneId.systemDefault()).toInstant())
5249
.findFirst()
53-
.orElse(s3Object.lastModified()); // fallback to lastModified if metadata not found
50+
.orElse(blobItem.getProperties().getLastModified().toInstant()); // fallback to lastModified if metadata not found
5451

5552
return new S3StorageItem(
56-
s3Object.key(),
57-
extractFilename(s3Object.key()),
58-
s3Object.size(),
59-
s3Object.lastModified(),
53+
blobItem.getName(),
54+
extractFilename(blobItem.getName()),
55+
blobItem.getProperties().getContentLength(),
56+
blobItem.getProperties().getLastModified().toInstant(),
6057
uploadedAt,
61-
generateUrl(s3Object.key())
58+
generateUrl(blobItem.getName())
6259
);
6360
})
6461
.collect(Collectors.toList());
@@ -67,14 +64,11 @@ public List<S3StorageItem> listObjects() {
6764
@Override
6865
public void uploadObject(MultipartFile file) throws IOException {
6966
String key = generateKey(file.getOriginalFilename());
70-
71-
PutObjectRequest request = PutObjectRequest.builder()
72-
.bucket(bucketName)
73-
.key(key)
74-
.contentType(file.getContentType())
75-
.build();
76-
77-
s3Client.putObject(request, RequestBody.fromInputStream(file.getInputStream(), file.getSize()));
67+
68+
var blobClient = blobServiceClient.getBlobContainerClient(containerName).getBlobClient(key);
69+
BlobHttpHeaders headers = new BlobHttpHeaders().setContentType(file.getContentType());
70+
BlobParallelUploadOptions options = new BlobParallelUploadOptions(file.getInputStream()).setHeaders(headers);
71+
blobClient.uploadWithResponse(options, null, null);
7872

7973
// Send message to queue for thumbnail generation
8074
ImageProcessingMessage message = new ImageProcessingMessage(
@@ -99,31 +93,23 @@ public void uploadObject(MultipartFile file) throws IOException {
9993

10094
@Override
10195
public InputStream getObject(String key) throws IOException {
102-
GetObjectRequest request = GetObjectRequest.builder()
103-
.bucket(bucketName)
104-
.key(key)
105-
.build();
106-
107-
return s3Client.getObject(request);
96+
return blobServiceClient.getBlobContainerClient(containerName)
97+
.getBlobClient(key)
98+
.openInputStream();
10899
}
109100

110101
@Override
111102
public void deleteObject(String key) throws IOException {
112103
// Delete both original and thumbnail if it exists
113-
DeleteObjectRequest request = DeleteObjectRequest.builder()
114-
.bucket(bucketName)
115-
.key(key)
116-
.build();
117-
118-
s3Client.deleteObject(request);
104+
blobServiceClient.getBlobContainerClient(containerName)
105+
.getBlobClient(key)
106+
.delete();
119107

120108
try {
121109
// Try to delete thumbnail if it exists
122-
DeleteObjectRequest thumbnailRequest = DeleteObjectRequest.builder()
123-
.bucket(bucketName)
124-
.key(getThumbnailKey(key))
125-
.build();
126-
s3Client.deleteObject(thumbnailRequest);
110+
blobServiceClient.getBlobContainerClient(containerName)
111+
.getBlobClient(getThumbnailKey(key))
112+
.delete();
127113
} catch (Exception e) {
128114
// Ignore if thumbnail doesn't exist
129115
}
@@ -137,21 +123,19 @@ public void deleteObject(String key) throws IOException {
137123

138124
@Override
139125
public String getStorageType() {
140-
return "s3";
126+
return "azure";
141127
}
142128

143129
private String extractFilename(String key) {
144130
// Extract filename from the object key
145131
int lastSlashIndex = key.lastIndexOf('/');
146132
return lastSlashIndex >= 0 ? key.substring(lastSlashIndex + 1) : key;
147133
}
148-
134+
149135
private String generateUrl(String key) {
150-
GetUrlRequest request = GetUrlRequest.builder()
151-
.bucket(bucketName)
152-
.key(key)
153-
.build();
154-
return s3Client.utilities().getUrl(request).toString();
136+
return blobServiceClient.getBlobContainerClient(containerName)
137+
.getBlobClient(key)
138+
.getBlobUrl();
155139
}
156140

157141
private String generateKey(String filename) {

asset-manager/web/src/main/resources/application.properties

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
spring.application.name=assets-manager
22

3-
# AWS S3 Configuration
4-
aws.accessKey=your-access-key
5-
aws.secretKey=your-secret-key
6-
aws.region=us-east-1
7-
aws.s3.bucket=your-bucket-name
3+
# Azure Blob Storage Configuration
4+
azure.storage.account-name=${AZURE_STORAGE_ACCOUNT_NAME}
5+
azure.storage.blob.container-name=${AZURE_STORAGE_BLOB_CONTAINER_NAME}
86

97
# Max file size for uploads
108
spring.servlet.multipart.max-file-size=10MB
@@ -22,4 +20,4 @@ spring.datasource.username=postgres
2220
spring.datasource.password=postgres
2321
spring.jpa.hibernate.ddl-auto=update
2422
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
25-
spring.jpa.show-sql=true
23+
spring.jpa.show-sql=true

0 commit comments

Comments
 (0)