Primeiros passos com Java

Este tutorial destina-se a quem está começando a criar apps na nuvem, como engenheiros e desenvolvedores da Web que querem aprender os principais conceitos de desenvolvimento de apps no que se referem ao Google Cloud.

Objetivos

Para ver outros tutoriais específicos para cada linguagem a fim de criar seus apps, consulte estes guias:

Custos

Neste tutorial, usamos os seguintes componentes faturáveis do Google Cloud:

O tutorial foi criado para manter o uso de seus recursos dentro dos limites do nível Sempre gratuito do Google Cloud. Para gerar uma estimativa de custo baseada na projeção de uso deste tutorial, use a calculadora de preços. Novos usuários do Google Cloud podem ser qualificados para uma avaliação gratuita.

Ao concluir este tutorial, exclua os recursos criados para evitar o faturamento contínuo. Para mais informações, consulte Como fazer a limpeza.

Antes de começar

  1. Faça login na sua conta do Google Cloud. Se você começou a usar o Google Cloud agora, crie uma conta para avaliar o desempenho de nossos produtos em situações reais. Clientes novos também recebem US$ 300 em créditos para executar, testar e implantar cargas de trabalho.
  2. No Console do Google Cloud, na página do seletor de projetos, selecione ou crie um projeto do Google Cloud.

    Acessar o seletor de projetos

  3. Verifique se o faturamento está ativado para seu projeto na nuvem. Saiba como confirmar se o faturamento está ativado para o projeto.

  4. Para criar um banco de dados do Firestore no modo nativo, conclua as seguintes etapas:
    1. No Console do Cloud, acesse a página do visualizador do Firestore.
      Acessar o visualizador do Firestore
    2. Na tela Selecione um modo do Cloud Firestore, clique em Selecionar Modo nativo.
    3. Selecione um local para seu banco de dados do Firestore. Essa configuração é o local padrão de recurso do Google Cloud para seu projeto do Cloud . Esse local é usado em serviços do Google Cloud no seu projeto do Cloud que exigem uma configuração de local, especificamente, o bucket padrão do Cloud Storage e o app Cloud Run.
    4. Clique em Criar banco de dados.
  5. Ative as APIs Cloud Run Admin, Cloud Storage, Cloud Logging, and Error Reporting.

    Ative as APIs

  6. No Cloud Shell, abra o código-fonte do app.
    Acessar o Cloud Shell

    O Cloud Shell oferece acesso de linha de comando aos seus recursos do Google Cloud diretamente no navegador.

  7. Para fazer o download do código de exemplo e passar para o diretório do app, clique em Continuar.
  8. No Cloud Shell, configure a ferramenta gcloud para usar seu novo projeto do Google Cloud:

    # Configure gcloud for your project
    gcloud config set project PROJECT_ID
    

    Substitua PROJECT_ID pelo ID do projeto do Google Cloud que você criou usando o Console do Cloud.

    A ferramenta de linha de comando gcloud é a maneira principal de interagir com seus recursos do Google Cloud na linha de comando. Neste tutorial, você usará a ferramenta gcloud para implantar e monitorar seu app.

Como executar o app

  1. Se você já usa o Cloud Shell e já tiver configurado para usar o Java 11, atualize as variáveis de ambiente alternativas do Java, JAVA_HOME e PATH, para especificar o Java 8.
  2. Mude para o diretório bookshelf/1-cloud-run e execute o aplicativo:
    GOOGLE_CLOUD_PROJECT=PROJECT_ID mvn -Plocal clean jetty:run-exploded
    
    Substitua PROJECT_ID pelo ID do projeto do Google Cloud que você criou.
  3. No Cloud Shell, clique em Visualização da Web e selecione Visualizar na porta 8080. Uma nova janela será aberta com o app em execução.

Como implantar o app no Cloud Run

O Google Cloud oferece várias opções de execução do código. Neste exemplo, você usa o Cloud Run para implantar um app escalonável no Google Cloud. Sem gerenciamento de servidores, o Cloud Run permite que você se concentre em escrever o código. Além disso, o Cloud Run é escalonado automaticamente para suportar picos de tráfego repentinos.

  1. Crie a imagem usando Jib:
    mvn package jib:build -Dimage=gcr.io/PROJECT_ID/bookshelf

    Substitua PROJECT_ID pelo ID do projeto do Google Cloud que você criou.

  2. Depois implante a imagem:
    gcloud run deploy bookshelf --image gcr.io/PROJECT_ID/bookshelf \
    --platform managed --region us-central1 --allow-unauthenticated
    Substitua PROJECT_ID pelo ID do projeto do Google Cloud que você criou.

Quando a implantação for bem-sucedida, enviará um endpoint para o app em execução no Cloud Run, no seguinte formato:

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

Seu aplicativo está visível agora neste link, chamado YOUR_CODE_RUN_URL. No navegador da Web, insira o URL para ver o app.

Página inicial do app Bookshelf

Como manter os dados no Firestore

Não é possível armazenar informações nas suas instâncias do Cloud Run porque elas serão perdidas se a instância for reiniciada e deixarão de existir quando novas instâncias forem criadas. No entanto, é possível usar um banco de dados no qual todas as suas instâncias possam ler e gravar dados.

