Usa Datastore con Java para el entorno estándar de App Engine

Esta parte del instructivo de Bookshelf para Java muestra cómo crear, leer, actualizar y borrar datos estructurados en Datastore.

Esta página forma parte de un instructivo de varias páginas. Para comenzar desde el principio y revisar las instrucciones de configuración, ve a la app de Bookshelf en Java.

Configuración

El archivo pom.xml contiene información de configuración para todas las partes del instructivo de Bookshelf. Para esta parte del instructivo, no es necesario que agregues información de configuración. El único requisito es que la propiedad bookshelf.storageType esté establecida en datastore, lo cual ya está hecho por ti.

Ejecuta la app en tu máquina local

Para ejecutar la app de manera local:

  1. En el directorio getting-started-java/bookshelf-standard/2-structured-data, ingresa el siguiente comando para iniciar un servidor web local:

    mvn package appengine:run
  2. En tu navegador web, ve a http://localhost:8080.

Ahora puedes navegar por las páginas web de la app y agregar, editar y borrar libros.

Implementa la app en el entorno estándar de App Engine

Para implementar en el entorno estándar de App Engine, haz lo siguiente:

  1. Para crear un índice del almacén de datos que se cargue en la aplicación Bookshelf, cree al menos un libro y, luego, haz clic en Mis libros. Ten en cuenta que compilar la aplicación con el comando clean borra ese índice local, así que haz esto en la compilación de la aplicación que vas a implementar.
  2. En el directorio getting-started-java/bookshelf-standard/2-structured-data, ingresa el siguiente comando para implementar la aplicación:
    mvn appengine:deploy -Dappengine.appId=[YOUR-PROJECT-ID] -Dappengine.version=[YOUR-VERSION]
    Reemplaza [YOUR-PROJECT-ID] por el ID del proyecto, y [YOUR-VERSION] por la versión, como 1, 2 o algún otro valor string que desees usar.
  3. En el navegador web, ingresa la siguiente URL:

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

    Reemplaza lo siguiente:

Una vez que actualices la app, puedes volver a implementar la versión actualizada mediante el mismo comando que usaste cuando la implementaste por primera vez. Para ello, especifica el mismo ID del proyecto y la misma versión. Esto sobrescribe la aplicación implementada en la actualidad. Si especificas una cadena de versión diferente en la línea de comando actualizada, la nueva implementación crea una nueva versión de la aplicación y la promueve para que sea la versión de servicio actual.

Borra las versiones de la app que no estén en uso para reducir costos.

Para borrar la versión de una aplicación, haz lo siguiente:

  1. En Cloud Console, ve a la página Versiones de App Engine.

    Ir a la página Versiones

  2. Selecciona la casilla de verificación de la versión no predeterminada de la app que deseas borrar.
  3. Haz clic en Borrar para borrar la versión de la app.

Para obtener toda la información acerca de la limpieza de los recursos facturables, consulta la sección Limpieza del paso final de este instructivo.

Estructura de la app

En el siguiente diagrama, se muestran los componentes de la app y la manera en que se conectan entre sí.

Proceso y estructura de la implementación de la app de Bookshelf

Comprende el código

En esta sección, se explica el código de la app y su funcionamiento.

Interactúa con Datastore

La app usa un objeto de servicio autorizado Datastore para interactuar con Datastore. Este objeto intercambia credenciales por un token para acceder a las API del almacén de datos. La aplicación también crea un objeto KeyFactory de tipo Book. El libro es el único tipo de datos que almacena esta app. Sin embargo, por lo general, puedes almacenar todos los tipos de datos que quieras. El almacén de datos admite una amplia variedad de tipos de datos.

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

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

Crea libros

Para guardar un libro, la app almacena una entidad en Datastore. Una entidad tiene una clave y una colección de pares nombre-valor. El método createBook crea una nueva entidad de tipo BOOK y configura valores que proporciona el usuario para el autor, la descripción, la fecha de publicación y el título. La clave se asigna a la entidad cuando esta se agrega a 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
}

Lee desde Datastore

El método readBooktoma el ID de un libro y lo convierte en una clave. Luego, pasa la clave al método getProperty, que devuelve un objeto 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;
  }
}

El método entityToBook convierte la entidad otra vez desde Datastore a un objeto Book mediante los métodos getProperty para cada tipo, de forma similar a la forma en que se usa setProperty durante la creación de la entidad. Los nombres de propiedad son valores 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();
}

Actualiza libros

La actualización requiere llamar al método put con un Entity.

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

Borra libros

Borrar con Datastore requiere llamar al método delete con un Key.

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

Muestra una lista de libros

El método listBooks muestra una lista de libros, 10 a la vez, junto con una URL segura 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);
  }
}

Index

Datastore crea un índice para cada una de sus propiedades de forma predeterminada, aunque puede cambiar este comportamiento. Algunas consultas necesitan más de una sola propiedad en el índice para completarse, como las consultas Query by user y ordered by Title antes mencionadas. Puedes crear índices y así admitir esas consultas de forma manual o usar el servidor de desarrollo para crear índices.