Java on Azure 実践開発【Blob Upload ②: App Service ローカル保存後アップロード編】

## はじめに

本記事は、『Java on Azure 実践開発 Blob Upload』シリーズの第2回「App Service ローカル保存後アップロード」編です。
サンプルコードは、[kohei3110/JavaOnAzure-BlobStorage](https://github.com/kohei3110/JavaOnAzure-BlobStorage) に上がっています。

## シナリオ概説

本シリーズでは、Blob Storage へのファイルアップロードについて、Azure を使った Java アプリケーションのサンプルコードを使用しながら、開発方法をご紹介します。

一口にファイルアップロードといっても、あらゆる方式があるかと思います。例えば、以下のようなものがあります。

| No. | シナリオ |  概要 | 記事 URL |
| :--- | :--- | :--- | :--- |
| 1 | サーバー経由でのストリームライクなアップロード | SAS の流出を懸念する場合、サーバー経由でのストリームライクなアップロード | [Java on Azure 実践開発【Blob Upload ①: ストリームライクなアップロード編】](https://qiita.com/kk31108424/items/63ab4fdd0492e344573a) |
| 2 | サーバーに一時保存後アップロード | アプリケーションサーバーのローカルストレージにファイルを一度保存後、アップロード（クライアントからは同期に見える） | [Java on Azure 実践開発【Blob Upload ②: App Service ローカル保存後アップロード編】](https://qiita.com/kk31108424/items/366649945294a50b808a) |
| 3 | サーバーに一時保存後定期アップロード | アプリケーションサーバーのローカルストレージにファイルを一度保存後、**定期ジョブにて**アップロード（クライアントからは非同期に見える） | [Java on Azure 実践開発【Blob Upload ③: 定期アップロード編】](https://qiita.com/kk31108424/items/5182adf18695238fc1e1) |
| 4 | 署名付き URL を使ったアップロード | アプリケーションから返却された署名付き URL を用いて、クライアントからファイルをアップロードする | [Java on Azure 実践開発【Blob Upload ④: 署名付き URL を使ったアップロード編】](https://qiita.com/kk31108424/items/314027635b4518b2a6b2) |

本記事では、<b>『2. 一時保存後アップロード』</b>について実装上のポイントを解説していきます。

## 実装内容

アップロード対象のファイルを、アプリケーション実行環境（今回はApp Service）のローカルファイルストレージに保存後、Blob ストレージへアップロードします。想定されるシナリオは、クライアントから渡されたアップロード対象のファイルを、サーバー側で変換などの処理を行ったのち、アップロードする場合などです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248756/abe9941a-70f8-784a-fe4d-786b96bcc22a.png)

## アップロード方法

[`BlobAsyncClient#uploadFromFile()`メソッド](https://docs.microsoft.com/en-us/java/api/com.azure.storage.blob.blobasyncclient.uploadfromfile?view=azure-java-stable#com-azure-storage-blob-blobasyncclient-uploadfromfile(java-lang-string-boolean))を使用します。このメソッドにより、指定されたファイルにて、新しいブロック blob が作成されます。

なお、<b>既定では、`BlobAsyncClient#uploadFromFile()`メソッドは既存の blob を上書きしません。</b>既定のまま上書きしようとすると、`409 BlobAlreadyExists` エラーが返ってきます。

参考: 『[Blob service のエラーコード](https://docs.microsoft.com/ja-jp/rest/api/storageservices/blob-service-error-codes)』

既存の blob への上書きを有効化するには、overwrite オプションを `true` に指定する必要があります。今回のサンプルアプリケーションでも、上書きを有効化しています。

```java:UploadBlobRepository.java
・・・
        blobAsyncClient.uploadFromFile(destinationFile.toString(), true)  // 第二引数を true にすると、上書きが有効化される
・・・
```

## 実装に必要な SDK のクラス

実装にあたって、Azure SDK for Java を使用しました。SDK を使うため、私の方でいくつかクラスを作りました。以下は、その UML 図です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248756/99ff4d6f-8a1f-643c-a3f0-2eb452e3f9e5.png)

ここからは、実装する際に必要となる SDK のクラスについて解説していきます。

### BlobAsyncClient クラス
[①: ストリームライクなアップロード編]()でも使用した、`BlobAsyncClient` クラスです。（リンク入れる）★

`BlobAsyncClient` クラスは、Blob Storage の各オブジェクト（Blob）操作をするためのクライアントを提供します。`BlobAsyncClient` クラスにより、Blob アップロードやダウンロード、Blob のコピーなどの操作が可能になります。

`BlobAsyncClient` は、`BlobClientBuilder` でインスタンス化するか、`getBlobAsyncClient()`メソッドで取得することができます。

なお、Azure では以下３種類の Blob をサポートしています。今回は、ファイルアップロード用途なので、ブロック Blob を使用しました。
これらに対応するクライアントも、Azure SDK for Java で用意されています。

| Blob 種類 | 概要 | クライアント取得メソッド | Javadoc |
| :--- | :--- | :--- | :--- |
|ブロック BLOB | 大量のデータを効率的にアップロードするためのに最適。| [BlobAsyncClient.getBlockBlobAsyncClient Method](https://docs.microsoft.com/ja-jp/java/api/com.azure.storage.blob.blobasyncclient.getblockblobasyncclient?view=azure-java-stable)| [getBlockBlobAsyncClient()](https://javadoc.io/static/com.azure/azure-storage-blob/12.0.0-preview.4/com/azure/storage/blob/BlobAsyncClient.html#getBlockBlobAsyncClient--) |
| 追加 BLOB | 追加操作（仮想マシンのデータのログ記録などのシナリオ）に最適。| [BlobAsyncClient.getAppendBlobAsyncClient Method](https://docs.microsoft.com/ja-jp/java/api/com.azure.storage.blob.blobasyncclient.getappendblobasyncclient?view=azure-java-stable) | [getAppendBlobAsyncClient()](https://javadoc.io/static/com.azure/azure-storage-blob/12.0.0-preview.4/com/azure/storage/blob/BlobAsyncClient.html#getAppendBlobAsyncClient--) | 
| ページ BLOB | ランダムな読み取りと書き込みの操作用に最適。| [BlobAsyncClient.getPageBlobAsyncClient Method](https://docs.microsoft.com/ja-jp/java/api/com.azure.storage.blob.blobasyncclient.getpageblobasyncclient?view=azure-java-stable) | [getPageBlobAsyncClient()](https://javadoc.io/static/com.azure/azure-storage-blob/12.0.0-preview.4/com/azure/storage/blob/BlobAsyncClient.html#getPageBlobAsyncClient--) |

参考: 『[BlobAsyncClient Class](https://docs.microsoft.com/en-us/java/api/com.azure.storage.blob.blobasyncclient?view=azure-java-stable)』
JavaDoc: 『[Class BlobAsyncClient](https://azuresdkartifacts.blob.core.windows.net/azure-sdk-for-java/staging/apidocs/com/azure/storage/blob/BlobAsyncClient.html)』

```java:UploadBlobRepository.java
・・・
    private BlobAsyncClient buildBlobClient (String blobName) throws Exception {
        try {
            String connectionString = this.getConnectionStringRepository.getConnectionString();
            BlobAsyncClient blobAsyncClient = new BlobClientBuilder()
                .connectionString(connectionString)
                .containerName(CONTAINER_NAME)
                .blobName(blobName)
                .buildAsyncClient();
            
            return blobAsyncClient;
        } catch (Exception e) {
            logger.warning("Build blobAsyncClient has failed.");
            throw new Exception(e.toString());
        }
    }
・・・
```

## Tips

実装上の Tips をご紹介します。

### 既存 blob の上書き

上述しましたが、<b>既定では、`BlobAsyncClient#uploadFromFile()`メソッドは既存の blob を上書きしません。</b>既定のまま上書きしようとすると、`409 BlobAlreadyExists` エラーが返ってきます。

参考: 『[uploadFromFile(String filePath, boolean overwrite)](https://docs.microsoft.com/en-us/java/api/com.azure.storage.blob.blobasyncclient.uploadfromfile?view=azure-java-stable#com-azure-storage-blob-blobasyncclient-uploadfromfile(java-lang-string-boolean))』

## おわりに

本記事は、『Java on Azure 実践開発 Blob Upload 編】②』として、アプリケーション実行環境のローカルストレージに保存後、ファイルをアップロードする方法についてまとめました。

次回は、アプリケーションサーバーのローカルストレージにファイルを一度保存後、定期ジョブにてアップロードする方法についてまとめていきます！お楽しみに～。