Aplicación Spring Boot con Cloud Datastore

1. Descripción general

Google Cloud Datastore es una base de datos de documentos NoSQL creada para proporcionar ajuste de escala automático, alto rendimiento y facilidad de desarrollo de aplicaciones.

Qué aprenderás

  • Cómo usar Cloud Datastore para guardar y recuperar objetos Java en Spring Boot

Requisitos

  • Un proyecto de Google Cloud Platform
  • Un navegador, como Chrome o Firefox

¿Cómo usarás este instructivo?

Ler Leer y completar los ejercicios

¿Cómo calificarías tu experiencia con el uso de los servicios de Google Cloud Platform?

Principiante Intermedio Avanzado

2. Configuración y requisitos

Configuración del entorno de autoaprendizaje

  1. Accede a Google Cloud Console y crea un proyecto nuevo o reutiliza uno existente. Si aún no tienes una cuenta de Gmail o de Google Workspace, debes crear una.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • El Nombre del proyecto es el nombre visible de los participantes de este proyecto. Es una cadena de caracteres que no se utiliza en las APIs de Google. Puedes actualizarla cuando quieras.
  • El ID del proyecto es único en todos los proyectos de Google Cloud y es inmutable (no se puede cambiar después de configurarlo). La consola de Cloud genera automáticamente una cadena única. Por lo general, no importa cuál sea. En la mayoría de los codelabs, deberás hacer referencia al ID de tu proyecto (suele identificarse como PROJECT_ID). Si no te gusta el ID que se generó, podrías generar otro aleatorio. También puedes probar uno propio y ver si está disponible. No se puede cambiar después de este paso y se usa el mismo durante todo el proyecto.
  • Recuerda que hay un tercer valor, un número de proyecto, que usan algunas APIs. Obtén más información sobre estos tres valores en la documentación.
  1. A continuación, deberás habilitar la facturación en la consola de Cloud para usar las APIs o los recursos de Cloud. Ejecutar este codelab no costará mucho, tal vez nada. Para cerrar recursos y evitar que se generen cobros más allá de este instructivo, puedes borrar los recursos que creaste o borrar el proyecto. Los usuarios nuevos de Google Cloud son aptos para participar en el programa Prueba gratuita de $300.

Activar Cloud Shell

  1. En la consola de Cloud, haz clic en Activar Cloud Shell853e55310c205094.png.

55efc1aaa7a4d3ad.png

Si es la primera vez que inicias Cloud Shell, aparecerá una pantalla intermedia en la que se describirá qué es. Si apareció una pantalla intermedia, haz clic en Continuar.

9c92662c6a846a5c.png

El aprovisionamiento y la conexión a Cloud Shell solo tomará unos minutos.

9f0e51b578fecce5.png

Esta máquina virtual está cargada con todas las herramientas de desarrollo necesarias. Ofrece un directorio principal persistente de 5 GB y se ejecuta en Google Cloud, lo que permite mejorar considerablemente el rendimiento de la red y la autenticación. Gran parte de tu trabajo en este codelab, si no todo, se puede hacer con un navegador.

Una vez que te conectes a Cloud Shell, deberías ver que te autenticaste y que el proyecto se configuró con tu ID del proyecto.

  1. En Cloud Shell, ejecuta el siguiente comando para confirmar que tienes la autenticación:
gcloud auth list

Resultado del comando

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. En Cloud Shell, ejecuta el siguiente comando para confirmar que el comando gcloud conoce tu proyecto:
gcloud config list project

Resultado del comando

[core]
project = <PROJECT_ID>

De lo contrario, puedes configurarlo con el siguiente comando:

gcloud config set project <PROJECT_ID>

Resultado del comando

Updated property [core/project].

3. Inicializar Cloud Datastore

En GCP Console, navega a Menú -> Datastore (en la sección Storage) o haz clic aquí.

Si nunca usaste Datastore en el proyecto actual, verás la pantalla "Selecciona un modo de Cloud Firestore". Selecciona la opción "Modo Datastore".

f938295c7ff297f4.png

Luego, verás la pantalla "Elige dónde almacenar tus datos". Selecciona us-east1 o cualquier otra ubicación regional y haz clic en "Crear base de datos":

916ac84fec10fae7.png

4. Cómo iniciar una nueva aplicación de Spring Boot Java

Desde el entorno de Cloud Shell, usa el siguiente comando para inicializar y arrancar una nueva aplicación de Spring Boot:

$ curl https://start.spring.io/starter.tgz \
  -d packaging=war \
  -d dependencies=cloud-gcp \
  -d type=maven-project \
  -d baseDir=datastore-example \
  -d bootVersion=3.0.5 | tar -xzvf -

