Utiliser Cloud Datastore avec Java

Cette partie du tutoriel consacré à Bookshelf pour Java explique comment créer, lire, mettre à jour et supprimer des données structurées dans Cloud Datastore.

Ce tutoriel comporte plusieurs pages. Pour le suivre depuis le début et consulter les instructions relatives à la configuration, accédez à la page Application Bookshelf pour Java.

Configurer les paramètres

Le fichier pom.xml contient les informations de configuration pour toutes les parties du tutoriel consacré à Bookshelf. Pour cette partie, vous n'avez pas besoin d'ajouter d'informations de configuration. Il n'y a qu'une condition requise : définir la priorité bookshelf.storageType sur datastore, ce qui a déjà été fait.

Exécuter l'application sur votre machine locale

Pour exécuter l'application localement :

  1. Dans le répertoire getting-started-java/bookshelf/2-structured-data, saisissez la commande suivante pour démarrer un serveur Web local. Remplacez [YOUR_PROJECT_ID] par l'ID de votre projet GCP.

    mvn -Plocal clean jetty:run-exploded -DprojectID=[YOUR-PROJECT-ID]
  2. Dans votre navigateur Web, accédez à http://localhost:8080.

Vous pouvez à présent consulter les pages Web de l'application pour ajouter, modifier et supprimer des livres.

Déployer l'application dans l'environnement flexible App Engine

  1. Déployez l'application.

    mvn appengine:deploy -DprojectID=YOUR-PROJECT-ID
    
  2. Dans votre navigateur Web, saisissez l'adresse suivante. Remplacez [YOUR_PROJECT_ID] par votre ID de projet.

    https://[YOUR_PROJECT_ID].appspot-preview.com
    

Pour mettre à jour l'application, vous pouvez déployer la dernière version en saisissant la même commande que celle utilisée pour le premier déploiement. Le nouveau déploiement crée une nouvelle version de votre application, qui est alors définie comme version par défaut. Les anciennes versions de votre application sont conservées, tout comme les instances de VM associées. Toutes ces versions d'applications et instances de VM sont des ressources facturables.

Vous pouvez réduire les coûts en supprimant les versions autres que celles par défaut de votre application. Pour en savoir plus sur le nettoyage des ressources facturables, consultez la section Effectuer un nettoyage de la dernière étape de ce tutoriel.

Structure de l'application

Le schéma suivant montre les composants de l'application et décrit la façon dont ils sont interconnectés.

Structure et processus de déploiement de l'application Bookshelf

Comprendre le code

Cette section décrit le code de l'application et son fonctionnement.

Interagir avec Cloud Datastore

L'application utilise un objet de service Datastore autorisé pour interagir avec Cloud  Datastore. Cet objet a échangé des identifiants contre un jeton pour accéder aux API Cloud Datastore. L'application crée également un objet KeyFactory de type Book. Le livre est le seul type de données que cette application stocke. Cependant, vous pouvez en principe stocker autant de types de données que vous le souhaitez. Cloud Datastore est compatible avec un large éventail de types de données.

private Datastore datastore;
private KeyFactory keyFactory;

public DatastoreDao() {
  datastore = DatastoreOptions.getDefaultInstance().getService(); // Authorized Datastore service
  keyFactory = datastore.newKeyFactory().setKind("Book2");      // Is used for creating keys later
}

Créer des livres

Pour enregistrer un livre, l'application enregistre une entité dans Cloud Datastore. Une entité possède une clé et une collection de paires nom/valeur. La méthode createBook commence par une clé IncompleteKey, à laquelle est attribuée une valeur lorsque l'entité est ajoutée à Cloud Datastore. Le code crée l'entité conformément au modèle de conception du compilateur en effectuant des appels répétés à la méthode set.

@Override
public Long createBook(Book book) {
  IncompleteKey key = keyFactory.newKey();          // Key will be assigned once written
  FullEntity<IncompleteKey> incBookEntity = Entity.newBuilder(key)  // Create the Entity
      .set(Book.AUTHOR, book.getAuthor())           // Add Property ("author", book.getAuthor())
      .set(Book.DESCRIPTION, book.getDescription())
      .set(Book.PUBLISHED_DATE, book.getPublishedDate())
      .set(Book.TITLE, book.getTitle())
      .build();
  Entity bookEntity = datastore.add(incBookEntity); // Save the Entity
  return bookEntity.getKey().getId();                     // The ID of the Key
}

Lire à partir de Cloud Datastore

La méthode readBook convertit l'ID d'un livre en clé. Elle transmet ensuite la clé à la méthode get, qui renvoie un objet Entity.

@Override
public Book readBook(Long bookId) {
  Entity bookEntity = datastore.get(keyFactory.newKey(bookId)); // Load an Entity for Key(id)
  return entityToBook(bookEntity);
}

La méthode entityToBook convertit l'entité renvoyée par Cloud Datastore en objet Book à l'aide des méthodes get pour chaque type.

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

Mettre à jour les livres

La mise à jour de livres nécessite d'appeler la méthode update avec un élément Entity.

@Override
public void updateBook(Book book) {
  Key key = keyFactory.newKey(book.getId());  // From a book, create a Key
  Entity entity = Entity.newBuilder(key)         // Convert Book to an Entity
      .set(Book.AUTHOR, book.getAuthor())
      .set(Book.DESCRIPTION, book.getDescription())
      .set(Book.PUBLISHED_DATE, book.getPublishedDate())
      .set(Book.TITLE, book.getTitle())
      .build();
  datastore.update(entity);                   // Update the Entity
}

Supprimer des livres

La suppression avec Cloud Datastore nécessite d'appeler la méthode delete avec un élément Key.

@Override
public void deleteBook(Long bookId) {
  Key key = keyFactory.newKey(bookId);        // Create the Key
  datastore.delete(key);                      // Delete the Entity
}

Répertorier des livres

La méthode listBooks retourne une liste de livres, 10 à la fois, avec un élément Cursor sécurisé pour les URL :

@Override
public Result<Book> listBooks(String startCursorString) {
  Cursor startCursor = null;
  if (startCursorString != null && !startCursorString.equals("")) {
    startCursor = Cursor.fromUrlSafe(startCursorString);    // Where we left off
  }
  Query<Entity> query = Query.newEntityQueryBuilder()       // Build the Query
      .setKind("Book2")                                     // We only care about Books
      .setLimit(10)                                         // Only show 10 at a time
      .setStartCursor(startCursor)                          // Where we left off
      .setOrderBy(OrderBy.asc(Book.TITLE))                  // Use default Index "title"
      .build();
  QueryResults<Entity> resultList = datastore.run(query);   // Run the query
  List<Book> resultBooks = entitiesToBooks(resultList);     // Retrieve and convert Entities
  Cursor cursor = resultList.getCursorAfter();              // Where to start next time
  if (cursor != null && resultBooks.size() == 10) {         // Are we paging? Save Cursor
    String cursorString = cursor.toUrlSafe();               // Cursors are WebSafe
    return new Result<>(resultBooks, cursorString);
  } else {
    return new Result<>(resultBooks);
  }
}

Index

Cloud Datastore crée automatiquement un index pour chacune de vos propriétés, mais vous pouvez modifier ce comportement. Certaines requêtes nécessitent plus d'une propriété dans l'index pour s'exécuter. C'est le cas des requêtes Query by user et ordered by Title query ci-dessus. L'émulateur Cloud Datastore suggère les index dont votre application a besoin.

Pour créer ces index :

gcloud datastore indexes create index.yaml