Blobstore API for Java 8 の概要

注: blob データの保存には、Blobstore ではなく Google Cloud Storage の使用をご検討ください。

Blobstore API を使用すると、blob と呼ばれるデータ オブジェクトをアプリケーションで提供できるようになります。blob は、データストア サービスのオブジェクトに許可されているサイズよりはるかに大きいサイズのオブジェクトです。blob は、動画や画像などのサイズの大きいファイルを提供する場合や、ユーザーがサイズの大きいデータファイルをアップロードできるようにする場合に便利です。blob は HTTP リクエストでファイルをアップロードすることによって作成されます。通常アプリケーションでこの処理を行うには、ファイル アップロード用のフィールドを含むフォームをユーザーに提示します。フォームが送信されると、Blobstore によってファイルの内容から blob が作成され、blob への不透明な参照(blob キー)が返されます。このキーは後で blob を提供するときに使用できます。アプリケーションは、ユーザー リクエストに応じて完全な blob 値を提供でき、あるいはファイルに似たストリーミング インターフェースを使用して、値を直接読み取ることができます。

Blobstore を導入する

Google App Engine には Blobstore サービスが含まれています。このサービスを利用すると、アプリケーションでデータ オブジェクトを提供できます。制限は 1 回の HTTP 接続でアップロードまたはダウンロードできるデータ量のみです。これらのオブジェクトを Blobstore 値または blob と呼びます。 Blobstore 値はリクエスト ハンドラからのレスポンスとして提供され、ウェブフォームを通じたアップロード データとして作成されます。blob データは、アプリケーションで直接作成されるのではなく、送信されたウェブフォームや他の HTTP POST リクエストによって間接的に作成されます。Blobstore API を使用すると、Blobstore 値をユーザーに送信したり、ファイルに似たストリームでアプリケーションから Blobstore 値にアクセスしたりできます。

アプリケーションで Blobstore 値のアップロードをユーザーに促すには、ファイル アップロード用のフィールドを含むウェブフォームを提示します。アプリケーションは Blobstore API を呼び出し、フォームのアクション URL を生成します。ユーザーのブラウザは、生成された URL を通じてファイルを Blobstore に直接アップロードします。続いて、Blobstore は blob を保存し、blob キーが含まれるように書き換えたリクエストをアプリケーションで指定されているパスに渡します。そのパスにはアプリケーションのリクエスト ハンドラがあり、そこで追加のフォーム処理を行うことができます。

blob を提供するには、アプリケーションで送信レスポンスにヘッダーを設定します。このレスポンスは App Engine で blob 値に置き換えられます。

作成した blob は変更できませんが、削除することはできます。各 blob には対応する blob 情報レコードがあり、データストアに保存されています。blob 情報レコードを参照すると、作成日時やコンテンツ タイプなどの blob の詳細がわかります。blob キーを使用して blob 情報レコードをフェッチし、そのプロパティへのクエリができます。

アプリケーションでは API を呼び出して Blobstore 値を読み取れますが、一度に読み取れるサイズは制限されています。制限サイズは API の戻り値の最大サイズで 32 MB より少し小さい値であり、Java では定数 com.google.appengine.api.blobstore.BlobstoreService.MAX_BLOB_FETCH_SIZE で表されます。アプリケーションでは、ユーザーがファイルをアップロードした場合以外、Blobstore 値の作成も変更もできません。

Blobstore を使用する

Blobstore を使用すると、ユーザーからアップロードされるサイズの大きなファイルをアプリケーションで受け取ることや提供することができます。アップロードされたファイルは blob と呼ばれます。アプリケーションは blob に直接アクセスするのではなく、データストアの blob 情報エンティティBlobInfo クラスで表されます)を介して blob を使用します。

ユーザーは 1 つ以上のファイル入力フィールドを含む HTML フォームを送信して blob を作成します。アプリケーションは blobstoreService.createUploadUrl() をこのフォームの送信先(アクション)として設定し、この関数にアプリケーションのハンドラの URL パスを渡します。ユーザーがフォームを送信すると、ユーザーのブラウザが指定されたファイルを Blobstore に直接アップロードします。Blobstore は、アップロードされたファイルデータを 1 つ以上の対応する blob キーで置き換えることで、ユーザーのリクエストを書き換え、アップロードされたファイルデータを保存します。そして、書き換えたリクエストを、blobstoreService.createUploadUrl() に指定された URL パスにあるハンドラに渡します。このハンドラは、blob キーに基づいて追加の処理を行うことができます。

アプリケーションは、ファイルに似たストリーミング インターフェースを使用して、Blobstore 値の一部を読み取ることができます。詳細については、BlobstoreInputStream クラスをご覧ください。

