はじめに
Azure Storage Blobに対してJavaプログラムからアクセスする方法についてちょっと調査をしていたら色々とハマったので、備忘録として記します。
Azure SDK for Java
Azure SDK for Javaのドキュメントは以下にあります。
Azure Storage Blobに対するJavaプログラムからのアクセスについては以下にサンプルがあります。
Azure SDK for Javaにはv8系とv12系の二つがあるようです。Javaのバージョンとはあまり関係がない?みたいで、今はv12系を使うようです。
ここに書いてあることで多くのことを満たせるかなと思います。以下では実際に調査をしてハマったことを記します。
BOMを使う
Azure SDK for Javaではさまざまなライブラリが提供されているのですが、それらの依存関係やバージョンを統一するためにBOMが提供されています。
Gradleでは5.2からBOMをサポートしているようです。
build.gradle
上で以下のように書けばOKです。
dependencies { implementation platform('com.azure:azure-sdk-bom:1.2.0') implementation 'com.azure:azure-storage-blob' }
BOMを使うとv12系が利用されるようでした。
ログを出力する
実行した際、以下のメッセージが出力されることがあります。
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
これはLogbackなどのロギングライブラリを導入しておけば出力されません。Logbackを使う場合、Gradleに以下の記述をします。
dependencies { implementation platform('com.azure:azure-sdk-bom:1.2.0') implementation 'com.azure:azure-storage-blob' implementation 'ch.qos.logback:logback-classic:1.2.11' // ← 追加 }
Logbackの設定をsrc/main/resources/logback.xml
に書きます。内容は以下のような感じ。
<configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern> %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n </pattern> </encoder> </appender> <root level="info"> <appender-ref ref="STDOUT" /> </root> </configuration>
このようにすることで、以下のようなログが出力されました。
2022-03-27 15:38:38.603 [main] INFO c.a.c.i.jackson.JacksonVersion - Package versions: jackson-annotations=2.13.1, jackson-core=2.13.1, jackson-databind=2.13.1, jackson-dataformat-xml=2.13.1, jackson-datatype-jsr310=2.13.1, azure-core=1.26.0, Troubleshooting version conflicts: https://aka.ms/azsdk/java/dependency/troubleshoot
詳細は以下にも書かれています。
JavaDoc
細かいメソッドなどを調べるためにJavaDocは欠かせません。以下のページにてAzure SDK for Javaとして提供しているサービスごとのJavaDocのリンクがまとまっています。
Azure Storage Blobは以下のページから辿れるJavaDocを参照すると良いかと思います。
CONTENT-TYPEなどを設定する
上記のサンプルをもとに実行するとCONTENT-TYPE
がapplication/octet-stream
になっていました。
これを修正するためには色々とコードを書く必要があります。
blobClient
の型をBlobClient
からBlockBlobClient
にします。
BlockBlobClient blobClient = blobContainerClient.getBlobClient(blobName).getBlockBlobClient();
CONTENT-TYPE
を設定するにはBlobHttpHeaders
のインスタンスを作成します。
BlobHttpHeaders blobHttpHeaders = new BlobHttpHeaders().setContentDisposition("attachment").setContentType("text/plain");
あとはBlockBlobClient
のuploadWithResponse
メソッドを使ってアップロードします。
以下のような実装になりました(package文やimport文は省略)。
public class BlobHelper { private BlobServiceClient blobServiceClient; private BlobContainerClient blobContainerClient; public BlobHelper() { } public void createBlobServiceClient(String connectionString) { // blobに接続するためのクライアントを作成する this.blobServiceClient = new BlobServiceClientBuilder() .connectionString(connectionString) .buildClient(); } public void createBlobContainerClient(String containerName) { // コンテナーにアクセスするクライアントを作成する this.blobContainerClient = this.blobServiceClient .getBlobContainerClient(containerName); if (!this.blobContainerClient.exists()) { this.blobContainerClient.create(); } } void createBlobWithData(String blobName, String blobContents) throws NoSuchAlgorithmException { // Blobを作成する BlockBlobClient blobClient = blobContainerClient.getBlobClient(blobName).getBlockBlobClient(); // メタデータの設定 Map<String, String> blobMetadata = Collections.singletonMap("myblobmetadata", "sample"); // 各種ヘッダーの設定 BlobHttpHeaders blobHttpHeaders = new BlobHttpHeaders().setContentDisposition("attachment") .setContentType("text/plain"); byte[] md5 = MessageDigest.getInstance("MD5").digest(blobContents.getBytes(StandardCharsets.UTF_8)); InputStream dataStream = new ByteArrayInputStream(blobContents.getBytes(StandardCharsets.UTF_8)); blobClient.uploadWithResponse(dataStream, blobContents.length(), blobHttpHeaders, blobMetadata, null, md5, null, null, null); } }
以下のような結果となりました。無事、CONTENT-TYPE
がtext/plain
になっています。他にも各種メタデータも設定されています。
ソース
この時点のソースは以下です。