1. Introduction
Spring Framework 5.0 a ajouté une compatibilité dédiée à Kotlin, ce qui permet aux développeurs Kotlin d'utiliser facilement Spring. Par conséquent, ces modifications signifient que les intégrations Google Cloud fournies par Spring Cloud GCP fonctionnent également de manière fluide dans Kotlin. Dans cet atelier de programmation, vous allez découvrir à quel point il est facile de commencer à utiliser les services Google Cloud dans vos applications Kotlin.
Cet atelier de programmation vous guide dans la configuration d'une application d'enregistrement simple en Kotlin, qui montre comment utiliser les services GCP, y compris Cloud Pub/Sub et Cloud SQL.
Ce que vous allez faire
Dans cet atelier de programmation, vous allez configurer une application Kotlin Spring Boot qui accepte les informations des inscrits, les publie dans un sujet Cloud Pub/Sub et les conserve dans une base de données Cloud MySQL.
Points abordés
Découvrez comment intégrer les services Google Cloud à votre application Kotlin Spring.
Prérequis
- Un projet Google Cloud Platform
- Un navigateur tel que Chrome ou Firefox
Comment allez-vous utiliser ce tutoriel ?
Comment évalueriez-vous votre expérience de création d'applications Web HTML/CSS ?
Quel est votre niveau d'expérience avec les services Google Cloud Platform ?
2. Préparation
Configuration de l'environnement d'auto-formation
- Connectez-vous à Cloud Console, puis créez un projet ou réutilisez un projet existant. (Si vous n'avez pas encore de compte Gmail ou G Suite, vous devez en créer un.)
Mémorisez l'ID du projet. Il s'agit d'un nom unique permettant de différencier chaque projet Google Cloud (le nom ci-dessus est déjà pris ; vous devez en trouver un autre). Il sera désigné par le nom PROJECT_ID tout au long de cet atelier de programmation.
- Vous devez ensuite activer la facturation dans Cloud Console pour pouvoir utiliser les ressources Google Cloud.
L'exécution de cet atelier de programmation est très peu coûteuse, voire sans frais. Veillez à suivre les instructions de la section "Nettoyer" qui indique comment désactiver les ressources afin d'éviter les frais une fois ce tutoriel terminé. Les nouveaux utilisateurs de Google Cloud peuvent participer au programme d'essai sans frais pour bénéficier d'un crédit de 300 $.
Google Cloud Shell
Bien que Google Cloud puisse être utilisé à distance depuis votre ordinateur portable, nous allons nous servir de Google Cloud Shell pour cet atelier de programmation, un environnement de ligne de commande exécuté dans le cloud.
Activer Cloud Shell
- Dans Cloud Console, cliquez sur Activer Cloud Shell
.
Si vous n'avez encore jamais démarré Cloud Shell, un écran intermédiaire s'affiche en dessous de la ligne de séparation pour décrire de quoi il s'agit. Si tel est le cas, cliquez sur Continuer (cet écran ne s'affiche qu'une seule fois). Voici à quoi il ressemble :
Le provisionnement et la connexion à Cloud Shell ne devraient pas prendre plus de quelques minutes.
Cette machine virtuelle contient tous les outils de développement nécessaires. Elle intègre un répertoire d'accueil persistant de 5 Go et s'exécute sur Google Cloud, ce qui améliore nettement les performances réseau et l'authentification. Vous pouvez réaliser une grande partie, voire la totalité, des activités de cet atelier dans un simple navigateur ou sur votre Chromebook.
Une fois connecté à Cloud Shell, vous êtes en principe authentifié et le projet est défini avec votre ID de projet.
- Exécutez la commande suivante dans Cloud Shell pour vérifier que vous êtes authentifié :
gcloud auth list
Résultat de la commande
Credentialed Accounts
ACTIVE ACCOUNT
* <my_account>@<my_domain.com>
To set the active account, run:
$ gcloud config set account `ACCOUNT`
gcloud config list project
Résultat de la commande
[core] project = <PROJECT_ID>
Si vous obtenez un résultat différent, exécutez cette commande :
gcloud config set project <PROJECT_ID>
Résultat de la commande
Updated property [core/project].
3. Provisionner des ressources Pub/Sub
Nous devons d'abord configurer un sujet et un abonnement Cloud Pub/Sub. Dans cette application, nous allons publier des informations d'inscription dans un sujet Pub/Sub. Ces informations seront ensuite lues à partir de ce sujet et conservées dans une base de données.
Dans ce tutoriel, nous allons nous appuyer sur Cloud Shell pour provisionner nos ressources. Notez que vous pouvez également configurer des ressources Pub/Sub dans la section Cloud Pub/Sub de la console Google Cloud.
Dans votre terminal Cloud Shell, commencez par activer l'API Pub/Sub.
$ gcloud services enable pubsub.googleapis.com
Nous allons ensuite créer un sujet Pub/Sub nommé registrations pour cette application. Les informations d'inscription envoyées via l'application seront publiées dans ce sujet.
$ gcloud pubsub topics create registrations
Enfin, créez un abonnement pour le sujet. Un abonnement Pub/Sub vous permet de recevoir des messages d'un sujet.
$ gcloud pubsub subscriptions create registrations-sub --topic=registrations
Vous avez terminé de créer un sujet et un abonnement Cloud Pub/Sub pour votre application.
4. Créer une instance et une base de données Cloud SQL (MySQL)
Pour notre exemple d'application, nous devons également configurer une instance de base de données pour stocker les informations sur les inscrits. Cette étape s'appuiera également sur le terminal Cloud Shell pour provisionner les ressources Cloud SQL. Notez que vous pouvez également afficher et configurer vos instances Cloud SQL dans la console Google Cloud.
Commencez par activer l'API Cloud SQL Admin.
$ gcloud services enable sqladmin.googleapis.com
Nous allons ensuite provisionner une instance Cloud SQL (MySQL). L'exécution de cette commande peut prendre un certain temps.
$ gcloud sql instances create codelab-instance --region=us-east1
Une fois votre instance Cloud SQL créée, créez-y une base de données nommée registrants.
$ gcloud sql databases create registrants --instance codelab-instance
Vous avez terminé de configurer l'instance et la base de données Cloud SQL pour votre application.
5. Initialiser une application Spring Boot
Nous sommes maintenant prêts à commencer à écrire l'application. Les étapes suivantes continueront d'utiliser Cloud Shell décrit dans les étapes de configuration.
Nous allons d'abord utiliser Initializr pour générer le code de structure du projet. Dans votre fenêtre Cloud Shell, exécutez la commande suivante :
$ cd ~
$ curl https://start.spring.io/starter.tgz \
-d language=kotlin \
-d bootVersion=2.4.0 \
-d dependencies=web,data-jpa,integration,cloud-gcp-pubsub,thymeleaf \
-d baseDir=registrations-codelab | tar -xzvf -
$ cd registrations-codelab
Cette commande génère une configuration initiale du projet Maven ainsi qu'un code de structure pour votre application dans le répertoire registrations-codelab/. Les sections suivantes décrivent les modifications de code nécessaires pour produire une application fonctionnelle.
Éditeur de code Cloud Shell
Le moyen le plus simple de commencer à modifier et à afficher du code dans l'environnement Cloud Shell est d'utiliser l'éditeur de code Cloud Shell intégré.
Une fois que vous avez ouvert une instance Cloud Shell, cliquez sur l'icône en forme de crayon pour ouvrir l'éditeur de code. L'éditeur doit vous permettre de modifier directement les fichiers de projet produits par Initialzr.

6. Configuration de la base de données
Commencez par configurer votre application pour qu'elle puisse se connecter à la base de données Cloud MySQL que vous avez configurée. Les bibliothèques Spring Cloud GCP proposent un starter Cloud MySQL qui fournit les dépendances nécessaires pour se connecter à une instance Cloud MySQL.
Ajoutez la dépendance spring-cloud-gcp-starter-sql-mysql au fichier pom.xml du projet :
registrations-codelab/pom.xml
...
<dependencies>
... Other dependencies above ...
<!-- Add the MySQL starter to the list of dependencies -->
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>spring-cloud-gcp-starter-sql-mysql</artifactId>
</dependency>
</dependencies>
Vous devez également modifier le fichier de configuration application.properties pour décrire la configuration de votre base de données. Copiez les propriétés suivantes dans votre fichier application.properties.
Recherchez le nom de connexion de l'instance à votre base de données :
$ gcloud sql instances describe codelab-instance \ --format 'value(connectionName)'
Le résultat de cette opération sera utilisé dans le fichier application.properties pour configurer les informations de connexion.
src/main/resources/application.properties
# Modify this property using the output from the previous command line. spring.cloud.gcp.sql.instance-connection-name=INSTANCE_CONNECTION_NAME # Your database name spring.cloud.gcp.sql.database-name=registrants # So app starts despite "table already exists" errors. spring.datasource.continue-on-error=true # Enforces database initialization spring.datasource.initialization-mode=always # Cloud SQL (MySQL) only supports InnoDB, not MyISAM spring.jpa.database-platform=org.hibernate.dialect.MySQL55Dialect spring.jpa.hibernate.ddl-auto=create-drop # This is used if you want to connect to a different database instance # user other than root; not used in codelab. # spring.datasource.username=root # This is used to specify the password of the database user; # not used in codelab. # spring.datasource.password=password
La seule propriété que vous devez modifier est le nom de connexion de l'instance. Cette valeur doit être mise en forme sous la forme d'une valeur séparée par un deux-points : YOUR_GCP_PROJECT_ID:REGION:DATABASE_INSTANCE_NAME.
7. Créer le contenu statique
Nous allons d'abord créer l'interface de notre application. L'application doit comporter un formulaire permettant d'enregistrer des personnes, ainsi qu'une vue affichant toutes les personnes enregistrées.
Pour la page d'accueil, créez un index.html contenant le formulaire d'inscription.
src/main/resources/static/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Registration Sample Application</title>
</head>
<body>
<h1>Registration</h1>
<div>
<nav>
<a href="/">Home</a><br>
<a href="/registrants">Registered People</a><br>
</nav>
<p>
This is a demo registration application which sends user information to a Pub/Sub topic and
persists it into a MySQL database.
</p>
<h2>Register Person</h2>
<div>
<form action="/registerPerson" method="post">
First Name: <input type="text" name="firstName" />
Last Name: <input type="text" name="lastName" />
Email: <input type="text" name="email" />
<input type="submit" value="Submit"/>
</form>
</div>
</div>
</body>
</html>
Nous allons ensuite créer un modèle Thymeleaf nommé registrants.html pour afficher les utilisateurs enregistrés. Thymeleaf est un framework de création de modèles que nous utilisons pour créer et diffuser du code HTML généré de manière dynamique. Vous verrez que le modèle ressemble à du code HTML, à l'exception de certains éléments Markdown supplémentaires permettant de gérer le contenu dynamique. Ce modèle accepte un seul paramètre appelé personsList, qui contient tous les inscrits via l'application.
src/main/resources/templates/registrants.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Registrants List</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<h1>Registrants List</h1>
<p>
This page displays all the people who were registered through the Pub/Sub topic.
All results are retrieved from the MySQL database.
</p>
<table border="1">
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
</tr>
<tr th:each="person : ${personsList}">
<td>[[${person.firstName}]]</td>
<td>[[${person.lastName}]]</td>
<td>[[${person.email}]]</td>
</tr>
</table>
</body>
</html>
À ce stade, vous pouvez vérifier que le contenu statique est diffusé.
Créez et exécutez l'application à l'aide de Maven :
$ ./mvnw spring-boot:run
Cliquez sur le bouton d'aperçu dans la fenêtre Cloud Shell et vérifiez que la page d'accueil s'affiche. Cependant, aucune des fonctionnalités de l'UI ne fonctionnera, car il nous manque un contrôleur Web. Nous l'ajouterons à l'étape suivante.

Après avoir prévisualisé l'application, appuyez sur CTRL+C pour la fermer.
8. Envoyer les inscrits à un sujet Pub/Sub
Dans cette étape, nous allons implémenter la fonctionnalité permettant de publier les inscrits envoyés via le formulaire Web dans un sujet Cloud Pub/Sub.
Ajouter les classes de données
Tout d'abord, nous allons créer des classes de données Kotlin. Elles serviront d'entités JPA et de représentation intermédiaire des participants inscrits via le formulaire.
Dans le package de démonstration, ajoutez deux fichiers : une classe Person et un PersonRepository Spring Data. Ces deux classes nous permettront de stocker et de récupérer facilement les entrées d'enregistrement de notre base de données MySQL à l'aide de Spring Data JPA.
src/main/kotlin/com/example/demo/Person.kt
package com.example.demo
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.Id
@Entity
data class Person(
val firstName: String,
val lastName: String,
val email: String,
@Id @GeneratedValue
var id: Long? = 0)
src/main/kotlin/com/example/demo/PersonRepository.kt
package com.example.demo
import org.springframework.data.repository.CrudRepository
interface PersonRepository : CrudRepository<Person, Long>
Ajouter le contrôleur Web
Ensuite, nous allons créer une classe de contrôleur qui traite les inscrits du formulaire et envoie les informations au sujet Cloud Pub/Sub que vous avez créé précédemment. Ce contrôleur crée deux points de terminaison :
/registerPerson: point de terminaison POST dans lequel les informations sur les inscrits sont envoyées, puis transmises au sujet Pub/Sub. Dans la fonctionregisterPerson(..), les informations sur l'inscrit sont envoyées au sujet Pub/Sub à l'aide dePubSubTemplate, une classe pratique des intégrations Spring Cloud GCP Pub/Sub qui réduit au minimum le code standard nécessaire pour commencer à interagir avec Cloud Pub/Sub./registrants: affiche tous les participants correctement enregistrés dans la base de données. Ces informations sont récupérées à partir de l'instance MySQL à l'aide du dépôt Spring Data que nous avons créé à l'étape précédente.
Créez la classe Controller suivante dans le package de démonstration :
src/main/kotlin/com/example/demo/Controller.kt
package com.example.demo
import com.google.cloud.spring.pubsub.core.PubSubTemplate
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.servlet.ModelAndView
import org.springframework.web.servlet.view.RedirectView
@RestController
class Controller(val pubSubTemplate: PubSubTemplate, val personRepository: PersonRepository) {
// The Pub/Sub topic name created earlier.
val REGISTRATION_TOPIC = "registrations"
@PostMapping("/registerPerson")
fun registerPerson(
@RequestParam("firstName") firstName: String,
@RequestParam("lastName") lastName: String,
@RequestParam("email") email: String): RedirectView {
pubSubTemplate.publish(
REGISTRATION_TOPIC,
Person(firstName, lastName, email))
return RedirectView("/")
}
@GetMapping("/registrants")
fun getRegistrants(): ModelAndView {
val personsList = personRepository.findAll().toList()
return ModelAndView("registrants", mapOf("personsList" to personsList))
}
}
Le contrôleur lit les informations sur le participant envoyées via le formulaire Web, puis les publie dans le sujet Pub/Sub.
Ajouter le bean JSON Object Mapper
Vous avez peut-être remarqué que dans le contrôleur, nous publions un objet Person dans le sujet Pub/Sub et non une chaîne. Cela est possible, car nous tirons parti de la compatibilité de Spring Cloud GCP avec les charges utiles JSON personnalisées à envoyer aux thèmes. Les bibliothèques vous permettent de sérialiser des objets au format JSON, d'envoyer des charges utiles JSON à un thème et de désérialiser la charge utile lorsqu'elle est reçue.
Pour profiter de cette fonctionnalité, nous devons ajouter un bean ObjectMapper au contexte de votre application. Ce bean ObjectMapper sera utilisé pour sérialiser les objets au format JSON lorsque votre application enverra et recevra des messages. Dans la classe DemoApplication.kt, ajoutez le bean Spring JacksonPubSubMessageConverter :
src/main/kotlin/com/example/demo/DemoApplication.kt
package com.example.demo
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
// new imports to add
import org.springframework.context.annotation.Bean
import com.fasterxml.jackson.databind.ObjectMapper
import com.google.cloud.spring.pubsub.support.converter.JacksonPubSubMessageConverter
@SpringBootApplication
class DemoApplication {
// This bean enables serialization/deserialization of
// Java objects to JSON for Pub/Sub payloads
@Bean
fun jacksonPubSubMessageConverter(objectMapper: ObjectMapper) =
JacksonPubSubMessageConverter(objectMapper)
}
fun main(args: Array<String>) {
runApplication<DemoApplication>(*args)
}
À ce stade, vous pouvez essayer d'exécuter de nouveau l'application en exécutant :
$ ./mvnw spring-boot:run
À partir du formulaire Web sur la page principale, l'application envoie désormais les informations au sujet Pub/Sub que vous avez créé. Cependant, il ne fait toujours rien d'utile, car nous devons encore lire à partir de ce sujet Pub/Sub. C'est ce que vous ferez à la prochaine étape.
9. Lecture des inscrits à partir du sujet Pub/Sub
Lors de la dernière étape, nous traiterons les informations des inscrits à partir du sujet Pub/Sub et les conserverons dans la base de données Cloud MySQL. L'application sera alors terminée. Vous pourrez envoyer de nouveaux inscrits via le formulaire et afficher tous les utilisateurs enregistrés via le point de terminaison /registrants.
Cette application tirera parti de Spring Integration, qui offre de nombreuses abstractions pratiques pour la gestion des messages. Nous allons ajouter un PubSubInboundChannelAdapter pour pouvoir lire les messages du sujet Pub/Sub et les placer sur le pubsubInputChannel pour un traitement ultérieur. Nous allons ensuite configurer la fonction messageReceiver à l'aide de @ServiceActivator pour qu'elle soit appelée avec les messages arrivant sur pubsubInputChannel.
src/main/kotlin/com/example/demo/DemoApplication.kt
package com.example.demo
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean
import com.fasterxml.jackson.databind.ObjectMapper
import org.springframework.cloud.gcp.pubsub.support.converter.JacksonPubSubMessageConverter
// new imports to add
import com.google.cloud.spring.pubsub.core.PubSubTemplate
import com.google.cloud.spring.pubsub.integration.AckMode
import com.google.cloud.spring.pubsub.integration.inbound.PubSubInboundChannelAdapter
import com.google.cloud.spring.pubsub.support.BasicAcknowledgeablePubsubMessage
import com.google.cloud.spring.pubsub.support.GcpPubSubHeaders
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.integration.annotation.ServiceActivator
import org.springframework.integration.channel.DirectChannel
import org.springframework.messaging.MessageChannel
import org.springframework.messaging.handler.annotation.Header
@SpringBootApplication
class DemoApplication {
private val REGISTRANT_SUBSCRIPTION = "registrations-sub"
@Autowired
private lateinit var personRepository: PersonRepository
// New Spring Beans to add
@Bean
fun pubsubInputChannel() = DirectChannel()
@Bean
fun messageChannelAdapter(
@Qualifier("pubsubInputChannel") inputChannel: MessageChannel,
pubSubTemplate: PubSubTemplate): PubSubInboundChannelAdapter {
val adapter = PubSubInboundChannelAdapter(
pubSubTemplate, REGISTRANT_SUBSCRIPTION)
adapter.outputChannel = inputChannel
adapter.ackMode = AckMode.MANUAL
adapter.payloadType = Person::class.java
return adapter
}
@ServiceActivator(inputChannel = "pubsubInputChannel")
fun messageReceiver(
payload: Person,
@Header(GcpPubSubHeaders.ORIGINAL_MESSAGE) message: BasicAcknowledgeablePubsubMessage) {
personRepository.save(payload)
print("Message arrived! Payload: $payload")
message.ack()
}
// ObjectMapper bean from previous step
@Bean
fun jacksonPubSubMessageConverter(objectMapper: ObjectMapper) = JacksonPubSubMessageConverter(objectMapper)
}
fun main(args: Array<String>) {
runApplication<DemoApplication>(*args)
}
À ce stade, vous avez terminé la configuration de l'application. Pour vérifier que l'application fonctionne correctement, exécutez la commande suivante :
$ ./mvnw spring-boot:run
Cliquez à nouveau sur le bouton Prévisualiser, puis essayez d'enregistrer un utilisateur en remplissant le formulaire et en l'envoyant.

Cliquez sur le lien Personnes inscrites pour vérifier que le nouvel inscrit figure dans le tableau.

Félicitations, vous avez terminé ! Arrêtez l'application en appuyant sur CTRL+C dans la fenêtre de terminal.
10. Nettoyage
Pour nettoyer votre environnement, vous devez supprimer le sujet Pub/Sub et l'instance Cloud MySQL que vous avez créés.
Supprimer l'instance Cloud MySQL
$ gcloud sql instances delete codelab-instance
Supprimer les ressources Pub/Sub
$ gcloud pubsub subscriptions delete registrations-sub $ gcloud pubsub topics delete registrations
11. Félicitations !
Vous avez terminé d'écrire une application Spring Kotlin qui s'intègre à Cloud Pub/Sub et Cloud SQL (MySQL).
En savoir plus
- Projet Spring sur GCP : http://cloud.spring.io/spring-cloud-gcp/
- Dépôt GitHub Spring on GCP : https://github.com/GoogleCloudPlatform/spring-cloud-gcp
- Java sur Google Cloud Platform : https://cloud.google.com/java/
- Exemples d'applications Kotlin utilisant GCP : https://github.com/GoogleCloudPlatform/spring-cloud-gcp/tree/master/spring-cloud-gcp-kotlin-samples
Licence
Ce document est publié sous une licence Creative Commons Attribution 2.0 Generic.