Azure Storage

Azure Blob Storageのコンテナー内にファイルを格納するプログラムを作成してみた

以前、JavaでSpring Bootフレームワークを利用してファイルをアップロードするプログラムを作成したことがあったが、ファイルのアップロード先をAzure Blob Storageのコンテナー内に設定することもできる。

今回は、App Service上でAzure Blob Storageのコンテナー内にファイルをアップロードするプログラムを作成してみたので、共有する。

前提条件

下記記事のBlob Storageの作成が完了していること。

Azure Blob Storageを作成しファイルを格納してみたAzure Blob Storageを利用すると、Azure上にBlobデータ(テキストファイルや画像、アーカイブファイル等)を格納する...

また、下記記事の実装が完了していること。

Azure App Service上でSpring Bootを利用したJavaアプリケーションを作成してみた前回は、Azure Potal上でApp Serviceを作成してみたが、今回は、前回作成したApp ServiceにSpring Bo...

Azure Storageへのアクセスキー、Blobコンテナー名の確認

Azure Storageにアクセスするプログラム内では、アカウント名・アクセスキー・コンテナー名を設定する必要があるが、その設定内容はAzure Portal上で確認できる。その手順は、以下の通り。

1) Azure Portalにログイン後、作成したAzure Storageを表示し、「アクセスキー」メニューを押下後、「キーの表示」を押下する。
Storageの設定確認_1

2) 以下のように、アクセスキーが表示される。このうち「key1」の「キー」をアクセスキーとする。
Storageの設定確認_2

3) 「概要」メニューを表示した後で、「コンテナー」メニューを押下する。
Storageの設定確認_3

4) 以下のように、「blobcontainer」というコンテナーがあることが確認できる。
Storageの設定確認_4



作成したサンプルプログラム(App Service側)の内容

作成したサンプルプログラム(App Service側)の構成は以下の通り。なお、Azure Functions側のソースコードは修正していない。
サンプルプログラムの構成
なお、上記の赤枠は、前提条件のプログラムから追加・変更したプログラムである。

pom.xmlの内容は以下の通りで、Azure Storageにアクセスするための設定を追加している。

<?xml version="1.0" encoding="UTF-8"?>
 
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">  
  <modelVersion>4.0.0</modelVersion>  
  <parent> 
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-parent</artifactId>  
    <version>2.4.0</version>  
    <relativePath/>  
    <!-- lookup parent from repository --> 
  </parent>  
  <groupId>com.example</groupId>  
  <artifactId>demoAzureApp</artifactId>  
  <version>0.0.1-SNAPSHOT</version>  
  <packaging>war</packaging>  
  <name>demoAzureApp</name>  
  <description>Demo project for Spring Boot</description>  
  <properties> 
    <java.version>1.8</java.version> 
  </properties>  
  <dependencies> 
    <dependency> 
      <groupId>org.springframework.boot</groupId>  
      <artifactId>spring-boot-starter-thymeleaf</artifactId> 
    </dependency>  
    <dependency> 
      <groupId>org.springframework.boot</groupId>  
      <artifactId>spring-boot-starter-web</artifactId> 
    </dependency>
    <!-- lombokの設定 -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <scope>provided</scope>
    </dependency>
    <!-- Azure Storageの設定 -->
    <dependency>
      <groupId>com.microsoft.azure</groupId>
      <artifactId>azure-storage</artifactId>
      <version>8.3.0</version>
    </dependency>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.4</version>
    </dependency>
    <dependency> 
      <groupId>org.springframework.boot</groupId>  
      <artifactId>spring-boot-starter-tomcat</artifactId>  
      <scope>provided</scope> 
    </dependency>  
    <dependency> 
      <groupId>org.springframework.boot</groupId>  
      <artifactId>spring-boot-starter-test</artifactId>  
      <scope>test</scope> 
    </dependency> 
  </dependencies>  
  <build> 
    <plugins> 
      <plugin> 
        <groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-maven-plugin</artifactId> 
      </plugin>  
      <plugin>
        <groupId>com.microsoft.azure</groupId>
        <artifactId>azure-webapp-maven-plugin</artifactId>
        <version>1.12.0</version>
        <configuration>
          <schemaVersion>v2</schemaVersion>
          <subscriptionId>(ログインユーザーのサブスクリプションID)</subscriptionId>
          <resourceGroup>azureAppDemo</resourceGroup>
          <appName>azureAppDemoService</appName>
          <pricingTier>B1</pricingTier>
          <region>japaneast</region>
          <appServicePlanName>ASP-azureAppDemo-8679</appServicePlanName>
          <appServicePlanResourceGroup>azureAppDemo</appServicePlanResourceGroup>
          <runtime>
            <os>Linux</os>
            <javaVersion>Java 8</javaVersion>
            <webContainer>Tomcat 8.5</webContainer>
          </runtime>
          <deployment>
            <resources>
              <resource>
                <directory>${project.basedir}/target</directory>
                <includes>
                  <include>*.war</include>
                </includes>
              </resource>
            </resources>
          </deployment>
        </configuration>
      </plugin>
    </plugins> 
  </build> 
</project>

application.propertiesの内容は以下の通りで、Azure Storageにアクセスするためのアカウント名・アクセスキー・コンテナー名を追加している。
application_properties

