Premiers pas avec Java

Ce tutoriel s'adresse à ceux qui débutent dans la création d'applications dans le cloud, tels que les ingénieurs et les développeurs Web, et qui souhaitent connaître les concepts clés du développement d'applications sur Google Cloud.

Objectifs

Pour découvrir d'autres tutoriels sur la création d'applications par langage, consultez les guides suivants :

Coûts

Ce tutoriel utilise les composants facturables suivants de Google Cloud :

Ce tutoriel est conçu pour que votre utilisation des ressources respecte les limites définies pour le niveau Always Free de Google Cloud. Obtenez une estimation des coûts en fonction de votre utilisation prévue à l'aide du simulateur de coût. Les nouveaux utilisateurs de Google Cloud peuvent bénéficier d'un essai gratuit.

Une fois que vous avez terminé ce tutoriel, vous pouvez éviter de continuer à payer des frais en supprimant les ressources que vous avez créées. Consultez la page Effectuer un nettoyage pour en savoir plus.

Avant de commencer

  1. Connectez-vous à votre compte Google.

    Si vous n'en possédez pas déjà un, vous devez en créer un.

  2. Dans Cloud Console, sur la page de sélection du projet, sélectionnez ou créez un projet Cloud.

    Accéder à la page de sélection du projet

  3. Vérifiez que la facturation est activée pour votre projet Google Cloud. Découvrez comment vérifier que la facturation est activée pour votre projet.

  4. Pour créer une base de données Firestore en mode natif, effectuez la procédure suivante :
    1. Dans Cloud Console, accédez à la page du lecteur Firestore.
      Accéder au lecteur Firestore
    2. Sur l'écran Sélectionner un mode Cloud Firestore, cliquez sur Sélectionner le mode natif.
    3. Sélectionnez un emplacement pour votre base de données Firestore. Ce paramètre d'emplacement correspond à l'emplacement par défaut des ressources Google Cloud de votre projet Cloud. Cet emplacement est utilisé pour les services Google Cloud exploités dans votre projet Cloud qui requièrent un paramètre d'emplacement, plus précisément le bucket Cloud Storage par défaut et l'application App Engine.
    4. Cliquez sur Créer une base de données.
  5. Activez les App Engine Admin, Cloud Storage, Cloud Logging, and Error Reporting API.

    Activer les API

  6. Dans Cloud Shell, ouvrez le code source de l'application.
    Accéder à Cloud Shell

    Cloud Shell vous permet d'accéder via la ligne de commande à vos ressources Google Cloud, directement depuis votre navigateur.

  7. Pour télécharger l'exemple de code et accéder au répertoire de l'application, cliquez sur Continuer.
  8. Dans Cloud Shell, configurez l'outil gcloud pour qu'il utilise votre nouveau projet Google Cloud :

        # Configure gcloud for your project
        gcloud config set project PROJECT_ID
        

    Remplacez PROJECT_ID par l'ID du projet Google Cloud que vous avez créé avec Cloud Console.

    L'outil de ligne de commande gcloud représente votre principal moyen d'interaction avec vos ressources Google Cloud via la ligne de commande. Dans ce tutoriel, l'outil gcloud vous permet de déployer et de surveiller votre application.

Exécuter votre application

  1. Si vous utilisez déjà Cloud Shell et si vous l'avez configuré pour utiliser Java 11, mettez à jour les alternatives Java du shell, JAVA_HOME, ainsi que les variables d'environnement PATH pour spécifier Java 8.
  2. Accédez au répertoire 1-cloud-run et exécutez l'application :
        GOOGLE_CLOUD_PROJECT=PROJECT_ID mvn -Plocal clean jetty:run-exploded
        
    Remplacez PROJECT_ID par l'ID du projet Google Cloud que vous avez créé.
  3. Dans Cloud Shell, cliquez sur Aperçu sur le Web , puis sélectionnez Prévisualiser sur le port 8080. Une nouvelle fenêtre s'affiche avec votre application en cours d'exécution.

Déployer votre application dans Cloud Run

Google Cloud permet d'exécuter du code de plusieurs façons. Dans cet exemple, vous utilisez Cloud Run pour déployer une application évolutive dans Google Cloud. Comme aucune gestion de serveur n'est nécessaire, Cloud Run vous permet de vous concentrer sur l'écriture du code. De plus, Cloud Run évolue automatiquement pour gérer les pics de trafic soudains.

  1. Créez l'image à l'aide de Jib :
    mvn package jib:build -Dimage gcr.io/PROJECT_ID/bookshelf

    Remplacez PROJECT_ID par l'ID du projet Google Cloud que vous avez créé.

  2. Déployez ensuite l'image :
    gcloud run deploy bookshelf --image gcr.io/PROJECT_ID/bookshelf \
        --platform managed --region us-central1 --allow-unauthenticated
    Remplacez PROJECT_ID par l'ID du projet Google Cloud que vous avez créé.

Une fois le déploiement effectué, vous obtenez un point de terminaison pour l'application s'exécutant dans Cloud Run au format suivant :

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

Votre application est désormais visible via ce lien, représenté ici par YOUR_CODE_RUN_URL. Dans votre navigateur Web, saisissez l'URL pour accéder à l'application.

Page d'accueil de l'application Bookshelf

Faire persister vos données avec Firestore

Vous ne pouvez pas stocker d'informations sur vos instances App Engine, car elles sont perdues si l'instance redémarre et n'existent pas lorsque des instances sont créées. À la place, vous devez utiliser une base de données, qui est le point de départ de toute opération de lecture ou d'écriture de vos instances.

