App Engine スタンダード環境で Datastore を Java から使う

Java 用の Bookshelf のチュートリアルのこのパートでは、構造化データを Datastore 内に作成する方法を説明します。また、作成したデータの読み取り、更新、削除方法も説明します。

このページは複数ページからなるチュートリアルの一部です。最初からセットアップ手順を確認するには、Java Bookshelf アプリに移動してください。

設定の構成

この Bookshelf チュートリアルのすべてのパートの構成情報は、pom.xml ファイルに保持されます。チュートリアルのこのパートでは、構成情報を追加する必要はありません。唯一の要件は bookshelf.storageType プロパティの値を datastore に設定することで、これはすでに設定されています。

ローカルマシンでのアプリの実行

アプリをローカルで実行するには:

  1. getting-started-java/bookshelf-standard/2-structured-data ディレクトリで、次のコマンドを入力し、ローカル ウェブサーバーを起動します。

    mvn package appengine:run
  2. ウェブブラウザで http://localhost:8080 にアクセスします。

これでアプリのウェブページを開き、書籍の追加、編集、削除ができます。

App Engine スタンダード環境へのアプリのデプロイ

アプリを App Engine スタンダード環境にデプロイするには:

  1. Bookshelf アプリにアップロードされる Datastore インデックスを作成するには、少なくとも 1 つの書籍を作成して、[My Books] をクリックします。clean コマンドを使用してアプリをビルドすると、そのローカル インデックスが削除されます。したがって、デプロイするアプリのビルドでは必ずこの作業を行ってください。
  2. getting-started-java/bookshelf-standard/2-structured-data ディレクトリで、次のコマンドを入力してアプリをデプロイします。
    mvn appengine:deploy -Dappengine.appId=[YOUR-PROJECT-ID] -Dappengine.version=[YOUR-VERSION]
    [YOUR-PROJECT-ID] は実際のプロジェクト ID に、[YOUR-VERSION] は実際のバージョン(12 などの文字列値)に置き換えます。
  3. ウェブブラウザに次のアドレスを入力します。

    https://PROJECT_ID.REGION_ID.r.appspot.com

    以下を置き換えます。

アプリを更新した後は、アプリを最初にデプロイしたときと同じコマンドに、同じプロジェクト ID とバージョンを指定することで、更新されたバージョンを再デプロイできます。これにより、現在デプロイされているアプリが上書きされます。更新時のコマンドラインで別のバージョン文字列を指定すると、新しいデプロイによってアプリの新しいバージョンが作成され、それが現行の提供バージョンとして採用されます。

アプリの提供バージョン以外のバージョンを削除することで、コストを削減できます。

アプリのバージョンを削除するには:

  1. Cloud Console で、App Engine の [バージョン] ページに移動します。

    [バージョン] ページに移動

  2. デフォルト以外で削除するアプリのバージョンのチェックボックスをオンにします。
  3. [削除] をクリックして、アプリのバージョンを削除します。

課金対象のリソースをクリーンアップする方法の詳細については、このチュートリアルの最後のステップにあるクリーンアップ セクションをご覧ください。

アプリの構造

次の図は、アプリのコンポーネントとそれらの組み合わせ方法を示しています。

Bookshelf App のデプロイと構造

コードの説明

このセクションでは、アプリのコードとその動作を順を追って説明します。

Datastore を操作する

このアプリは承認済みの Datastore サービス オブジェクトを使用して Datastore を操作します。このオブジェクトは、Datastore API にアクセスするためのトークンの認証情報を交換します。アプリは、型が BookKeyFactory オブジェクトも作成します。書籍は、このアプリが格納する唯一のデータ型です。ただし、一般に、格納できるデータ型の数に制限はありません。Datastore は、幅広い種類のデータ型をサポートしています。

private DatastoreService datastore;
private static final String BOOK_KIND = "Book2";

public DatastoreDao() {
  datastore = DatastoreServiceFactory.getDatastoreService(); // Authorized Datastore service
}

書籍を作成する

このアプリでは、書籍を保存するために Datastore に 1 つのエンティティが格納されます。エンティティは 1 つのキーと 1 つのコレクション(名前と値のペアの集合)を持ちます。createBook メソッドは、BOOK 型の新しいエンティティを作成して、ユーザーが入力した著者名、説明、出版日、タイトルの値を設定します。キーは、エンティティが Datastore に追加されるときに割り当てられます。

