諸事情でAzureのBlob Storageへアップロードおよびダウンロードを行う方法を調べる機会があったので、少しメモっておきます。
検証バージョン
- Spring Boot 2.5.2
- Azure Spring Boot 3.6.0
- Azure Storage Blob(Azure JDK for Java) 12.12.0
試したこと
以下の3つの方法でアップロード/ダウンロードが行えることを確認しました。
- Springの
Resource
インタフェース経由でアクセスする方法 - DIコンテナから
BlobServiceClientBuilder
を取得してAzure JDKのAPI経由でアクセスする方法 - DIコンテナは使わずに Azure JDK のAPI経由でアクセスする方法
Springの Resource
インタフェースの利用
Azure Spring Bootを利用すると、Spring の Resource
インタフェース経由でアップロード及びダウンロードを行うことができます。
azure:
storage:
account-name: kazuki43zoostorage
# アカウントキーは環境変数から取得
#account-key: ${AZURE_STORAGE_ACCOUNT_KEY}
blob-endpoint: https://${azure.storage.account-name}.blob.core.windows.net
export AZURE_STORAGE_ACCOUNT_KEY=xxxxxxxxxxx
@Value("azure-blob://test-container/data/uploadAndDownloadWithResource.txt")
Resource sampleText;
@Test
void uploadAndDownloadWithResource() throws IOException {
// Upload
String content = "uploadAndDownloadWithResource";
try (OutputStream out = ((WritableResource) sampleText).getOutputStream()) {
out.write(content.getBytes(StandardCharsets.UTF_8));
}
// Download
try (InputStream in = sampleText.getInputStream()) {
Assertions.assertThat(StreamUtils.copyToString(in, StandardCharsets.UTF_8)).isEqualTo(content);
}
}
DIコンテナに登録される BlobServiceClientBuilder
を利用
Azure Spring Bootを利用すると、Azure Blobに接続するためのコンポーネント(BlobServiceClientBuilder
)をDIコンテナから取得し、Azure JDKのAPIを呼び出すことでアップロード及びダウンロードを行うことができます。
SpringのResourceインタフェースを利用すると非常に簡単にアクセスすることができる一方で、Auzre JDKでサポートされている機能をフルに利用できないというデメリットもあります。そのため、Auzre JDKが提供している機能をフルに活用したい場合は、BlobServiceClientBuilderをDIコンテナから取得する方法を利用すると良いと思います。
@Autowired
BlobServiceClientBuilder blobServiceClientBuilder;
@Test
void uploadAndDownloadWithClientOnDIContainer() {
// Build client
BlobClient blobClient = blobServiceClientBuilder.buildClient()
.getBlobContainerClient("test-container")
.getBlobClient("data/uploadAndDownloadWithClientOnDIContainer.txt");
// Upload
String content = "uploadAndDownloadWithClientOnDIContainer";
{
BinaryData uploadData = BinaryData.fromString(content);
blobClient.uploadWithResponse(
new BlobParallelUploadOptions(uploadData).setComputeMd5(true), Duration.ofSeconds(10), Context.NONE);
}
// Download
{
BlobDownloadContentResponse downloadResponse = blobClient.downloadContentWithResponse(
null, null, Duration.ofSeconds(10), Context.NONE);
String contentMd5 = encoder.encodeToString(DigestUtils.md5Digest(downloadResponse.getValue().toBytes()));
String headerMd5 = encoder.encodeToString(downloadResponse.getDeserializedHeaders().getContentMd5());
Assertions.assertThat(contentMd5).isEqualTo(headerMd5);
Assertions.assertThat(downloadResponse.getValue().toString()).isEqualTo(content);
}
}
MD5ハッシュ値を利用したアップロードとダウンロードの検証については、Azure SDK側でどこまで行ってくれるのかちゃんとわかってないです・・・・。
BlobParallelUploadOptionsのsetComputeMd5メソッドのJavaDocには「Whether or not the library should calculate the md5 and send it for the service to verify.」と記載があるので、setComputeMd5(true)を指定することで、アップロード時にサーバ側でアップロードしたファイルの検証してくれるのかな〜と思っていますが・・・実際のところよくわかってないです。
ダウンロード時の検証については、おそらくAzure SDKの中で自動で検証してくれる機能はないのかな〜と思っており、Azure SDKのAPI経由でサーバで管理しているコンテンツのMD5ハッシュ値を取得して、実際にダウンロードしたファイルとの検証を自前で行う必要があるのかな〜と思っています(こちらもよくわかってない・・・)。
Azure JDKのAPIだけを利用
Azure JDKのAPIのみを利用してアップロード及びダウンロードを行うことも当然できます。
@Test
void uploadAndDownloadWithClient() {
String accountName = "kazuki43zoostorage";
String accountKey = System.getenv("AZURE_STORAGE_ACCOUNT_KEY"); // アカウントキーは環境変数から取得
// Build client
BlobClient blobClient = new BlobServiceClientBuilder()
.endpoint("https://" + accountName + ".blob.core.windows.net")
.credential(new StorageSharedKeyCredential(accountName, accountKey))
.buildClient()
.getBlobContainerClient("test-container")
.getBlobClient("data/uploadAndDownloadWithClient.txt");
// Upload
String content = "uploadAndDownloadWithClient";
{
BinaryData uploadData = BinaryData.fromString(content);
blobClient.uploadWithResponse(
new BlobParallelUploadOptions(uploadData).setComputeMd5(true), Duration.ofSeconds(10), Context.NONE);
}
// Download
{
BlobDownloadContentResponse downloadResponse = blobClient.downloadContentWithResponse(
null, null, Duration.ofSeconds(10), Context.NONE);
String contentMd5 = encoder.encodeToString(DigestUtils.md5Digest(downloadResponse.getValue().toBytes()));
String headerMd5 = encoder.encodeToString(downloadResponse.getDeserializedHeaders().getContentMd5());
Assertions.assertThat(contentMd5).isEqualTo(headerMd5);
Assertions.assertThat(downloadResponse.getValue().toString()).isEqualTo(content);
}
}
実行結果
こんな感じでアップロードされました。
検証アプリ
まとめ
MD5検証がライブラリ側(サーバ側)でどこまで対応しているのかがまだ不明な点はありますが、コンテンツのアップロードおよびダウンロードができることは確認できたので、いったん満足しています。MD5検証どこまでサポートされているか知っている方がいたら是非コメントください!!