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

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

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

設定の構成

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

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

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

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

    mvn -Plocal clean appengine:devserver
  2. ウェブブラウザで http://localhost:8080 に移動します。

これで、アプリのウェブページを閲覧し、書籍の追加、編集、削除を行えるようになります。

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

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

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

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

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

アプリのバージョンを削除する手順は次のとおりです。

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

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

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

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

アプリケーションの構造

次の図は、アプリケーションを構成するコンポーネントと、それらの接続関係を示しています。

Bookshelf アプリのデプロイ プロセスと構造

コードを理解する

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

Cloud Datastore の操作

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

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

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

書籍を作成する

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

@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
}

Cloud 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 メソッドは、Cloud 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 ではデフォルトでプロパティごとにインデックスが作成されますが、この動作を変更することもできます。クエリによってはインデックス内の複数のプロパティを使わないと実行できないものがあります。たとえば、上記のユーザー別クエリやタイトル順クエリがそれに該当します。そのようなクエリをサポートするには、手動でインデックスを作成するか、開発用サーバーを使用してインデックスを作成します。

このページは役立ちましたか?評価をお願いいたします。