Google Cloud permet de stocker des données de plusieurs façons. Dans cet exemple, vous utilisez Firestore pour stocker les données de chaque livre. Firestore est une base de données de documents NoSQL entièrement gérée et sans serveur qui permet de stocker et d'interroger des données. Firestore effectue un autoscaling en fonction des besoins de votre application et n'exploite aucune instance lorsque vous ne l'utilisez pas. Ajoutez votre premier livre dès aujourd'hui.

  1. Dans votre navigateur Web, saisissez l'URL suivante :

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

    Remplacez les éléments suivants :

  2. Pour créer un livre à partir de l'application déployée, cliquez sur Add book (Ajouter un livre).

    Ajouter un livre dans l'application Bookshelf
  3. Dans le champ Title (Titre), saisissez Moby Dick.
  4. Dans le champ Author (Auteur), saisissez Herman Melville.
  5. Cliquez sur Save (Enregistrer). L'application Bookshelf possède désormais une entrée.

    Entrée
  6. Pour actualiser la page Firestore dans Cloud Console, cliquez sur Actualiser. Les données s'affichent dans Firestore. L'application Bookshelf stocke chaque livre sous la forme d'un document Firestore ayant un ID unique, et tous ces documents sont stockés dans une collection Firestore. Dans ce tutoriel, la collection s'appelle "books" (livres). Exemple de document Firestore

Firestore stocke les livres à l'aide de la bibliothèque cliente Firestore. Voici un exemple de récupération d'un document 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);
      }
    }

Pour en savoir plus sur l'utilisation de Firestore, consultez l'article Ajouter des données.

Stocker des fichiers importés dans Cloud Storage

Maintenant que vous avez ajouté un livre, vous pouvez inclure son image de couverture. Vous ne pouvez pas stocker de fichiers sur vos instances. Une base de données n'est pas adaptée aux fichiers image. Utilisez plutôt Cloud Storage.

Cloud Storage est le principal magasin de blobs pour Google Cloud. Vous pouvez utiliser Cloud Storage pour héberger des éléments d'applications que vous voulez partager sur Google Cloud. Pour utiliser Cloud Storage, vous devez créer un bucket Cloud Storage, c'est-à-dire un conteneur de base permettant de conserver vos données.

  1. Dans Cloud Console, accédez à la page Navigateur Cloud Storage.

    Accéder à la page Navigateur Cloud Storage

  2. Cliquez sur Créer un bucket.
  3. Dans la boîte de dialogue Créer un bucket, saisissez le nom du bucket en ajoutant l'ID du projet Google Cloud à la chaîne _bucket. Le nom de votre bucket doit se présenter comme suit : YOUR_PROJECT_ID_bucket. Ce nom doit respecter les exigences concernant les noms de buckets. Vous pouvez conserver les valeurs par défaut de tous les autres champs.
  4. Cliquez sur Créer.
  5. Une fois le bucket créé, cliquez sur Edit book (Modifier le livre), puis sélectionnez une image à importer pour sa couverture. Vous pouvez par exemple utiliser cette image du domaine public :
    Couverture du livre Moby Dick
  6. Cliquez sur Enregistrer. Vous êtes redirigé vers la page d'accueil sur laquelle se trouve une entrée de votre application Bookshelf.
    Entrée

L'application Bookshelf envoie les fichiers importés vers Cloud Storage à l'aide de la bibliothèque cliente 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");
        }
      }
    }

Pour en savoir plus sur l'utilisation de Cloud Storage, consultez la liste des guides d'utilisation.

Surveiller votre application à l'aide de la suite pour les opérations de Google Cloud

Vous avez déployé votre application, et créé et modifié des livres. Utilisez les outils de gestion des performances des applications pour surveiller ces événements pour vos utilisateurs.

Surveiller les journaux à l'aide de Cloud Logging

  1. Dans Google Cloud, accédez à la visionneuse de journaux.

    Accéder à la visionneuse de journaux

    Vous pouvez surveiller votre application en temps réel. Si vous rencontrez des problèmes avec celle-ci, la visionneuse est l'un des premiers éléments à consulter.

    Visionneuse de journaux Stackdriver
  2. Dans la liste déroulante Resource (Ressource), sélectionnez Cloud Run Revision, bookshelf (Révision dans Cloud Run, bookshelf).

Surveiller les erreurs avec Error Reporting

  1. Dans Cloud Console, accédez à la page Error Reporting.
    Accéder à la page Rapports d'erreurs
    Stackdriver Error Reporting met en évidence les erreurs et les exceptions dans votre application et vous permet de configurer des alertes à leur sujet.
  2. Dans le navigateur, accédez à l'URL /errors dans l'application.
    YOUR_CODE_RUN_URL/errors

    Vous générez ainsi une nouvelle exception de test, qui est envoyée à la suite pour les opérations de Google Cloud.

  3. Dans Cloud Console, revenez à la page Rapports d'erreurs. La nouvelle erreur s'affiche après quelques instants. Cliquez sur Actualisation automatique pour ne pas avoir à actualiser la page manuellement.

    Message d'erreur dans Error Reporting

Nettoyer

Pour éviter que les ressources utilisées dans ce tutoriel soient facturées sur votre compte Google Cloud Platform :

Supprimer le projet

  1. Dans Cloud Console, accédez à la page Gérer les ressources.

    Accéder à la page Gérer les ressources

  2. Dans la liste des projets, sélectionnez le projet que vous souhaitez supprimer, puis cliquez sur Supprimer.
  3. Dans la boîte de dialogue, saisissez l'ID du projet, puis cliquez sur Arrêter pour supprimer le projet.

Étape suivante