1. Introduzione
Il framework 5.0 di Spring ha aggiunto il supporto dedicato a Kotlin semplificando l'utilizzo di Spring da parte degli sviluppatori di Kotlin. Di conseguenza, queste modifiche hanno fatto sì che le integrazioni di Google Cloud fornite da Spring Cloud GCP funzionino perfettamente anche in Kotlin. In questo codelab scoprirai quanto è facile iniziare a utilizzare i servizi Google Cloud nelle applicazioni Kotlin.
Questo codelab illustra la configurazione di una semplice applicazione di registrazione in Kotlin che dimostra l'utilizzo dei servizi Google Cloud, tra cui Cloud Pub/Sub e Cloud SQL.
Cosa creerai
In questo codelab, configurerai un'applicazione Kotlin Spring Boot che accetta le informazioni sul registrante, le pubblica in un argomento Cloud Pub/Sub e le rende persistenti in un database Cloud MySQL.
Cosa imparerai a fare
Come eseguire l'integrazione con i servizi Google Cloud nella tua applicazione Kotlin Spring.
Che cosa ti serve
- Un progetto Google Cloud
- Un browser, ad esempio Chrome o Firefox
Come utilizzerai questo tutorial?
Come valuteresti la tua esperienza nello sviluppo di app web HTML/CSS?
Come giudichi la tua esperienza di utilizzo dei servizi della piattaforma Google Cloud?
2. Configurazione e requisiti
Configurazione dell'ambiente da seguire in modo autonomo
- Accedi alla console Cloud e crea un nuovo progetto o riutilizzane uno esistente. Se non hai ancora un account Gmail o G Suite, devi crearne uno.
Ricorda l'ID progetto, un nome univoco in tutti i progetti Google Cloud (il nome precedente è già stato utilizzato e non funzionerà correttamente). Verrà indicato più avanti in questo codelab come PROJECT_ID
.
- Successivamente, dovrai abilitare la fatturazione in Cloud Console per utilizzare le risorse Google Cloud.
Eseguire questo codelab non dovrebbe costare molto. Assicurati di seguire le istruzioni nella sezione "Pulizia" in cui viene spiegato come arrestare le risorse in modo da non incorrere in fatturazione oltre questo tutorial. I nuovi utenti di Google Cloud sono idonei al programma prova senza costi di 300$.
Google Cloud Shell
Anche se Google Cloud può essere utilizzato da remoto dal tuo laptop, in questo codelab utilizzeremo Google Cloud Shell, un ambiente a riga di comando in esecuzione nel cloud.
Attiva Cloud Shell
- Dalla console Cloud, fai clic su Attiva Cloud Shell .
Se non hai mai avviato Cloud Shell, ti verrà mostrata una schermata intermedia (below the fold) in cui viene illustrato di cosa si tratta. In tal caso, fai clic su Continua (e non la vedrai più). Ecco come appare quella singola schermata:
Il provisioning e la connessione a Cloud Shell dovrebbero richiedere solo qualche istante.
Questa macchina virtuale viene caricata con tutti gli strumenti di sviluppo necessari. Offre una home directory permanente da 5 GB e viene eseguita in Google Cloud, migliorando notevolmente le prestazioni di rete e l'autenticazione. Gran parte, se non tutto, del lavoro in questo codelab può essere svolto semplicemente con un browser o Chromebook.
Una volta eseguita la connessione a Cloud Shell, dovresti vedere che il tuo account è già autenticato e il progetto è già impostato sul tuo ID progetto.
- Esegui questo comando in Cloud Shell per verificare che l'account sia autenticato:
gcloud auth list
Output comando
Credentialed Accounts ACTIVE ACCOUNT * <my_account>@<my_domain.com> To set the active account, run: $ gcloud config set account `ACCOUNT`
gcloud config list project
Output comando
[core] project = <PROJECT_ID>
In caso contrario, puoi impostarlo con questo comando:
gcloud config set project <PROJECT_ID>
Output comando
Updated property [core/project].
3. Esegui il provisioning delle risorse Pub/Sub
Per prima cosa, dovremo configurare un argomento e una sottoscrizione Cloud Pub/Sub. In questa applicazione pubblicheremo le informazioni di registrazione in un argomento Pub/Sub. le informazioni vengono quindi lette da questo argomento e rese persistenti in un database.
In questo tutorial ci affideremo a Cloud Shell per eseguire il provisioning delle risorse. Tieni presente che è possibile configurare le risorse Pub/Sub anche tramite la sezione Cloud Pub/Sub della console Google Cloud.
Nel terminale Cloud Shell, abilita prima l'API Pub/Sub.
$ gcloud services enable pubsub.googleapis.com
Quindi creeremo un argomento Pub/Sub denominato registrations
per questa applicazione. Le informazioni di registrazione inviate tramite la richiesta verranno pubblicate in questo argomento.
$ gcloud pubsub topics create registrations
Infine, crea una sottoscrizione per l'argomento. Una sottoscrizione Pub/Sub consente di ricevere messaggi da un argomento.
$ gcloud pubsub subscriptions create registrations-sub --topic=registrations
Hai completato la creazione di un argomento e di una sottoscrizione Cloud Pub/Sub per la tua applicazione.
4. Crea un'istanza e un database Cloud SQL (MySQL)
Per la nostra applicazione di esempio, dobbiamo anche configurare un'istanza di database per contenere le informazioni del registrante. Questo passaggio si baserà anche sul terminale Cloud Shell per il provisioning delle risorse Cloud SQL. Tieni presente che puoi visualizzare e configurare le istanze Cloud SQL anche tramite la console Google Cloud.
Abilita anzitutto l'API Cloud SQL Admin.
$ gcloud services enable sqladmin.googleapis.com
Successivamente, eseguiremo il provisioning di un'istanza Cloud SQL (MySQL). L'esecuzione del comando potrebbe richiedere del tempo.
$ gcloud sql instances create codelab-instance --region=us-east1
Dopo aver creato correttamente l'istanza Cloud SQL, crea un nuovo database nell'istanza denominato registrants
.
$ gcloud sql databases create registrants --instance codelab-instance
Hai completato la configurazione dell'istanza e del database Cloud SQL per la tua applicazione.
5. Inizializzare un'applicazione di avvio a molla
Ora siamo pronti per iniziare a scrivere la tua richiesta. I passaggi successivi continueranno a utilizzare Cloud Shell descritto nei passaggi di configurazione.
In primo luogo, utilizzeremo Initializr per generare il codice di scaffolding per il progetto. Nella finestra di Cloud Shell, esegui:
$ 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
Questo comando genera una configurazione iniziale del progetto Maven e un codice di scaffolding per la tua applicazione nella directory registrations-codelab/
. Le seguenti sezioni descrivono le modifiche al codice necessarie per produrre un'applicazione funzionante.
Editor di codice di Cloud Shell
Il modo più semplice per iniziare a modificare e visualizzare il codice nell'ambiente Cloud Shell è utilizzare l'editor di codice Cloud Shell integrato.
Dopo aver aperto un'istanza di Cloud Shell, fai clic sull'icona a forma di matita per aprire l'editor di codice. L'editor dovrebbe consentirti di modificare direttamente i file di progetto prodotti da Initialzr.
6. Configurazione per database
Per prima cosa, configura l'applicazione in modo che possa connettersi al database Cloud MySQL che hai impostato. Le librerie Spring Cloud Google Cloud offrono un comando iniziale di Cloud MySQL che fornisce le dipendenze necessarie per la connessione a un'istanza Cloud MySQL.
Aggiungi la dipendenza spring-cloud-gcp-starter-sql-mysql
al progetto pom.xml:
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>
Inoltre, devi modificare il file di configurazione application.properties
per descrivere la configurazione del database. Copia le seguenti proprietà nel file application.properties
.
Trova il nome della connessione dell'istanza al tuo database:
$ gcloud sql instances describe codelab-instance \ --format 'value(connectionName)'
Il relativo output verrà utilizzato nel file application.properties
per configurare le informazioni di connessione.
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
L'unica proprietà che devi modificare è il nome connessione istanza. Questo valore deve essere formattato come valore separato da due punti con il formato: YOUR_GCP_PROJECT_ID:REGION:DATABASE_INSTANCE_NAME
.
7. Creazione dei contenuti statici
Innanzitutto, creeremo il frontend per la nostra applicazione. L'applicazione deve contenere un modulo che consenta a qualcuno di registrare individui e una visualizzazione che mostri tutti gli iscritti che hanno ottenuto l'accesso.
Per la home page, crea un elemento index.html
contenente il modulo di registrazione.
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>
Successivamente, creeremo un modello Thymeleaf denominato registrants.html
per mostrare gli utenti registrati. Thymeleaf è un framework di modelli che utilizziamo per costruire e pubblicare codice HTML creato in modo dinamico. Vedrai che il modello è simile all'HTML, ma ha alcuni elementi markdown aggiuntivi per gestire i contenuti dinamici. Questo modello accetta un singolo parametro denominato personsList
che contiene tutti i registranti registrati tramite l'applicazione.
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>
A questo punto, puoi verificare che i contenuti statici vengano pubblicati.
Crea ed esegui l'app utilizzando Maven:
$ ./mvnw spring-boot:run
Fai clic sul pulsante Anteprima nella finestra di Cloud Shell e verifica che la home page venga visualizzata. Tuttavia, nessuna delle funzionalità dell'interfaccia utente funzionerà perché manca un controller web. Verrà aggiunto nel passaggio successivo.
Dopo aver visualizzato in anteprima l'applicazione, premi CTRL+C
per terminarla.
8. Invio dei registrant a un argomento Pub/Sub
In questo passaggio, implementeremo la funzionalità in cui i registranti inviati tramite il modulo web verranno pubblicati in un argomento Cloud Pub/Sub.
Aggiungere le classi di dati
Per prima cosa creeremo alcune classi di dati Kotlin; queste saranno le nostre entità JPA e fungono anche da rappresentazione intermedia dei registranti inviati tramite il modulo.
Nel pacchetto dimostrativo, aggiungi due nuovi file: una classe Person
e un PersonRepository
di Spring Data. Queste due classi ci consentiranno di archiviare e recuperare facilmente le voci di registrazione dal nostro database MySQL utilizzando 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>
Aggiungi il controller web
Quindi, creeremo una classe Controller che elabora i registranti dal modulo e invia le informazioni all'argomento Cloud Pub/Sub che hai creato in precedenza. Questo controller crea due endpoint:
/registerPerson
: l'endpoint POST in cui le informazioni sul registrante vengono inviate e quindi inviate all'argomento Pub/Sub. Nella funzioneregisterPerson(..)
, le informazioni sul registrante vengono inviate all'argomento Pub/Sub utilizzandoPubSubTemplate
, una classe di convenienza delle integrazioni Pub/Sub di Cloud Google Cloud Spring che riduce al minimo il codice boilerplate necessario per iniziare a interagire con Cloud Pub/Sub./registrants
: mostra tutti i registranti registrati correttamente nel database. Queste informazioni vengono recuperate dall'istanza MySQL utilizzando il repository Spring Data creato nel passaggio precedente.
Crea la seguente classe Controller nel pacchetto demo:
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))
}
}
Il controller legge le informazioni sul registrante inviate tramite il modulo web e poi le pubblica nell'argomento Pub/Sub.
Aggiunta del bean di mappatura degli oggetti JSON
Potresti aver notato nel controller che pubblichiamo un oggetto Person
nell'argomento Pub/Sub e non una stringa. Questo è possibile perché sfruttiamo il supporto di Spring Cloud Google Cloud per l'invio di payload JSON personalizzati agli argomenti. Le librerie consentono di serializzare gli oggetti in JSON, inviare payload JSON a un argomento e deserializzare il payload quando viene ricevuto.
Per sfruttare questa funzionalità, dobbiamo aggiungere un bean ObjectMapper
al contesto della tua domanda. Questo bean ObjectMapper
verrà utilizzato per serializzare gli oggetti da e verso JSON quando l'applicazione invia e riceve messaggi. Nella classe DemoApplication.kt
, aggiungi il fagiolo a molla 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)
}
A questo punto, puoi provare a eseguire nuovamente l'applicazione eseguendo:
$ ./mvnw spring-boot:run
Dal modulo web nella pagina principale, l'applicazione invierà le informazioni all'argomento Pub/Sub che hai creato. Tuttavia, non sta ancora facendo nulla di utile perché dobbiamo ancora leggere da quell'argomento Pub/Sub. Questa operazione viene eseguita nel passaggio successivo.
9. Lettura dei registranti dall'argomento Pub/Sub
Nel passaggio finale, elaboreremo le informazioni sul registrante dell'argomento Pub/Sub e le renderemo persistenti nel database Cloud MySQL. Questa operazione completerà la domanda, consentendoti di inviare nuovi iscritti tramite il modulo e di visualizzare tutti gli utenti registrati attraverso l'endpoint /registrants
.
Questa applicazione sfrutta Spring Integration, che offre molte utili astrazioni per la gestione dei messaggi. Aggiungeremo un PubSubInboundChannelAdapter
per consentirci di leggere i messaggi dell'argomento Pub/Sub e inserirli nella pubsubInputChannel
per un'ulteriore elaborazione. Configureremo quindi la funzione messageReceiver
utilizzando @ServiceActivator
affinché venga richiamata con i messaggi in arrivo su 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)
}
A questo punto, hai completato la configurazione dell'applicazione. Per verificare che l'app funzioni correttamente, esegui:
$ ./mvnw spring-boot:run
Fai di nuovo clic sul pulsante Anteprima e prova a registrare un utente compilando il modulo e inviandolo.
Fai clic sul link Persone registrate per verificare che il nuovo registrante sia visualizzato nella tabella.
Congratulazioni, hai terminato. Termina l'applicazione premendo CTRL+C
nella finestra del terminale.
10. Esegui la pulizia
Per ripulire il tuo ambiente, devi eliminare l'argomento Pub/Sub e l'istanza Cloud MySQL che hai creato.
Eliminazione dell'istanza Cloud MySQL
$ gcloud sql instances delete codelab-instance
Eliminazione delle risorse Pub/Sub
$ gcloud pubsub subscriptions delete registrations-sub $ gcloud pubsub topics delete registrations
11. Complimenti!
Hai completato la scrittura di un'applicazione Spring Kotlin che si integra con Cloud Pub/Sub e Cloud SQL (MySQL).
Scopri di più
- Spring sul progetto Google Cloud: http://cloud.spring.io/spring-cloud-gcp/
- Repository GitHub di Google Cloud Spring: https://github.com/GoogleCloudPlatform/spring-cloud-gcp
- Java su Google Cloud: https://cloud.google.com/java/
- Esempi di applicazioni Kotlin con Google Cloud: https://github.com/GoogleCloudPlatform/spring-cloud-gcp/tree/master/spring-cloud-gcp-kotlin-samples
Licenza
Questo lavoro è concesso in licenza ai sensi di una licenza Creative Commons Attribution 2.0 Generic.