Esto creará un nuevo directorio datastore-example/ con un nuevo proyecto de Maven, junto con pom.xml de Maven, un wrapper de Maven y un punto de entrada de la aplicación.

Nuestra aplicación proporcionará una CLI para que los usuarios ingresen comandos y vean los resultados. Crearemos una clase para representar un libro y, luego, la guardaremos en Cloud Datastore con Datastore Repository.

También debemos agregar una dependencia más necesaria a pom.xml.

Haz clic en Abrir editor en el menú de Cloud Shell para abrir el editor de código web.

6d823258c76a7452.png

Después de que se cargue el editor, modifica el archivo pom.xml para agregar las dependencias de Google Cloud Datastore Starter y Spring Shell Starter:

pom.xml

<project>
  ...
  <dependencies>
        ...
        <!-- Add GCP Datastore Starter -->
        <dependency>
                <groupId>com.google.cloud</groupId>
                <artifactId>spring-cloud-gcp-starter-data-datastore</artifactId>
        </dependency>

        <!-- Add Spring Shell Starter -->
        <dependency>
                <groupId>org.springframework.shell</groupId>
                <artifactId>spring-shell-starter</artifactId>
                <version>3.0.2</version>
        </dependency>

  </dependencies>
</project>

5. Crea la clase Book

Con el editor, crea la clase Book con el siguiente contenido:

datastore-example/src/main/java/com/example/demo/Book.java

package com.example.demo;

import com.google.cloud.spring.data.datastore.core.mapping.Entity;
import org.springframework.data.annotation.Id;

@Entity(name = "books")
public class Book {
  @Id
  Long id;

  String title;

  String author;

  int year;

  public Book(String title, String author, int year) {
    this.title = title;
    this.author = author;
    this.year = year;
  }

  public long getId() {
    return this.id;
  }

  @Override
  public String toString() {
    return "Book{" +
        "id=" + this.id +
        ", title='" + this.title + '\'' +
        ", author='" + this.author + '\'' +
        ", year=" + this.year +
        '}';
  }
}

Como puedes ver, este es un POJO simple. La clase se anota con @Entity para indicar que se puede almacenar en Datastore y proporcionar el nombre del tipo (piensa en un tipo como una tabla en las bases de datos SQL; consulta la documentación para obtener más detalles). El nombre del tipo es opcional. Si se omite, se generará en función del nombre de la clase.

Ten en cuenta que anotamos la propiedad id con @Id. Esto indica que queremos que este campo se use como la parte del identificador de la clave de Datastore. Cada entidad de Datastore necesita un identificador. Los tipos admitidos son String y Long.

Anulamos el método toString para que la representación de cadena de los objetos sea más legible, lo que será útil cuando los imprimamos.

6. Crea la interfaz BookRepository

Crea la clase BookRepository con el siguiente contenido:

datastore-example/src/main/java/com/example/demo/BookRepository.java

package com.example.demo;

import java.util.List;

import com.google.cloud.spring.data.datastore.repository.DatastoreRepository;


public interface BookRepository extends DatastoreRepository<Book, Long> {

  List<Book> findByAuthor(String author);

  List<Book> findByYearGreaterThan(int year);

  List<Book> findByAuthorAndYear(String author, int year);
}

La interfaz extiende DatastoreRepository<Book, Long>, donde Book es la clase de dominio y Long es el tipo Id. Declaramos tres métodos de consulta en nuestro repositorio para los que se generan implementaciones automáticamente en segundo plano.

El primero es findByAuthor. Como puedes suponer, la implementación de este método ejecutará una consulta que usará un valor proporcionado por el usuario en el filtro de condición para la igualdad del campo de autor.

El método findByYearGreaterThan ejecuta una consulta que filtra el campo del año para que sea mayor que el valor proporcionado por el usuario.

findByAuthorAndYear ejecuta una búsqueda de entidades en la que los campos de autor y año coinciden con los valores proporcionados por el usuario.

7. Crea la aplicación interactiva de la CLI

Abre la clase DemoApplication de la aplicación principal y modifícala para que se vea de la siguiente manera:

datastore-example/src/main/java/com/example/demo/DemoApplication.java

package com.example.demo;

import java.util.List;

import com.google.common.collect.Lists;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.shell.standard.ShellComponent;
import org.springframework.shell.standard.ShellMethod;

@ShellComponent
@SpringBootApplication
public class DemoApplication {
  @Autowired
  BookRepository bookRepository;

