Comienza a usar Java

Este instructivo está destinado a aquellos que estén comenzando a compilar aplicaciones en la nube, como ingenieros y desarrolladores web, que quieran aprender conceptos clave del desarrollo de aplicaciones y aplicarlos a Google Cloud.

Objetivos

Si deseas ver instructivos específicos sobre lenguajes para compilar aplicaciones, consulta las siguientes guías:

Costos

En este instructivo, se usan los siguientes componentes facturables de Google Cloud:

El instructivo está diseñado para que puedas mantener el uso de los recursos dentro de los límites del nivel Siempre gratuito de Google Cloud. Para generar una estimación de costos en función del uso previsto, usa la calculadora de precios. Es posible que los usuarios nuevos de Google Cloud sean aptos para obtener una prueba gratuita.

Cuando finalices este instructivo, podrás borrar los recursos creados para evitar que se te siga facturando. Para obtener más información, consulta cómo hacer una limpieza.

Antes de comenzar

  1. Accede a tu Cuenta de Google.

    Si todavía no tienes una cuenta, regístrate para obtener una nueva.

  2. En la página de selección de proyectos de Cloud Console, selecciona o crea un proyecto de Cloud.

    Ir a la página Selector de proyectos

  3. Asegúrate de que la facturación esté habilitada para tu proyecto de Google Cloud. Obtén información sobre cómo confirmar que tienes habilitada la facturación para tu proyecto.

  4. Para crear una base de datos de Firestore en modo nativo, sigue los pasos a continuación:
    1. En Cloud Console dirígete a la página Firestore viewer.
      Ir al Firestore viewer
    2. Desde la pantalla Selecciona un modo de Cloud Firestore, haz clic en Seleccionar Native mode.
    3. Selecciona una ubicación para tu base de datos de Firestore. Esta configuración corresponde a la ubicación predeterminada de los recursos de Google Cloud que definiste en el proyecto de Cloud. La configuración de la ubicación se usa en los servicios de Google Cloud del proyecto que la requieren; en particular, el depósito predeterminado de Cloud Storage y la aplicación de App Engine.
    4. Haz clic en Crear base de datos.
  5. Habilita las API de App Engine Admin, Cloud Storage, Cloud Logging, and Error Reporting.

    Habilita las API

  6. En Cloud Shell abre el código fuente de la app.
    Ir a Cloud Shell

    Cloud Shell brinda acceso de línea de comandos a tus recursos de Google Cloud directamente desde el navegador.

  7. Para descargar el código de muestra y cambiar al directorio de la app, haz clic en Continuar.
  8. En Cloud Shell configura la herramienta degcloud para que use tu proyecto de Google Cloud nuevo de la siguiente manera:

    # Configure gcloud for your project
    gcloud config set project PROJECT_ID
    

    Reemplaza PROJECT_ID por el ID del proyecto de Google Cloud que creaste mediante Cloud Console.

    La herramienta de línea de comandos de gcloud es la forma principal en la que interactúas con tus recursos de Google Cloud desde la línea de comandos. En este instructivo usarás la herramienta gcloud para implementar y supervisar tu aplicación.

Ejecuta la app

  1. Si ya usas Cloud Shell y lo configuraste para usar Java 11, actualiza las alternativas de Java de shell, JAVA_HOME, y las variables de entorno PATH para especificar Java 8.
  2. Cambia al directorio 1-cloud-run y ejecuta la aplicación, con el siguiente comando:
    GOOGLE_CLOUD_PROJECT=PROJECT_ID mvn -Plocal clean jetty:run-exploded
    
    Reemplaza PROJECT_ID por el ID del proyecto de Google Cloud que creaste.
  3. En Cloud Shell haz clic en Vista previa en la Web y selecciona Vista previa en el puerto 8080. Se abrirá una ventana nueva con tu app en ejecución.

Implementa tu aplicación en Cloud Run

Google Cloud ofrece varias opciones para ejecutar tu código. Para este ejemplo usa Cloud Run a fin de implementar una app escalable en Google Cloud. Gracias a que no necesita que se administren servidores, Cloud Run te permite enfocarte en escribir código. Además, Cloud Run escala de manera automática para admitir los aumentos de tráfico repentinos.

  1. Compila la imagen mediante Jib:
    mvn package jib:build -Dimage gcr.io/PROJECT_ID/bookshelf

    Reemplaza PROJECT_ID por el ID del proyecto de Google Cloud que creaste.

  2. Luego, implementa la imagen mediante este comando:
    gcloud run deploy bookshelf --image gcr.io/PROJECT_ID/bookshelf \
    --platform managed --region us-central1 --allow-unauthenticated
    Reemplaza PROJECT_ID por el ID del proyecto de Google Cloud que creaste.

