Primeros pasos con Java

Este tutorial va dirigido a personas que no tengan experiencia en el desarrollo de aplicaciones en la nube, como ingenieros o desarrolladores web, y que quieran aprender los conceptos básicos del desarrollo de aplicaciones en el entorno de Google Cloud.

Objetivos

Para ver otros tutoriales sobre cómo desarrollar aplicaciones de lenguajes específicos, consulta la siguiente guía de inicio rápido:

Costes

plain,alwaysfree

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 empezar

  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 Selector de proyectos de Cloud Console, selecciona o crea un proyecto de Cloud.

    Ir a la página Selector de proyectos

  3. Comprueba que la facturación esté habilitada en tu proyecto.

    Descubre cómo puedes habilitar la facturación

  4. Para crear una base de datos de Firestore en modo nativo, sigue estos pasos:
    1. En la consola de Cloud, ve a la página del visualizador de Firestore.
      Ir al visualizador de Firestore
    2. En la pantalla Selecciona un modo de Cloud Firestore, haz clic en Seleccionar modo nativo.
    3. Selecciona una ubicación para tu base de datos de Firestore. La opción que configures será la ubicación predeterminada de los recursos de Google Cloud para tu proyecto de dicha plataforma. Esta ubicación se usa para los servicios de Google Cloud de tu proyecto que requieren este parámetro. Concretamente, para tu segmento de Cloud Storage y tu aplicación de App Engine predeterminados.
    4. Haz clic en Crear base de datos.
  5. appengine.googleapis.com,storage-api.googleapis.com,logging.googleapis.com,clouderrorreporting.googleapis.com App Engine Admin, Cloud Storage, Stackdriver Logging, and Stackdriver Error Reporting no_steps,no_credentials
  6. En Cloud Shell, abre el código fuente de la aplicación.
    Ir a Cloud Shell

    Cloud Shell te ofrece acceso a tus recursos de Google Cloud mediante la línea de comandos directamente desde el navegador.

  7. Para descargar el código de ejemplo y cambiarlo en el directorio de la aplicación, haz clic en Continuar.
  8. En Cloud Shell, configura la herramienta gcloud para usar tu nuevo proyecto de Google Cloud:

        # Configure gcloud for your project
        gcloud config set project PROJECT_ID
        

    Sustituye PROJECT_ID por el ID del proyecto de Google Cloud que has creado con la consola de Cloud.

    La herramienta de línea de comandos gcloud es la forma principal de interactuar con tus recursos de Google Cloud desde la línea de comandos. En este tutorial, usarás la herramienta gcloud para desplegar y supervisar tu aplicación.

Ejecutar la aplicación

  1. Ejecuta la aplicación:
        GOOGLE_CLOUD_PROJECT=PROJECT_ID mvn -Plocal clean jetty:run-exploded
        
    Sustituye PROJECT_ID por el ID del proyecto de Google Cloud que has creado.
  2. En Cloud Shell, haz clic en Vista previa web y selecciona Obtener vista previa en puerto 8080 para que se abra una ventana nueva con tu aplicación en ejecución.

Desplegar una aplicación en Cloud Run

Google Cloud te ofrece diferentes opciones para ejecutar tu código. En este ejemplo, vas a usar Cloud Run para desplegar una aplicación escalable en Google Cloud. Cloud Run te permite centrarte en escribir código, ya que no tienes que gestionar servidores. Además, se escala automáticamente para adaptarse a los picos de tráfico repentinos.

  1. Crea la imagen con Jib:
    mvn package jib:build
  2. A continuación, despliégala de la siguiente forma:
    gcloud beta run deploy bookshelf --image gcr.io/PROJECT_ID/bookshelf \
        --platform managed --region us-central1

Una vez desplegada, se generará un punto de conexión con la aplicación que se ejecuta en Cloud Run en el siguiente formato:

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

Para ver la aplicación, introduce el enlace YOUR_CODE_RUN_URL en el navegador web.

Página principal de la aplicación Bookshelf

Conservar los datos con Firestore

No puedes almacenar información en tus instancias de App Engine, ya que se perderá si se reinician las instancias y no se mantendrá al crear otras. En su lugar, debes usar una base de datos que todas tus instancias utilicen para las operaciones de lectura y escritura.