blob をアップロードする

blob を作成してアップロードする手順は次のとおりです。

1. アップロード URL を作成します

blobstoreService.createUploadUrl を呼び出して、ユーザーが記入するフォームのアップロード URL を作成し、そのフォームの POST が完了したら読み込むようにアプリケーション パスを渡します。

<body>
    <form action="<%= blobstoreService.createUploadUrl("/upload") %>" method="post" enctype="multipart/form-data">
        <input type="file" name="myFile">
        <input type="submit" value="Submit">
    </form>
</body>

このコードは、アップロード フォームを JSP として作成した場合の例です。

2. アップロード フォームを作成する

フォームにはファイル アップロード用のフィールドを含め、フォームの enctypemultipart/form-data と設定する必要があります。ユーザーがフォームを送信すると、Blobstore API が POST を処理し、blob を作成します。この API は、blob の情報レコードを作成してデータストアに保存し、書き換えたリクエストをアプリケーションの blob キーとして指定されているパスに渡します。

3. アップロード ハンドラを実装する

このハンドラでは、blob キーとともにアプリケーションのデータモデルの残りの部分を保存できます。blob キー自体には、データストアの blob 情報エンティティから引き続きアクセスできます。ユーザーがフォームを送信し、ハンドラが呼び出された時点で、blob はすでに保存され、blob 情報がデータストアに追加されていることに注意してください。アプリケーションに blob を保持しない場合は、すぐに blob を削除して blob が孤立しないようにしてください。

次のコードの getUploads はアップロードされた一連の blob を返します。Map オブジェクトは、アップロード フィールドの名前をそのフィールドに含まれる blob に関連付けたリストです。

Map<String, List<BlobKey>> blobs = blobstoreService.getUploads(req);
List<BlobKey> blobKeys = blobs.get("myFile");

if (blobKeys == null || blobKeys.isEmpty()) {
    res.sendRedirect("/");
} else {
    res.sendRedirect("/serve?blob-key=" + blobKeys.get(0).getKeyString());
}

Blobstore がユーザーのリクエストを書き換えると、アップロードされたファイルの MIME 部分の本文が空になり、MIME 部分のヘッダーとして blob キーが追加されます。他のすべてのフォーム フィールドとパーツは保持され、アップロード ハンドラに渡されます。コンテンツ タイプを指定していない場合、Blobstore はファイル拡張子から推定を試みます。コンテンツ タイプが判断できない場合、新しく作成される blob にはコンテンツ タイプ application/octet-stream が割り当てられます。

blob を提供する

blob を提供するには、blob のダウンロード ハンドラをパスとしてアプリケーションに含める必要があります。このハンドラから該当の blob の blob キーを blobstoreService.serve(blobKey, res); に渡す必要があります。以下の例では、blob キーは URL 引数 (req.getParameter('blob-key')) としてダウンロード ハンドラに渡しています。実際には、ダウンロード ハンドラで blob キーを取得するために、他のメソッドやユーザーの操作など、お好みの方法を使用できます。

public void doGet(HttpServletRequest req, HttpServletResponse res)
    throws IOException {
        BlobKey blobKey = new BlobKey(req.getParameter("blob-key"));
        blobstoreService.serve(blobKey, res);

blob は任意のアプリケーション URL から提供できます。アプリケーションで blob を提供するには、blob キーを含むレスポンスに特別なヘッダーを配置します。App Engine はレスポンスの本文を blob のコンテンツに置き換えます。

blob バイトの範囲

Blobstore は、リクエストへのレスポンスとして、サイズの大きな値全体ではなく値の一部の提供をサポートしています。値の一部を提供するには、送信レスポンスに X-AppEngine-BlobRange ヘッダーを含めます。その値は標準的な HTTP バイト範囲とします。バイト番号は 0 から始まります。X-AppEngine-BlobRange を空にすると、API は範囲ヘッダーを無視して blob 全体を提供します。範囲の例を以下に示します。

  • 0-499: 値の最初の 500 バイト(0~499 バイト目まで)を提供します。
  • 500-999: 501 バイト目から始まる 500 バイトを提供します。
  • 500-: 501 バイト目から値の最後までのすべてのバイトを提供します。
  • -500: 値の最後の 500 バイトを提供します。

Blobstore 値に対して有効なバイト範囲が指定されている場合、Blobstore は 206 Partial Content ステータス コードとリクエストされたバイト範囲をクライアントに送信します。範囲が有効でなければ、Blobstore は 416 Requested Range Not Satisfiable を送信します。

Blobstore では、重複の有無にかかわらず 1 回のリクエストでの複数のバイト範囲(100-199,200-299 など)の指定をサポートしていません。

サンプル アプリケーションを完成させる

以下のサンプル アプリケーションでは、アプリケーションのメイン URL でユーザーにファイルのアップロードを求めるフォームを読み込みます。アップロード ハンドラはすぐにダウンロード ハンドラを呼び出し、データを提供します。これは、サンプル アプリケーションを簡略化するためのものです。実際にはアップロード データのリクエストにメイン URL を使用したり、アップロードされた blob をすぐに提供したりしなくてもかまいません。

// file Upload.java

import java.io.IOException;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;

public class Upload extends HttpServlet {
    private BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();

    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse res)
        throws ServletException, IOException {

        Map<String, List<BlobKey>> blobs = blobstoreService.getUploads(req);
        List<BlobKey> blobKeys = blobs.get("myFile");

        if (blobKeys == null || blobKeys.isEmpty()) {
            res.sendRedirect("/");
        } else {
            res.sendRedirect("/serve?blob-key=" + blobKeys.get(0).getKeyString());
        }
    }
}

