1. Giriş
Spring Framework 5.0'a özel Kotlin desteği eklendi. Böylece, Kotlin geliştiricilerinin Spring'i kullanmaları kolaylaştı. Sonuç olarak bu değişiklikler, Spring Cloud GCP tarafından sağlanan Google Cloud entegrasyonlarının Kotlin'de de sorunsuz çalışmasını sağladı. Bu codelab'de, Kotlin uygulamalarınızda Google Cloud hizmetlerini kullanmaya başlamanın ne kadar kolay olduğunu göreceksiniz.
Bu codelab'de, Cloud Pub/Sub ve Cloud SQL gibi GCP hizmetlerinin kullanımını gösteren, Kotlin'de basit bir kayıt uygulamasının nasıl ayarlanacağı adım adım açıklanmıştır.
Neler oluşturacaksınız?
Bu codelab'de kaydedenin bilgilerini kabul eden, bunu bir Cloud Pub/Sub konusuna yayınlayan ve Cloud MySQL veritabanında devam ettiren bir Kotlin Spring Boot uygulaması kuracaksınız.
Neler öğreneceksiniz?
Kotlin Spring uygulamanızda Google Cloud hizmetleriyle entegrasyon.
İhtiyacınız olanlar
- Bir Google Cloud Platform Projesi
- Chrome veya Firefox gibi bir tarayıcı
Bu eğiticiden nasıl yararlanacaksınız?
HTML/CSS web uygulamaları oluşturma deneyiminizi nasıl değerlendirirsiniz?
Google Cloud Platform hizmetlerinin kullanımıyla ilgili deneyiminizi nasıl değerlendirirsiniz?
2. Kurulum ve Gereksinimler
Kendi hızınızda ortam kurulumu
- Cloud Console'da oturum açıp yeni bir proje oluşturun veya mevcut bir projeyi yeniden kullanın. (Gmail veya G Suite hesabınız yoksa hesap oluşturmanız gerekir.)
Tüm Google Cloud projelerinde benzersiz bir ad olan proje kimliğini unutmayın (yukarıdaki ad zaten alınmış ve size uygun olmayacaktır!). Bu kod laboratuvarın ilerleyen bölümlerinde PROJECT_ID
olarak adlandırılacaktır.
- Sonraki adımda, Google Cloud kaynaklarını kullanmak için Cloud Console'da faturalandırmayı etkinleştirmeniz gerekir.
Bu codelab'i çalıştırmanın maliyeti, yüksek değildir. "Temizleme" bölümündeki talimatları izlediğinizden emin olun. bölümünde, bu eğiticinin dışında faturalandırmayla karşılaşmamanız için kaynakları nasıl kapatacağınız konusunda tavsiyelerde bulunuyoruz. Yeni Google Cloud kullanıcıları 300 ABD doları ücretsiz deneme programından yararlanabilir.
Google Cloud Shell
Google Cloud dizüstü bilgisayarınızdan uzaktan çalıştırılabilse de bu codelab'de, Cloud'da çalışan bir komut satırı ortamı olan Google Cloud Shell'i kullanacağız.
Cloud Shell'i etkinleştirme
- Cloud Console'da, Cloud Shell'i etkinleştir simgesini tıklayın.
Cloud Shell'i daha önce hiç çalıştırmadıysanız ne olduğunu açıklayan bir ara ekran (ekranın alt kısmında) gösterilir. Bu durumda Devam'ı tıklayın (bunu bir daha görmezsiniz). Tek seferlik ekran şöyle görünür:
Temel hazırlık ve Cloud Shell'e bağlanmak yalnızca birkaç dakika sürer.
İhtiyacınız olan tüm geliştirme araçlarını bu sanal makinede bulabilirsiniz. 5 GB boyutunda kalıcı bir ana dizin sunar ve Google Cloud'da çalışarak ağ performansını ve kimlik doğrulamasını büyük ölçüde iyileştirir. Bu codelab'deki çalışmalarınızın tamamı olmasa bile büyük bir kısmı yalnızca bir tarayıcı veya Chromebook'unuzla yapılabilir.
Cloud Shell'e bağlandıktan sonra kimliğinizin doğrulandığını ve projenin proje kimliğinize ayarlandığını görürsünüz.
- Kimlik doğrulamanızın tamamlandığını onaylamak için Cloud Shell'de aşağıdaki komutu çalıştırın:
gcloud auth list
Komut çıkışı
Credentialed Accounts ACTIVE ACCOUNT * <my_account>@<my_domain.com> To set the active account, run: $ gcloud config set account `ACCOUNT`
gcloud config list project
Komut çıkışı
[core] project = <PROJECT_ID>
Doğru değilse aşağıdaki komutla ayarlayabilirsiniz:
gcloud config set project <PROJECT_ID>
Komut çıkışı
Updated property [core/project].
3. Pub/Sub kaynaklarının temel hazırlığını yapma
Öncelikle bir Cloud Pub/Sub konusu ve aboneliği oluşturmamız gerekiyor. Bu uygulamada kayıt bilgilerini bir Pub/Sub konusuna yayınlayacağız; bilgiler daha sonra bu konudan okunur ve bir veritabanında saklanır.
Bu eğiticide kaynaklarımızı sağlamak için Cloud Shell'den yararlanacağız. Pub/Sub kaynaklarını Google Cloud Console'daki Cloud Pub/Sub bölümünden de yapılandırabileceğinizi unutmayın.
Cloud Shell terminalinizde önce Pub/Sub API'yi etkinleştirin.
$ gcloud services enable pubsub.googleapis.com
Daha sonra, bu uygulama için registrations
adında bir Pub/Sub konusu oluşturacağız. Başvuru üzerinden gönderilen kayıt bilgileri bu konuda yayınlanacak.
$ gcloud pubsub topics create registrations
Son olarak, konu için bir abonelik oluşturun. Pub/Sub aboneliği, bir konudan mesaj almanıza olanak tanır.
$ gcloud pubsub subscriptions create registrations-sub --topic=registrations
Uygulamanız için Cloud Pub/Sub konusu ve aboneliği oluşturmayı tamamladınız.
4. Cloud SQL (MySQL) Örneği ve Veritabanı Oluşturma
Örnek uygulamamız için kaydedenin bilgilerini saklayacak bir veritabanı örneği de oluşturmamız gerekir. Bu adımda Cloud SQL kaynaklarının sağlanması için Cloud Shell terminali de kullanılır. Cloud SQL örneklerinizi Google Cloud Console üzerinden de görüntüleyip yapılandırabileceğinizi unutmayın.
Öncelikle Cloud SQL Admin API'yi etkinleştirin.
$ gcloud services enable sqladmin.googleapis.com
Şimdi de Cloud SQL (MySQL) örneğinin temel hazırlığını yapacağız. Bu komut biraz zaman alabilir.
$ gcloud sql instances create codelab-instance --region=us-east1
Cloud SQL örneğinizi başarıyla oluşturduktan sonra, örneğinizde registrants
adlı yeni bir veritabanı oluşturun.
$ gcloud sql databases create registrants --instance codelab-instance
Uygulamanızın Cloud SQL örneği ve veritabanı kurulumunu tamamladınız.
5. Spring Boot Uygulamasını Başlatma
Artık başvuruyu yazmaya hazırız. Sonraki adımlar, kurulum adımlarında açıklanan Cloud Shell'i kullanmaya devam edecek.
İlk olarak, İlkizr'i kullanarak projenin iskele kodunu oluşturacağız. Cloud Shell pencerenizde şu komutu çalıştırın:
$ 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
Bu komut, registrations-codelab/
dizininde uygulamanız için ilk Maven projesi kurulumunun yanı sıra yapı kodu oluşturur. Aşağıdaki bölümlerde, çalışan bir uygulama üretmek için gereken kod düzenlemeleri açıklanmaktadır.
Cloud Shell Kod Düzenleyici
Cloud Shell ortamında kodu değiştirmeye ve görüntülemeye başlamanın en kolay yolu yerleşik Cloud Shell Kod Düzenleyici'yi kullanmaktır.
Bir Cloud Shell örneği açtıktan sonra kod düzenleyiciyi açmak için Kalem simgesini tıklayın. Düzenleyici, Initialzr tarafından oluşturulan proje dosyalarını doğrudan değiştirmenize izin vermelidir.
6. Veritabanı Yapılandırması
İlk olarak, uygulamanızı, ayarladığınız Cloud MySQL veritabanına bağlanacak şekilde yapılandırın. Spring Cloud GCP kitaplıkları, Cloud MySQL örneğine bağlanmak için gerekli bağımlılıkları sağlayan bir Cloud MySQL başlatıcı sunar.
spring-cloud-gcp-starter-sql-mysql
bağımlılığını proje pom.xml dosyasına ekleyin:
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>
Ayrıca, veritabanı yapılandırmanızı tanımlamak için application.properties
yapılandırma dosyasını değiştirmeniz gerekir. Aşağıdaki özellikleri application.properties
dosyanıza kopyalayın.
Veritabanınızla ilişkili örnek bağlantısının adını bulun:
$ gcloud sql instances describe codelab-instance \ --format 'value(connectionName)'
Bunun çıkışı, bağlantı bilgilerini yapılandırmak için application.properties
dosyasında kullanılır.
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
Değiştirmeniz gereken tek özellik örnek bağlantı adıdır. Bu değer, şu biçimde iki nokta üst üste ile ayrılmış bir değer olarak biçimlendirilmelidir: YOUR_GCP_PROJECT_ID:REGION:DATABASE_INSTANCE_NAME
.
7. Statik İçerik Oluşturma
İlk olarak uygulamamız için ön ucu oluşturacağız. Başvuruda, kişilerin bireyleri kaydetmesine olanak tanıyan bir form ve tüm başarılı kayıt yaptıranların gösterildiği bir görünüm bulunmalıdır.
Ana sayfa için kayıt formunu içeren bir index.html
oluşturun.
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>
Ardından, kayıtlı kullanıcıları görüntülemek için registrants.html
adlı bir Thymeleaf şablonu oluşturacağız. Thymeleaf, dinamik olarak oluşturulmuş HTML'yi oluşturmak ve sunmak için kullandığımız bir şablon çerçevesidir. Şablonun HTML'ye benzediğini görürsünüz. Tek fark, dinamik içeriği işlemek için bazı ek Markdown öğelerine sahip olmasıdır. Bu şablonda, uygulama üzerinden kaydolan tüm kaydedenleri içeren personsList
adlı tek parametre kabul edilir.
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>
Bu noktada, statik içeriğin sunulduğunu doğrulayabilirsiniz.
Uygulamayı Maven kullanarak derleyin ve çalıştırın:
$ ./mvnw spring-boot:run
Cloud Shell penceresinde önizleme düğmesini tıklayın ve ana sayfanın oluşturulduğunu gördüğünüzden emin olun. Ancak web denetleyicisi olmadığı için kullanıcı arayüzündeki işlevlerin hiçbiri çalışmaz. Bu değer sonraki adımda eklenecektir.
Uygulamayı önizledikten sonra uygulamayı sonlandırmak için CTRL+C
tuşuna basın.
8. Kaydedenleri Pub/Sub Konusuna Gönderme
Bu adımda, web formu üzerinden gönderilen kayıt yaptıran kişilerin bir Cloud Pub/Sub konusunda yayınlanacağı bu özelliği uygulayacağız.
Veri Sınıflarını ekleme
İlk olarak bazı Kotlin veri sınıfları oluşturacağız. Bu tüzel kişiler JPA tüzel kişimizdir ve aynı zamanda form aracılığıyla gönderilen, kayıt yaptıran kullanıcıları temsil eden aracımızdır.
Demo paketine iki yeni dosya ekleyin: Person
sınıfı ve Spring Data PersonRepository
. Bu iki sınıf, Spring Data JPA'yı kullanarak MySQL veritabanımızdaki kayıt girişlerini kolayca depolamamızı ve almamızı sağlayacak.
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>
Web Denetleyicisi Ekleme
Şimdi, kayıt yaptıran kullanıcıları formdan işleyen ve bilgileri daha önce oluşturduğunuz Cloud Pub/Sub konusuna gönderen bir Denetleyici sınıfı oluşturacağız. Bu denetleyici iki uç nokta oluşturur:
/registerPerson
: Kaydeden bilgilerinin gönderilip Pub/Sub konusuna gönderildiği POST uç noktası.registerPerson(..)
işlevinde, kaydeden bilgileri Spring Cloud GCP Pub/Sub entegrasyonlarından sağlanan bir kolaylık sınıfı olanPubSubTemplate
kullanılarak Pub/Sub konusuna gönderilir. Bu işlem, Cloud Pub/Sub ile etkileşime geçmek için gereken ortak metin kodunu en aza indirir./registrants
: Veritabanına başarıyla kaydedilen tüm kaydedenleri gösterir. Bu bilgiler, önceki adımda oluşturduğumuz Spring Data deposu kullanılarak MySQL örneğinden alınır.
Demo paketinde aşağıdaki Denetleyici sınıfını oluşturun:
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))
}
}
Denetleyici, web formu aracılığıyla gönderilen kaydeden bilgilerini okur ve ardından bu bilgileri Pub/Sub konusuna yayınlar.
JSON Nesne Eşlemesi Bean'i ekleme
Denetleyici'de, Pub/Sub konusuna String yerine bir Person
nesnesi yayınladığımızı fark etmiş olabilirsiniz. Konulara gönderilecek özel JSON yükleri için Spring Cloud GCP desteğinden yararlandığımızdan bu mümkündür. Kitaplıklar nesneleri JSON'ye serileştirmenize, JSON yüklerini bir konuya göndermenize ve alındıktan sonra yükü seri durumdan çıkarmanıza olanak tanır.
Bu özellikten yararlanmak için uygulama bağlamınıza ObjectMapper
çekirdeği eklememiz gerekir. Bu ObjectMapper
çekirdeği, uygulamanız mesaj gönderip aldığında JSON'a gelen ve JSON'dan nesneleri serileştirmek için kullanılır. DemoApplication.kt
sınıfına, JacksonPubSubMessageConverter
Bahar fasulyesini ekleyin:
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)
}
Bu noktada, aşağıdaki komutu çalıştırarak uygulamayı çalıştırmayı tekrar deneyebilirsiniz:
$ ./mvnw spring-boot:run
Uygulama, ana sayfadaki web formundan bilgileri oluşturduğunuz Pub/Sub konusuna gönderir. Ancak yine de işe yaramıyor. Bu konuda hâlâ Pub/Sub konusundan okumamız gerekiyor. Bu işlem bir sonraki adımda gerçekleştirilir.
9. Pub/Sub Konusundan Kaydedenleri Okuma
Son adımda, Pub/Sub konusundan kaydeden bilgilerini işleyecek ve bu bilgileri Cloud MySQL veritabanında saklayacağız. Bu işlem sonucunda başvuru tamamlanır. Bu sayede, form aracılığıyla yeni kayıt yaptıran kullanıcılar gönderebilir ve kayıtlı tüm kullanıcıları /registrants
uç noktası üzerinden görüntüleyebilirsiniz.
Bu uygulama, mesajlarla çalışırken kullanabileceğiniz birçok pratik soyutlama sunan Spring Integration'dan yararlanacaktır. Pub/Sub konusundan mesajları okuyabilmemiz ve bunları daha fazla işlenmek üzere pubsubInputChannel
konumuna getirebilmemiz için bir PubSubInboundChannelAdapter
eklenecek. Ardından, pubsubInputChannel
tarihinde gelen mesajlarla çağrılacak @ServiceActivator
kullanarak messageReceiver
işlevini yapılandıracağız.
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)
}
Bu noktada, uygulamanın kurulumunu tamamlamış olursunuz. Uygulamanın düzgün çalıştığını doğrulamak için şu komutu çalıştırın:
$ ./mvnw spring-boot:run
Önizle düğmesini tekrar tıklayın ve formu doldurup göndererek bir kullanıcı kaydetmeyi deneyin.
Yeni kaydedenin tabloda göründüğünü doğrulamak için Kayıtlı Kişiler bağlantısını tıklayın.
Tebrikler, artık hazırsınız! Terminal penceresinde CTRL+C
tuşuna basarak uygulamayı sonlandırın.
10. Temizleme
Ortamınızı temizlemek için Pub/Sub konusunu ve oluşturduğunuz Cloud MySQL örneğini silmeniz gerekir.
Cloud MySQL Örneğini Silme
$ gcloud sql instances delete codelab-instance
Pub/Sub Kaynaklarını Silme
$ gcloud pubsub subscriptions delete registrations-sub $ gcloud pubsub topics delete registrations
11. Tebrikler!
Cloud Pub/Sub ve Cloud SQL (MySQL) ile entegre olan bir Spring Kotlin uygulaması yazmayı tamamladınız.
Daha Fazla Bilgi
- GCP projesinde ilkbahar: http://cloud.spring.io/spring-cloud-gcp/
- Spring'de GCP GitHub deposu: https://github.com/GoogleCloudPlatform/spring-cloud-gcp
- Google Cloud Platform'da Java: https://cloud.google.com/java/
- GCP'yi kullanan örnek Kotlin Uygulamaları: https://github.com/GoogleCloudPlatform/spring-cloud-gcp/tree/master/spring-cloud-gcp-kotlin-samples
Lisans
Bu çalışma, Creative Commons Attribution 2.0 Genel Amaçlı Lisans ile lisans altına alınmıştır.