1. Pengantar
Spring Framework 5.0 menambahkan dukungan Kotlin khusus yang memudahkan developer Kotlin menggunakan Spring. Akibatnya, perubahan ini berarti bahwa integrasi Google Cloud yang disediakan oleh Spring Cloud GCP juga berfungsi dengan lancar di Kotlin. Dalam codelab ini, Anda akan melihat betapa mudahnya mulai menggunakan layanan Google Cloud di aplikasi Kotlin.
Codelab ini memandu penyiapan aplikasi pendaftaran sederhana di Kotlin yang mendemonstrasikan penggunaan layanan GCP, termasuk: Cloud Pub/Sub dan Cloud SQL.
Yang akan Anda build
Dalam codelab ini, Anda akan menyiapkan aplikasi Kotlin Spring Boot yang menerima informasi pendaftar, memublikasikannya ke topik Cloud Pub/Sub, dan mempertahankannya ke database Cloud MySQL.
Yang akan Anda pelajari
Cara berintegrasi dengan layanan Google Cloud di aplikasi Kotlin Spring.
Yang Anda butuhkan
- Project Google Cloud Platform
- Browser, seperti Chrome atau Firefox
Bagaimana Anda akan menggunakan tutorial ini?
Bagaimana Anda menilai pengalaman Anda membuat aplikasi web HTML/CSS?
Bagaimana penilaian Anda terhadap pengalaman menggunakan layanan Google Cloud Platform?
2. Penyiapan dan Persyaratan
Penyiapan lingkungan mandiri
- Login ke Cloud Console dan buat project baru atau gunakan kembali project yang sudah ada. (Jika belum memiliki akun Gmail atau G Suite, Anda harus membuatnya.)
Ingat project ID, nama unik di semua project Google Cloud (maaf, nama di atas telah digunakan dan tidak akan berfungsi untuk Anda!) Project ID tersebut selanjutnya akan dirujuk di codelab ini sebagai PROJECT_ID
.
- Selanjutnya, Anda harus mengaktifkan penagihan di Cloud Console untuk menggunakan resource Google Cloud.
Menjalankan operasi dalam codelab ini seharusnya tidak memerlukan banyak biaya, bahkan mungkin tidak sama sekali. Pastikan untuk mengikuti petunjuk yang ada di bagian "Membersihkan" yang memberi tahu Anda cara menonaktifkan resource sehingga tidak menimbulkan penagihan di luar tutorial ini. Pengguna baru Google Cloud memenuhi syarat untuk mengikuti program Uji Coba Gratis senilai $300 USD.
Google Cloud Shell
Meskipun Google Cloud dapat dioperasikan secara jarak jauh dari laptop Anda, dalam codelab ini kita akan menggunakan Google Cloud Shell, yakni lingkungan command line yang berjalan di Cloud.
Mengaktifkan Cloud Shell
- Dari Cloud Console, klik Aktifkan Cloud Shell .
Jika belum pernah memulai Cloud Shell, Anda akan melihat layar perantara (di paruh bawah) yang menjelaskan apa itu Cloud Shell. Jika demikian, klik Lanjutkan (dan Anda tidak akan pernah melihatnya lagi). Berikut tampilan layar sekali-tampil tersebut:
Perlu waktu beberapa saat untuk penyediaan dan terhubung ke Cloud Shell.
Mesin virtual ini berisi semua alat pengembangan yang Anda perlukan. Layanan ini menawarkan direktori beranda tetap sebesar 5 GB dan beroperasi di Google Cloud, sehingga sangat meningkatkan performa dan autentikasi jaringan. Sebagian besar pekerjaan Anda dalam codelab ini dapat dilakukan hanya dengan browser atau Chromebook.
Setelah terhubung ke Cloud Shell, Anda akan melihat bahwa Anda sudah diautentikasi dan project sudah ditetapkan ke project ID Anda.
- Jalankan perintah berikut di Cloud Shell untuk mengonfirmasi bahwa Anda telah diautentikasi:
gcloud auth list
Output perintah
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 perintah
[core] project = <PROJECT_ID>
Jika tidak, Anda dapat menyetelnya dengan perintah ini:
gcloud config set project <PROJECT_ID>
Output perintah
Updated property [core/project].
3. Menyediakan resource Pub/Sub
Pertama, kita perlu menyiapkan topik dan langganan Cloud Pub/Sub. Dalam aplikasi ini, kami akan memublikasikan info pendaftaran ke topik Pub/Sub; informasi kemudian dibaca dari topik ini dan disimpan di {i>database<i}.
Dalam tutorial ini, kita akan mengandalkan Cloud Shell untuk menyediakan resource. Perlu diperhatikan bahwa Anda juga dapat mengonfigurasi resource Pub/Sub melalui bagian Cloud Pub/Sub di Konsol Google Cloud.
Di terminal Cloud Shell Anda, aktifkan Pub/Sub API terlebih dahulu.
$ gcloud services enable pubsub.googleapis.com
Selanjutnya, kita akan membuat topik Pub/Sub bernama registrations
untuk aplikasi ini. Informasi pendaftaran yang dikirimkan melalui pendaftaran akan dipublikasikan untuk topik ini.
$ gcloud pubsub topics create registrations
Terakhir, buat langganan untuk topik tersebut. Langganan Pub/Sub memungkinkan Anda menerima pesan dari suatu topik.
$ gcloud pubsub subscriptions create registrations-sub --topic=registrations
Sekarang Anda telah selesai membuat topik dan langganan Cloud Pub/Sub untuk aplikasi.
4. Membuat Instance dan Database Cloud SQL (MySQL)
Untuk aplikasi contoh, kita juga perlu menyiapkan instance database untuk menyimpan informasi pendaftar. Langkah ini juga akan bergantung pada terminal Cloud Shell untuk menyediakan resource Cloud SQL. Perlu diperhatikan bahwa Anda juga dapat melihat dan mengonfigurasi instance Cloud SQL melalui Konsol Google Cloud.
Pertama, aktifkan Cloud SQL Admin API.
$ gcloud services enable sqladmin.googleapis.com
Selanjutnya, kita akan menyediakan instance Cloud SQL (MySQL). Perintah ini mungkin memerlukan waktu beberapa saat.
$ gcloud sql instances create codelab-instance --region=us-east1
Setelah berhasil membuat instance Cloud SQL, buat database baru dalam instance Anda yang diberi nama registrants
.
$ gcloud sql databases create registrants --instance codelab-instance
Anda kini telah menyelesaikan penyiapan instance dan database Cloud SQL untuk aplikasi Anda.
5. Melakukan inisialisasi Aplikasi Spring Boot
Sekarang kami siap untuk mulai menulis permohonan. Langkah berikutnya akan terus menggunakan Cloud Shell yang dijelaskan dalam langkah penyiapan.
Pertama, kita akan menggunakan Initializr untuk membuat kode scaffolding untuk project. Di jendela Cloud Shell, jalankan:
$ 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
Perintah ini menghasilkan penyiapan project Maven awal serta kode scaffolding untuk aplikasi Anda di direktori registrations-codelab/
. Bagian berikut ini menjelaskan pengeditan kode yang diperlukan untuk menghasilkan aplikasi yang berfungsi.
Editor Kode Cloud Shell
Cara termudah untuk mulai memodifikasi dan melihat kode di lingkungan Cloud Shell adalah menggunakan Cloud Shell Code Editor bawaan.
Setelah Anda membuka instance Cloud Shell, klik ikon Pensil untuk membuka editor kode. Editor harus memungkinkan Anda untuk langsung memodifikasi file project yang dihasilkan oleh Initialzr.
6. Konfigurasi Database
Pertama, konfigurasikan aplikasi Anda agar dapat terhubung ke database Cloud MySQL yang Anda siapkan. Library GCP Spring Cloud menawarkan starter Cloud MySQL yang menyediakan dependensi yang diperlukan untuk terhubung ke instance Cloud MySQL.
Tambahkan dependensi spring-cloud-gcp-starter-sql-mysql
ke project 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>
Selain itu, Anda perlu memodifikasi file konfigurasi application.properties
untuk mendeskripsikan konfigurasi database Anda. Salin properti berikut ke dalam file application.properties
Anda.
Temukan nama koneksi instance ke database Anda:
$ gcloud sql instances describe codelab-instance \ --format 'value(connectionName)'
Output ini akan digunakan dalam file application.properties
untuk mengonfigurasi informasi koneksi.
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
Satu-satunya properti yang harus Anda ubah adalah nama koneksi instance. Nilai ini harus diformat sebagai nilai yang dipisahkan titik dua dengan bentuk: YOUR_GCP_PROJECT_ID:REGION:DATABASE_INSTANCE_NAME
.
7. Membuat Konten Statis
Pertama, kita akan membuat frontend untuk aplikasi. Permohonan harus memiliki formulir yang memungkinkan seseorang mendaftarkan individu serta tampilan yang menampilkan semua pendaftar yang berhasil.
Untuk halaman beranda, buat index.html
yang berisi formulir pendaftaran.
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>
Selanjutnya, kita akan membuat template Thymeleaf bernama registrants.html
untuk menampilkan pengguna yang terdaftar. Thymeleaf adalah kerangka kerja {i>template<i} yang kita gunakan untuk membangun dan menyajikan HTML yang dibuat secara dinamis. Anda akan melihat bahwa template terlihat seperti HTML, tetapi memiliki beberapa elemen markdown tambahan untuk menangani konten dinamis. Template ini menerima satu parameter yang disebut personsList
yang berisi semua pendaftar yang terdaftar melalui aplikasi.
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>
Pada tahap ini, Anda dapat memverifikasi bahwa konten statis sedang disajikan.
Bangun dan jalankan aplikasi menggunakan Maven:
$ ./mvnw spring-boot:run
Klik tombol pratinjau di jendela Cloud Shell dan pastikan Anda melihat halaman beranda sedang dirender. Namun, tidak ada fungsi di UI yang akan berfungsi karena kita tidak memiliki pengontrol web. Ini akan ditambahkan di langkah berikutnya.
Setelah melihat pratinjau aplikasi, tekan CTRL+C
untuk menghentikan aplikasi.
8. Mengirim Pendaftar ke Topik Pub/Sub
Pada langkah ini, kita akan menerapkan fitur yang memungkinkan pendaftar yang dikirim melalui formulir web akan dipublikasikan ke topik Cloud Pub/Sub.
Menambahkan Class Data
Pertama, kita akan membuat beberapa class data Kotlin; ini akan menjadi entitas JPA kami dan juga bertindak sebagai representasi perantara kami dari pendaftar yang dikirimkan melalui formulir.
Di paket demo, tambahkan dua file baru: class Person
dan PersonRepository
Data Spring. Kedua class ini akan memungkinkan kita untuk menyimpan dan mengambil entri pendaftaran dari database MySQL dengan mudah menggunakan 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>
Menambahkan Pengontrol Web
Selanjutnya, kita akan membuat class Pengontrol yang memproses pendaftar dari formulir dan mengirimkan informasi ke topik Cloud Pub/Sub yang Anda buat sebelumnya. Pengontrol ini membuat dua endpoint:
/registerPerson
: Endpoint POST tempat info pendaftar dikirimkan lalu dikirim ke topik Pub/Sub. Dalam fungsiregisterPerson(..)
, info pendaftar dikirim ke topik Pub/Sub menggunakanPubSubTemplate
, class praktis dari integrasi Spring Cloud GCP Pub/Sub yang meminimalkan kode boilerplate yang diperlukan untuk mulai berinteraksi dengan Cloud Pub/Sub./registrants
: Menampilkan semua pendaftar yang berhasil didaftarkan dalam database. Informasi ini diambil dari instance MySQL menggunakan repositori Spring Data yang kita buat di langkah sebelumnya.
Buat class Pengontrol berikut dalam paket 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))
}
}
Pengontrol membaca informasi pendaftar yang dikirim melalui formulir web, lalu memublikasikan informasi tersebut ke topik Pub/Sub.
Menambahkan Mapper Bean Objek JSON
Anda mungkin telah melihat di Pengontrol bahwa kita memublikasikan objek Person
ke topik Pub/Sub, bukan String. Hal ini memungkinkan karena kami memanfaatkan dukungan Spring Cloud GCP untuk payload JSON kustom yang akan dikirim ke topik - library memungkinkan Anda melakukan serialisasi objek ke JSON, mengirim payload JSON ke sebuah topik, dan melakukan deserialisasi payload saat diterima.
Untuk memanfaatkan fitur ini, kita harus menambahkan bean ObjectMapper
ke konteks aplikasi Anda. Kacang ObjectMapper
ini akan digunakan untuk membuat serialisasi objek ke dan dari JSON saat aplikasi Anda mengirim dan menerima pesan. Di class DemoApplication.kt
, tambahkan JacksonPubSubMessageConverter
Spring bean:
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)
}
Pada tahap ini, Anda dapat mencoba menjalankan aplikasi lagi dengan menjalankan:
$ ./mvnw spring-boot:run
Dari formulir web di halaman utama, aplikasi kini akan mengirimkan informasi ke topik Pub/Sub yang Anda buat. Namun, hal tersebut masih belum membantu karena kita masih perlu membaca dari topik Pub/Sub tersebut. Hal ini dilakukan pada langkah berikutnya.
9. Membaca Pendaftar dari Topik Pub/Sub
Pada langkah terakhir, kami akan memproses info pendaftar dari topik Pub/Sub dan mempertahankan informasi ke database Cloud MySQL. Langkah ini akan menyelesaikan permohonan, sehingga Anda dapat mengirimkan pendaftar baru melalui formulir dan melihat semua pengguna yang terdaftar melalui endpoint /registrants
.
Aplikasi ini akan memanfaatkan Integrasi Spring, yang menawarkan banyak abstraksi praktis untuk menangani pesan. Kita akan menambahkan PubSubInboundChannelAdapter
agar kita dapat membaca pesan dari topik Pub/Sub dan menempatkannya di pubsubInputChannel
untuk diproses lebih lanjut. Kemudian, kita akan mengonfigurasi fungsi messageReceiver
menggunakan @ServiceActivator
agar dipanggil dengan pesan yang tiba di 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)
}
Pada tahap ini, Anda telah menyelesaikan penyiapan untuk aplikasi. Untuk memverifikasi bahwa aplikasi berfungsi dengan baik, jalankan:
$ ./mvnw spring-boot:run
Klik tombol Preview lagi dan coba daftarkan pengguna dengan mengisi formulir dan mengirimkannya.
Klik link Orang Terdaftar untuk memverifikasi bahwa pendaftar baru muncul dalam tabel.
Selamat, Anda sudah selesai! Hentikan aplikasi dengan menekan CTRL+C
di jendela terminal.
10. Pembersihan
Untuk membersihkan lingkungan, Anda perlu menghapus topik Pub/Sub dan instance Cloud MySQL yang Anda buat.
Menghapus Instance Cloud MySQL
$ gcloud sql instances delete codelab-instance
Menghapus Resource Pub/Sub
$ gcloud pubsub subscriptions delete registrations-sub $ gcloud pubsub topics delete registrations
11. Selamat!
Anda kini telah selesai menulis aplikasi Spring Kotlin yang terintegrasi dengan Cloud Pub/Sub dan Cloud SQL (MySQL).
Pelajari Lebih Lanjut
- Project musim semi di GCP: http://cloud.spring.io/spring-cloud-gcp/
- Repositori GitHub Spring di GCP: https://github.com/GoogleCloudPlatform/spring-cloud-gcp
- Java di Google Cloud Platform: https://cloud.google.com/java/
- Contoh Aplikasi Kotlin yang menggunakan GCP: https://github.com/GoogleCloudPlatform/spring-cloud-gcp/tree/master/spring-cloud-gcp-kotlin-samples
Lisensi
Karya ini dilisensikan berdasarkan Lisensi Umum Creative Commons Attribution 2.0.