// file Serve.java

import java.io.IOException;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;

public class Serve extends HttpServlet {
    private BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse res)
        throws IOException {
            BlobKey blobKey = new BlobKey(req.getParameter("blob-key"));
            blobstoreService.serve(blobKey, res);
        }
}

// file index.jsp

<%@ page import="com.google.appengine.api.blobstore.BlobstoreServiceFactory" %>
<%@ page import="com.google.appengine.api.blobstore.BlobstoreService" %>

<%
    BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
%>

<html>
    <head>
        <title>Upload Test</title>
    </head>
    <body>
        <form action="<%= blobstoreService.createUploadUrl("/upload") %>" method="post" enctype="multipart/form-data">
            <input type="text" name="foo">
            <input type="file" name="myFile">
            <input type="submit" value="Submit">
        </form>
    </body>
</html>

// web.xml

<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
   http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">

  <servlet>
    <servlet-name>Upload</servlet-name>
    <servlet-class>Upload</servlet-class>
  </servlet>

  <servlet>
    <servlet-name>Serve</servlet-name>
    <servlet-class>Serve</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>Upload</servlet-name>
    <url-pattern>/upload</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>Serve</servlet-name>
    <url-pattern>/serve</url-pattern>
  </servlet-mapping>

</web-app>

Blobstore で Images サービスを使用する

Images サービスでは、変換のソースとして Blobstore 値を使用できます。Blobstore 値の最大サイズと同サイズのソース画像を使用できます。Images サービスで変換後の画像がアプリケーションに返されるので、そのサイズは 32 MB より小さくなければなりません。これは、ユーザーがアップロードしたサイズの大きな写真のサムネイル画像を作成する場合に便利です。

Images サービスで Blobstore 値を使用する方法については、Images サービスのドキュメントをご覧ください。

Google Cloud Storage で Blobstore API を使用する

Blobstore API を使用して Blobstore ではなく Cloud Storage に blob を保存できます。Google Cloud Storage のドキュメントの説明に従ってバケットを設定して、そのバケットとファイル名を BlobstoreServicecreateUploadUrl で指定し、バケット名を UploadOptions パラメータで指定する必要があります。アップロード ハンドラでは、返された FileInfo メタデータを処理し、後で blob を取得するために必要な Google Cloud Storage ファイル名を明示的に保存する必要があります。

Blobstore API を使用して Cloud Storage オブジェクトを提供することもできます。

以下のコード スニペットにその方法を示しています。このサンプルは、リクエストのバケット名とオブジェクト名を取得するリクエスト ハンドラの一部です。Blobstore サービスを作成し、そのサービスを使用して Google Cloud Storage の blob キーを作成します。その際、指定されたバケットとオブジェクト名を使用します。

BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
BlobKey blobKey = blobstoreService.createGsBlobKey(
    "/gs/" + fileName.getBucketName() + "/" + fileName.getObjectName());
blobstoreService.serve(blobKey, resp);

割り当て量と制限

Blobstore 値に使用する領域は、保存データ(課金対象)の割り当て量の計算対象になります。データストアの blob 情報エンティティはデータストア関連の制限に対してカウントされます。Google Cloud Storage は従量課金サービスであり、Cloud Storage の価格表に従って課金されることに注意してください。

システム全体の安全上の割り当て量について詳しくは、割り当てをご覧ください。

Blobstore の使用については特に、システム全体の安全上の割り当て量に加えて次の制限が適用されます。

  • アプリケーションからの API 呼び出し 1 回で読み取ることのできる Blobstore データの最大サイズは 32 MB です。
  • 1 つのフォームの POST でアップロードできるファイルの最大数は 500 です。
このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...

Java 8 の App Engine スタンダード環境