@Override
public Long createBook(Book book) {
  Entity incBookEntity = new Entity(BOOK_KIND);  // Key will be assigned once written
  incBookEntity.setProperty(Book.AUTHOR, book.getAuthor());
  incBookEntity.setProperty(Book.DESCRIPTION, book.getDescription());
  incBookEntity.setProperty(Book.PUBLISHED_DATE, book.getPublishedDate());
  incBookEntity.setProperty(Book.TITLE, book.getTitle());

  Key bookKey = datastore.put(incBookEntity); // Save the Entity
  return bookKey.getId();                     // The ID of the Key
}

Datastore から読み出す

readBook メソッドは、書籍の ID を引数に取り、それをキーに変換します。続いてそのキーが getProperty メソッドに渡され、Entity オブジェクトが返されます。

@Override
public Book readBook(Long bookId) {
  try {
    Entity bookEntity = datastore.get(KeyFactory.createKey(BOOK_KIND, bookId));
    return entityToBook(bookEntity);
  } catch (EntityNotFoundException e) {
    return null;
  }
}

entityToBook メソッドは、Datastore から取得したエンティティを Book オブジェクトに変換します。この変換ではタイプごとに getProperty メソッドが使われます。これは、エンティティの作成時に setProperty が使われるのに似ています。プロパティ名は String 値です。

public Book entityToBook(Entity entity) {
  return new Book.Builder()                                     // Convert to Book form
      .author((String) entity.getProperty(Book.AUTHOR))
      .description((String) entity.getProperty(Book.DESCRIPTION))
      .id(entity.getKey().getId())
      .publishedDate((String) entity.getProperty(Book.PUBLISHED_DATE))
      .title((String) entity.getProperty(Book.TITLE))
      .build();
}

書籍を更新する

更新を行うには、Entity を指定して put メソッドを呼び出す必要があります。

@Override
public void updateBook(Book book) {
  Key key = KeyFactory.createKey(BOOK_KIND, book.getId());  // From a book, create a Key
  Entity entity = new Entity(key);         // Convert Book to an Entity
  entity.setProperty(Book.AUTHOR, book.getAuthor());
  entity.setProperty(Book.DESCRIPTION, book.getDescription());
  entity.setProperty(Book.PUBLISHED_DATE, book.getPublishedDate());
  entity.setProperty(Book.TITLE, book.getTitle());

  datastore.put(entity);                   // Update the Entity
}

書籍を削除する

Datastore で削除を行うには、Key を指定して delete メソッドを呼び出す必要があります。

@Override
public void deleteBook(Long bookId) {
  Key key = KeyFactory.createKey(BOOK_KIND, bookId);        // Create the Key
  datastore.delete(key);                      // Delete the Entity
}

書籍のリストを表示する

listBooks メソッドは、書籍のリスト(1 回に 10 冊分)を、URL セーフな Cursor とともに返します。

@Override
public Result<Book> listBooks(String startCursorString) {
  FetchOptions fetchOptions = FetchOptions.Builder.withLimit(10); // Only show 10 at a time
  if (startCursorString != null && !startCursorString.equals("")) {
    fetchOptions.startCursor(Cursor.fromWebSafeString(startCursorString)); // Where we left off
  }
  Query query = new Query(BOOK_KIND) // We only care about Books
      .addSort(Book.TITLE, SortDirection.ASCENDING); // Use default Index "title"
  PreparedQuery preparedQuery = datastore.prepare(query);
  QueryResultIterator<Entity> results = preparedQuery.asQueryResultIterator(fetchOptions);

  List<Book> resultBooks = entitiesToBooks(results);     // Retrieve and convert Entities
  Cursor cursor = results.getCursor();              // Where to start next time
  if (cursor != null && resultBooks.size() == 10) {         // Are we paging? Save Cursor
    String cursorString = cursor.toWebSafeString();               // Cursors are WebSafe
    return new Result<>(resultBooks, cursorString);
  } else {
    return new Result<>(resultBooks);
  }
}

索引

Datastore では、デフォルトでプロパティことにインデックスが作成されますが、この動作を変更することもできます。上記の Query by user クエリや ordered by Titleクエリなど、インデックス内の複数のプロパティを必要とするクエリもあります。そのようなクエリをサポートするには、手動でインデックスを作成するか、開発用サーバーを使用してインデックスを作成します。