Cuando la implementación se complete, mostrará un extremo de la app que se ejecuta en Cloud Run en el siguiente formato:

https://bookshelf-abcdefghij-uc.a.run.app

Tu app ya se puede visualizar en este enlace, que de ahora en más se llamará YOUR_CODE_RUN_URL. En tu navegador web, ingresa la URL para ver la app.

Página principal de la aplicación de Bookshelf

Almacena tus datos con Firestore

No se puede almacenar información en tus instancias de App Engine porque se perderá si se reinicia la instancia, además de que no existirá cuando se creen instancias nuevas. En su lugar, usarás una base de datos en la que todas tus instancias puedan leer y escribir.

Google Cloud ofrece varias opciones para almacenar tus datos. En este ejemplo, usarás Firestore para almacenar los datos de cada libro. Firestore es una base de datos de documentos NoSQL, completamente administrada y sin servidores que te permite almacenar y consultar datos. Firestore escala de manera automática para cumplir las necesidades de tu aplicación y escala a cero cuando no la estás usando. Agrega el primer libro.

  1. En el navegador web, ingresa la siguiente URL:

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

    Reemplaza los siguientes elementos:

  2. Si deseas crear un libro para la app implementada, haz clic en Add book.

    Agrega un libro a la aplicación Bookshelf
  3. En el campo Título (Title), ingresa Moby Dick.
  4. En el campo Autor (Author), ingresa Herman Melville.
  5. Haz clic en Guardar. Ya tienes una entrada en la aplicación Bookshelf.

    Entrada de Moby Dick en la app Bookshelf
  6. Para actualizar la página de Firestore, en Cloud Console, haz clic en Actualizar . Los datos aparecen en Firestore. La aplicación Bookshelf almacena cada libro como un documento de Firestore con un ID único, y todos estos documentos se almacenan en una colección de Firestore. Para los propósitos de este instructivo, la colección se llama “books”. Ejemplo de un documento de Firestore

Firestore almacena los libros mediante la biblioteca cliente de Firestore. Aquí hay un ejemplo de recuperación de un documento de Firestore:

public class FirestoreDao implements BookDao {
  private CollectionReference booksCollection;

  public FirestoreDao() {
    Firestore firestore = FirestoreOptions.getDefaultInstance().getService();
    booksCollection = firestore.collection("books");
  }

  private Book documentToBook(DocumentSnapshot document) {
    Map<String, Object> data = document.getData();
    if (data == null) {
      System.out.println("No data in document " + document.getId());
      return null;
    }

    return new Book.Builder()
        .author((String) data.get(Book.AUTHOR))
        .description((String) data.get(Book.DESCRIPTION))
        .publishedDate((String) data.get(Book.PUBLISHED_DATE))
        .imageUrl((String) data.get(Book.IMAGE_URL))
        .createdBy((String) data.get(Book.CREATED_BY))
        .createdById((String) data.get(Book.CREATED_BY_ID))
        .title((String) data.get(Book.TITLE))
        .id(document.getId())
        .build();
  }

  @Override
  public String createBook(Book book) {
    String id = UUID.randomUUID().toString();
    DocumentReference document = booksCollection.document(id);
    Map<String, Object> data = Maps.newHashMap();

    data.put(Book.AUTHOR, book.getAuthor());
    data.put(Book.DESCRIPTION, book.getDescription());
    data.put(Book.PUBLISHED_DATE, book.getPublishedDate());
    data.put(Book.TITLE, book.getTitle());
    data.put(Book.IMAGE_URL, book.getImageUrl());
    data.put(Book.CREATED_BY, book.getCreatedBy());
    data.put(Book.CREATED_BY_ID, book.getCreatedById());
    try {
      document.set(data).get();
    } catch (InterruptedException | ExecutionException e) {
      e.printStackTrace();
    }

    return id;
  }