O Google Cloud oferece várias opções para armazenar seus dados. Neste exemplo, você usa o Firestore para armazenar os dados de cada livro. O Firestore é um banco de dados de documentos NoSQL totalmente gerenciado e sem servidor, que permite armazenar e consultar dados. Ele é escalonado automaticamente para atender às necessidades do app, sendo reduzido a zero quando não estiver sendo usado. Adicione seu primeiro livro agora.

  1. No seu navegador, acesse YOUR_CODE_RUN_URL.
  2. Para criar um livro para seu app implantado, clique em Adicionar livro.

    Adicionar um livro ao app Bookshelf
  3. No campo Título, insira Moby Dick.
  4. No campo Autor, insira Herman Melville.
  5. Clique em Salvar. Agora há uma entrada em seu app Bookshelf.

    Entrada Moby Dick no app Bookshelf
  6. No Console do Cloud, para atualizar a página do Firestore clique em Atualizar . Os dados são exibidos no Firestore. O app Bookshelf armazena cada livro como um documento do Firestore com um ID exclusivo. Todos esses documentos são armazenados em uma coleção do Cloud Firestore. Para os fins deste tutorial, a coleção é chamada de books. Exemplo de um documento do Firestore.

O Firestore armazena os livros usando a biblioteca de cliente do Firestore (em inglês). Veja a seguir um exemplo de como buscar um documento do 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 mais informações sobre como usar o Firestore, consulte Como adicionar dados ao Firestore.

Como armazenar uploads de arquivos no Cloud Storage

Agora que você adicionou um livro, é hora de adicionar a imagem da capa. Não é possível armazenar arquivos em suas instâncias. Um banco de dados não é a opção correta para arquivos de imagem. Em vez disso, use o Cloud Storage.

O Cloud Storage é o principal repositório de blobs do Google Cloud. Use o Cloud Storage para hospedar recursos de app que você quer compartilhar em todo o Google Cloud. Para usar o Cloud Storage, você precisa criar um bucket do Cloud Storage, um contêiner básico para guardar seus dados.

  1. No Console do Cloud, acesse a página Navegador do Cloud Storage.

    Acessar a página "Navegador do Cloud Storage"

  2. Clique em Criar bucket.
  3. Na caixa de diálogo Criar bucket, insira um nome para ele, anexando o ID do projeto do Google Cloud à string _bucket, de modo que o nome fique assim: YOUR_PROJECT_ID_bucket. Este nome está sujeito aos requisitos de nome de bucket. Todos os demais campos permanecem nos valores padrão.
  4. Clique em Criar.
  5. Após a criação do bucket, libere o acesso público aos objetos para que os usuários consigam vê-los. Para saber como fazer isso, consulte Como tornar os dados públicos.
  6. Clique em Editar livroe selecione uma imagem para carregar como a capa. Por exemplo, é possível usar este arquivo de domínio público:
    Capa do livro Moby Dick
  7. Clique em Salvar. Você será redirecionado para a página inicial onde há uma entrada do seu app Bookshelf.
    Entrada Moby Dick no app Bookshelf

O app Bookshelf envia os arquivos carregados para o Cloud Storage usando a biblioteca de cliente do 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 mais informações sobre como usar o Cloud Storage, consulte a lista de guias de instruções.

Como monitorar seu aplicativo usando o pacote de operações do Google Cloud

Você implantou seu app, depois criou e modificou livros. Para monitorar esses eventos para seus usuários, use o Gerenciamento do desempenho de aplicativos.

Monitore registros com o Cloud Logging

  1. No Google Cloud, acesse o visualizador de registros

    Acessar o visualizador de registros

    É possível monitorar seu app em tempo real. Se encontrar problemas em seu app, este é o primeiro lugar a ser verificado.

    Visualizador de registros do Stackdriver
  2. Na lista suspensa Recurso, selecione Revisão do Cloud Run, bookshelf.

Monitore erros com o Error Reporting

  1. No Console do Cloud, acesse a página Error Reporting.
    Acessar a página Error Reporting
    O Error Reporting destaca os erros e as exceções em seu app, além de permitir que você configure alertas para eles.
  2. No navegador, acesse o URL /errors em seu app.
    YOUR_CODE_RUN_URL/errors

    Isso gera uma nova exceção de teste e a envia ao pacote de operações do Google Cloud.

  3. No Console do Cloud, volte para a página Error Reporting e aguarde alguns instantes para ver o novo erro. Clique em Recarregar automaticamente para não precisar atualizar manualmente a página.

    Mensagem de erro do Error Reporting.

Limpeza

Para evitar cobranças na sua conta do Google Cloud pelos recursos usados no tutorial, exclua o projeto que os contém ou mantenha o projeto e exclua os recursos individuais.

Exclua o projeto

  1. No Console do Cloud, acesse a página Gerenciar recursos:

    Acessar "Gerenciar recursos"

  2. Na lista de projetos, selecione o projeto que você quer excluir e clique em Excluir .
  3. Na caixa de diálogo, digite o ID do projeto e clique em Encerrar para excluí-lo.

A seguir