コントローラクラスの内容は以下の通りで、アップロードボタンが押下されたときに、Blobコンテナーにアップロードしたファイルを格納する処理を追加している。

package com.example.demo;

import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.thymeleaf.util.StringUtils;

import com.microsoft.azure.storage.CloudStorageAccount;
import com.microsoft.azure.storage.blob.BlobOutputStream;
import com.microsoft.azure.storage.blob.CloudBlobClient;
import com.microsoft.azure.storage.blob.CloudBlobContainer;
import com.microsoft.azure.storage.blob.CloudBlockBlob;

@Controller
public class DemoController {

    /** Azure Storageのアカウント名 */
    @Value("${azure.storage.accountName}")
    private String storageAccountName;

    /** Azure Storageへのアクセスキー */
    @Value("${azure.storage.accessKey}")
    private String storageAccessKey;

    /** Azure StorageのBlobコンテナー名 */
    @Value("${azure.storage.containerName}")
    private String storageContainerName;

    /**
     * メイン画面を初期表示する.
     * @param model Modelオブジェクト
     * @return メイン画面
     */
    @GetMapping("/")
    public String index(Model model) {
        model.addAttribute("message"
            , "アップロードするファイルを指定し、アップロードボタンを押下してください。");
        return "main";
    }

    /**
     * ファイルデータをAzure Blob Storageに登録する.
     * @param uploadFile アップロードファイル
     * @param model      Modelオブジェクト
     * @return メイン画面
     */
    @PostMapping("/upload")
    public String add(@RequestParam("upload_file") MultipartFile uploadFile
            , Model model) {
        // ファイルが未指定の場合はエラーとする
        if (uploadFile == null 
            || StringUtils.isEmptyOrWhitespace(uploadFile.getOriginalFilename())) {
            model.addAttribute("errMessage", "ファイルを指定してください。");
            return "main";
        }

        // ファイルアップロード処理
        try {
            // Blobストレージへの接続文字列
            String storageConnectionString = "DefaultEndpointsProtocol=https;" 
                    + "AccountName=" + storageAccountName + ";" 
                    + "AccountKey=" + storageAccessKey + ";";

            // ストレージアカウントオブジェクトを取得
            CloudStorageAccount storageAccount 
                = CloudStorageAccount.parse(storageConnectionString);

            // Blobクライアントオブジェクトを取得
            CloudBlobClient blobClient = storageAccount.createCloudBlobClient();

            // Blob内のコンテナーを取得
            CloudBlobContainer container 
                = blobClient.getContainerReference(storageContainerName);

            // Blob内のコンテナーにデータを書き込む
            CloudBlockBlob blob 
                = container.getBlockBlobReference(uploadFile.getOriginalFilename());
            BlobOutputStream output = blob.openOutputStream();
            output.write(IOUtils.toByteArray(uploadFile.getInputStream()));
            output.close();

        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }

        // メイン画面へ遷移
        model.addAttribute("message", "ファイルアップロードが完了しました。");
        return "main";
    }
}

メイン画面のHTMLファイルの内容は以下の通りで、ファイルのアップロードを行う画面となっている。

<!DOCTYPE html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>メイン画面</title>
</head>
<body>
    <form method="post" enctype="multipart/form-data" th:action="@{/upload}">
    	<th:block th:if="!${#strings.isEmpty(message)}">
    		<span th:text="${message}">メッセージ</span><br/><br/>
    	</th:block>
        <th:block th:if="!${#strings.isEmpty(errMessage)}">
    		<font color="#FF0000">
                    <span th:text="${errMessage}">エラーメッセージ</span>
                </font><br/><br/>
    	</th:block>
    	ファイル : <input type="file" name="upload_file" /><br/><br/>
    	<input type="submit" value="アップロード" />
    </form>
</body>
</html>

その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/azure/tree/master/azure-blob-storage-upload/demoAzureApp



作成したサンプルプログラムの実行結果

サンプルプログラムをAzure App Serviceにデプロイして実行した結果は、以下の通り。

1) サンプルプログラム実行前のBlobコンテナーの内容は以下の通りで、ファイルがアップロードされていないことが確認できる。
サンプルプログラムの実行結果_1

2) Azure App ServiceのURL「https://azureappdemoservice.azurewebsites.net/」とアクセスし、「ファイルの選択」ボタンが押下する。
サンプルプログラムの実行結果_2_1

なお、上記URLは、下記Azure App ServiceのURLから確認できる。
サンプルプログラムの実行結果_2_2

3) アップロードファイルを選択し、「開く」ボタンを押下する。
サンプルプログラムの実行結果_3

4) 指定したファイルが選択された状態になっていることを確認後、「アップロード」ボタンを押下する。
サンプルプログラムの実行結果_4

5) アップロードが完了し、完了メッセージが表示されることが確認できる。
サンプルプログラムの実行結果_5

6) サンプルプログラム実行後、以下のように、アップロードしたファイルが配置されていることが確認できる。
サンプルプログラムの実行結果_6

要点まとめ

  • JavaでSpring Bootフレームワークを利用してファイルをアップロードするプログラムのファイルアップロード先は、Azure Blob Storageのコンテナー内に設定することができる。