  @Override
  public Book readBook(String bookId) {
    try {
      DocumentSnapshot document = booksCollection.document(bookId).get().get();

      return documentToBook(document);
    } catch (InterruptedException | ExecutionException e) {
      e.printStackTrace();
    }
    return null;
  }

  @Override
  public void updateBook(Book book) {
    DocumentReference document = booksCollection.document(book.getId());
    Map<String, Object> data = Maps.newHashMap();

    data.put(Book.AUTHOR, book.getAuthor());
    data.put(Book.DESCRIPTION, book.getDescription());
    data.put(Book.PUBLISHED_DATE, book.getPublishedDate());
    data.put(Book.TITLE, book.getTitle());
    data.put(Book.IMAGE_URL, book.getImageUrl());
    data.put(Book.CREATED_BY, book.getCreatedBy());
    data.put(Book.CREATED_BY_ID, book.getCreatedById());
    try {
      document.set(data).get();
    } catch (InterruptedException | ExecutionException e) {
      e.printStackTrace();
    }
  }

  @Override
  public void deleteBook(String bookId) {
    try {
      booksCollection.document(bookId).delete().get();
    } catch (InterruptedException | ExecutionException e) {
      e.printStackTrace();
    }
  }

  private List<Book> documentsToBooks(List<QueryDocumentSnapshot> documents) {
    List<Book> resultBooks = new ArrayList<>();
    for (QueryDocumentSnapshot snapshot : documents) {
      resultBooks.add(documentToBook(snapshot));
    }
    return resultBooks;
  }

  @Override
  public Result<Book> listBooks(String startTitle) {
    Query booksQuery = booksCollection.orderBy("title").limit(10);
    if (startTitle != null) {
      booksQuery = booksQuery.startAfter(startTitle);
    }
    try {
      QuerySnapshot snapshot = booksQuery.get().get();
      List<Book> results = documentsToBooks(snapshot.getDocuments());
      String newCursor = null;
      if (results.size() > 0) {
        newCursor = results.get(results.size() - 1).getTitle();
      }
      return new Result<>(results, newCursor);
    } catch (InterruptedException | ExecutionException e) {
      e.printStackTrace();
    }
    return new Result<>(Lists.newArrayList(), null);
  }

  @Override
  public Result<Book> listBooksByUser(String userId, String startTitle) {
    Query booksQuery =
        booksCollection.orderBy("title").whereEqualTo(Book.CREATED_BY_ID, userId).limit(10);
    if (startTitle != null) {
      booksQuery = booksQuery.startAfter(startTitle);
    }
    try {
      QuerySnapshot snapshot = booksQuery.get().get();
      List<Book> results = documentsToBooks(snapshot.getDocuments());
      String newCursor = null;
      if (results.size() > 0) {
        newCursor = results.get(results.size() - 1).getTitle();
      }
      return new Result<>(results, newCursor);
    } catch (InterruptedException | ExecutionException e) {
      e.printStackTrace();
    }
    return new Result<>(Lists.newArrayList(), null);
  }
}

Para obtener más información sobre el uso de Firestore, consulta Agrega datos a Firestore.

Almacena archivos subidos en Cloud Storage

Ahora que agregaste un libro, es momento de agregar su imagen de portada. No puedes almacenar archivos en tus instancias. Una base de datos no es la opción correcta para archivos de imagen. En cambio, debes usar Cloud Storage.

Cloud Storage es el almacenamiento de BLOB principal de Google Cloud. Puedes usar Cloud Storage a fin de alojar elementos de aplicaciones que deseas compartir en Google Cloud. Para usar Cloud Storage, debes crear un depósito de Cloud Storage, un contenedor básico en el que se guardan tus datos.

  1. En Cloud Console ve a la página Navegador de Cloud Storage.

    Ir a la página Navegador de Cloud Storage

  2. Haz clic en Crear depósito.
  3. En el cuadro de diálogo Crear depósito, adjunta el ID del proyecto de Google Cloud a la string _bucket para ingresar un nombre del depósito, de manera que sea similar a YOUR_PROJECT_ID_bucket. Este nombre está sujeto a los requisitos de nombres de los depósitos. En el resto de los campos, se pueden conservar los valores predeterminados.
  4. Haz clic en Crear.
  5. Una vez que se creó el depósito, haz clic en Edit book y selecciona una imagen para subir como portada del libro. Por ejemplo, puedes usar esta imagen de dominio público:
    Portada de Moby Dick
  6. Haz clic en Guardar. Se te redireccionará a la página principal, en la que encontrarás una entrada a tu aplicación de Bookshelf.
    Entrada de Moby Dick de la aplicación Bookshelf