Google Cloud te ofrece varias opciones para almacenar tus datos. En este ejemplo, vas a usar Firestore para almacenar los datos de cada libro. Firestore es una base de datos NoSQL de documentos totalmente gestionada y sin servidor que permite almacenar y consultar datos. Se escala automáticamente para adaptarse a las necesidades de tu aplicación y no consume ningún recurso cuando no la usas. Ahora vamos a añadir tu primer libro.

  1. Introduce la siguiente dirección en el navegador web:

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

    Haz los cambios siguientes:

  2. Para crear un libro en tu aplicación desplegada, haz clic en Add book (Añadir libro).

    Añadir un libro a la aplicación Bookshelf
  3. En el campo Title (Título), introduce Moby Dick.
  4. En el campo Author (Autor), introduce Herman Melville.
  5. Haz clic en Save (Guardar) y se habrá creado una entrada en tu aplicación Bookshelf.

    Entrada de Moby Dick en la aplicación Bookshelf
  6. En la consola de Cloud, haz clic en Actualizar para actualizar la página de Firestore. Los datos aparecerán en Firestore. La aplicación Bookshelf almacena cada libro como un documento de Firestore con un ID único, y estos documentos se guardan a su vez en una colección de Firestore. En este tutorial, la colección se llama "books". Ejemplo de documento de Firestore

Firestore almacena los libros mediante la biblioteca de cliente de Firestore. A continuación se incluye un ejemplo de cómo obtener 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 acerca del uso de Firestore, consulta el artículo sobre cómo añadir datos a Firestore.

Almacenar archivos subidos en Cloud Storage

Ahora que has añadido un libro, ha llegado el momento de añadir una imagen de portada. No puedes almacenar archivos en tus instancias, y una base de datos no es la opción adecuada para los archivos de imagen. En su lugar, te recomendamos que uses Cloud Storage.

Cloud Storage es el almacén de blobs principal de Google Cloud. Puedes usarlo para alojar los recursos de la aplicación que quieras compartir en Google Cloud. Para ello, debes crear un segmento de Cloud Storage (un contenedor básico para tus datos).

console
  1. En la consola de Cloud, ve a la página Navegador de Cloud Storage.

    Ir a la página Navegador de Cloud Storage

  2. Haz clic en Crear segmento.
  3. En el cuadro de diálogo Crear segmento, escribe el nombre del segmento. Para ello, añade el ID de tu proyecto de Google Cloud a la cadena _bucket para que el nombre tenga el formato YOUR_PROJECT_ID_bucket. El nombre está sujeto a los requisitos de nombres de segmentos. Puedes dejar los valores predeterminados del resto de los campos.
  4. Haz clic en Crear.
  5. Después de crear el segmento, haz clic en Edit book (Editar libro) y selecciona una imagen para subirla como portada del libro. Por ejemplo, puedes usar esta imagen pública:
    Portada del libro Moby Dick
  6. Haz clic en Save (Guardar). Se te redirigirá a la página principal, donde verás una entrada de tu aplicación Bookshelf.
    Entrada de Moby Dick en la aplicación Bookshelf

La aplicación Bookshelf envía los archivos subidos a Cloud Storage mediante la biblioteca de 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.

Monitorizar la aplicación con Stackdriver

Ya has desplegado tu aplicación, y has creado y modificado libros. Si quieres monitorizar estos eventos para tus usuarios, usa Stackdriver APM.

Monitorizar registros con Stackdriver Logging

  1. En Google Cloud, ve al visualizador de registros.

    Ir al visualizador de registros

    Desde ahí, puedes monitorizar tu aplicación en tiempo real. Si tienes algún problema con la aplicación, este es uno de los primeros sitios a los que debes acudir.

    Visualizador de registros de Stackdriver
  2. En la lista desplegable Recurso, selecciona Revisión de Cloud Run, Bookshelf.

Monitorizar errores con Stackdriver Error Reporting

  1. En la consola de Cloud, ve a la página Error Reporting.
    Ir a la página Error Reporting
    Stackdriver Error Reporting destaca errores y excepciones de tu aplicación, y te permite configurar alertas relacionadas con ellos.
  2. En el navegador, ve a la URL /errors de tu aplicación.
    YOUR_CODE_RUN_URL/errors

    Esta acción genera una nueva excepción de prueba y la envía a Stackdriver.

  3. En la consola de Cloud, vuelve a la página Error Reporting. En unos minutos, aparecerá el nuevo error. Haz clic en Volver a cargar automáticamente para que no tengas que actualizar la página manualmente.

    Mensaje de error de Error Reporting

Eliminar los recursos utilizados

Para evitar que los recursos utilizados en este tutorial se cobren en tu cuenta de Google Cloud Platform, sigue estas instrucciones:

Eliminar 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, luego, haz clic en Cerrar para borrar el proyecto.

Pasos siguientes