  public static void main(String[] args) {
     SpringApplication.run(DemoApplication.class, args);
  }

  @ShellMethod("Saves a book to Cloud Datastore: save-book <title> <author> <year>")
  public String saveBook(String title, String author, int year) {
     Book savedBook = this.bookRepository.save(new Book(title, author, year));
     return savedBook.toString();
  }

  @ShellMethod("Loads all books")
  public String findAllBooks() {
     Iterable<Book> books = this.bookRepository.findAll();
     return Lists.newArrayList(books).toString();
  }

  @ShellMethod("Loads books by author: find-by-author <author>")
  public String findByAuthor(String author) {
     List<Book> books = this.bookRepository.findByAuthor(author);
     return books.toString();
  }

  @ShellMethod("Loads books published after a given year: find-by-year-after <year>")
  public String findByYearAfter(int year) {
     List<Book> books = this.bookRepository.findByYearGreaterThan(year);
     return books.toString();
  }

  @ShellMethod("Loads books by author and year: find-by-author-year <author> <year>")
  public String findByAuthorYear(String author, int year) {
     List<Book> books = this.bookRepository.findByAuthorAndYear(author, year);
     return books.toString();
  }

  @ShellMethod("Removes all books")
  public void removeAllBooks() {
     this.bookRepository.deleteAll();
  }
}

Observa cómo anotamos la clase con @ShellComponent. Esto le indica a Spring que queremos usar esta clase como fuente para los comandos de la CLI. Los métodos anotados con @ShellMethod se expondrán como comandos de CLI en nuestra aplicación.

Aquí usamos los métodos que declaramos en la interfaz BookRepository: findByAuthor, findByYearGreaterThan y findByAuthorAndYear. También usamos tres métodos integrados: save, findAll y deleteAll.

Veamos el método saveBook. Creamos un objeto Book con los valores proporcionados por el usuario para el título, el autor y el año. Como puedes ver, no proporcionamos un valor de id, por lo que se asignará automáticamente al campo id cuando se guarde. El método save acepta un objeto de tipo Book y lo guarda en Cloud Datastore. Devuelve un objeto Book con todos los campos completados, incluido el campo id. Al final, devolvemos una representación de cadena de este objeto.

El resto de los métodos funcionan de manera similar: aceptan parámetros pasados a los métodos de repositorio apropiados y devuelven resultados convertidos en cadenas.

8. Ejecuta la aplicación

Para compilar y comenzar la aplicación, primero asegúrate de que JAVA_HOME esté configurado en la versión correcta:

$ export JAVA_HOME=/usr/lib/jvm/java-1.17.0-openjdk-amd64

Ejecuta este comando en Cloud Shell (desde la raíz del proyecto datastore-example/ donde se encuentra el pom.xml):

$ ./mvnw spring-boot:run
export JAVA_HOME=/usr/lib/jvm/java-1.17.0-openjdk-amd64

Después de una etapa de compilación exitosa, aparecerá el logotipo de Spring y el símbolo del sistema de shell:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.0.5)



shell:>

Ahora puedes experimentar con los comandos que definimos anteriormente. Para ver la lista de comandos, usa el comando de ayuda:

shell:> help
...
find-all-books: Loads all books
find-by-author: Loads books by author: find-by-author <author>
find-by-author-year: Loads books by author and year: find-by-author-year <author> <year>
find-by-year-after: Loads books published after a given year: find-by-year-after <year>
remove-all-books: Removes all books
save-book: Saves a book to Cloud Datastore: save-book <title> <author> <year>

Prueba lo siguiente:

  1. Crea algunos libros con el comando save-book.
  2. Ejecuta una búsqueda con el comando find-all-books
  3. Encuentra libros de un autor específico: find-by-author <author>
  4. Busca libros publicados después de un año específico: find-by-year-after <year>
  5. Buscar libros por autor y año específicos: find-by-author-year <author> <year>

9. Consulta lo que se almacena en Datastore con la interfaz web

Para ver cómo se almacenan las entidades en Cloud Datastore, ve a GCP Console. Si es necesario, ingresa "books" en el campo kind.

5fab21a6c89f45a.png

10. Limpia

Para limpiar, quita todos los libros con el comando remove-all-books de nombre adecuado del shell de la aplicación.

shell:> remove-all-books

Para salir de la aplicación, usa el comando quit y, luego, Ctrl+C.

11. ¡Felicitaciones!

En este codelab, creaste una aplicación de CLI interactiva que puede almacenar y recuperar objetos de Cloud Datastore.

Más información

Licencia

Este trabajo cuenta con una licencia Atribución 2.0 Genérica de Creative Commons.