La aplicación de Bookshelf envía los archivos subidos a Cloud Storage a través de la biblioteca cliente de Cloud Storage.

public class CloudStorageHelper {

  private final Logger logger = Logger.getLogger(CloudStorageHelper.class.getName());
  private static Storage storage = null;

  static {
    storage = StorageOptions.getDefaultInstance().getService();
  }

  /**
   * Uploads a file to Google Cloud Storage to the bucket specified in the BUCKET_NAME environment
   * variable, appending a timestamp to end of the uploaded filename.
   */
  public String uploadFile(FileItemStream fileStream, final String bucketName)
      throws IOException, ServletException {
    checkFileExtension(fileStream.getName());

    System.out.println("FileStream name: " + fileStream.getName() + "\nBucket name: " + bucketName);

    DateTimeFormatter dtf = DateTimeFormat.forPattern("-YYYY-MM-dd-HHmmssSSS");
    DateTime dt = DateTime.now(DateTimeZone.UTC);
    String dtString = dt.toString(dtf);
    final String fileName = fileStream.getName() + dtString;

    // the inputstream is closed by default, so we don't need to close it here
    @SuppressWarnings("deprecation")
    BlobInfo blobInfo =
        storage.create(
            BlobInfo.newBuilder(bucketName, fileName)
                // Modify access list to allow all users with link to read file
                .setAcl(new ArrayList<>(Arrays.asList(Acl.of(User.ofAllUsers(), Role.READER))))
                .build(),
            fileStream.openStream());
    logger.log(
        Level.INFO, "Uploaded file {0} as {1}", new Object[] {fileStream.getName(), fileName});
    // return the public download link
    return blobInfo.getMediaLink();
  }

  /** Checks that the file extension is supported. */
  private void checkFileExtension(String fileName) throws ServletException {
    if (fileName != null && !fileName.isEmpty() && fileName.contains(".")) {
      String[] allowedExt = {".jpg", ".jpeg", ".png", ".gif"};
      for (String ext : allowedExt) {
        if (fileName.endsWith(ext)) {
          return;
        }
      }
      throw new ServletException("file must be an image");
    }
  }
}

Para obtener más información sobre cómo usar Cloud Storage, consulta la lista de guías prácticas.

Supervisa la app con Google Cloud's operations suite

Ya implementaste la app y creaste y modificaste libros. A fin de supervisar estos eventos para los usuarios, usa la administración del rendimiento de las aplicaciones.

Supervisa los registros con Cloud Logging

  1. En Google Cloud ve al Visor de registros

    Ir al Visor de registros

    Puedes supervisar tu app en tiempo real. Si tienes problemas con tu app, este es uno de los primeros lugares que consultar.

    Visor de registros de Stackdriver
  2. En la lista desplegable Recursos, selecciona Revisión de Cloud Run, bookshelf.

Controla los errores con Error Reporting

  1. En Cloud Console ve a la página Error Reporting.
    Ir a la página Error Reporting
    Error Reporting destaca los errores y las excepciones de la app y te permite configurar alertas basadas en ellos.
  2. En el navegador ve a la URL /errors de la app.
    YOUR_CODE_RUN_URL/errors

    Esto genera una nueva excepción de prueba y la envía al Google Cloud's operations suite.

  3. En Cloud Console regresa a la página de Error Reporting y podrás ver el error nuevo en unos instantes. Haz clic en Volver a cargar de forma automática para no tener que actualizar la página de forma manual.

    Mensaje de error de Error Reporting.

Realiza una limpieza

Sigue estos pasos para evitar que se apliquen cargos a tu cuenta de Google Cloud Platform por los recursos que usaste en este instructivo:

Borra el proyecto

  1. En Cloud Console, ve a la página Administrar recursos.

    Ir a la página Administrar recursos

  2. En la lista de proyectos, selecciona el proyecto que deseas borrar y haz clic en Borrar .
  3. En el cuadro de diálogo, escribe el ID del proyecto y haz clic en Cerrar para borrar el proyecto.

Pasos siguientes