إنشاء تطبيق Kotlin Spring باستخدام Google Cloud Platform

1. مقدمة

أضاف الإصدار 5.0 من Springr دعمًا مخصصًا للغة Kotlin، مما يسهّل على مطوري Kotlin استخدام Spring. وبالتالي، تعني هذه التغييرات أن عمليات دمج Google Cloud التي يوفّرها Spring Cloud GCP تعمل بسلاسة أيضًا في Kotlin. في هذا الدرس التطبيقي حول الترميز، ستتعرَّف على مدى سهولة بدء استخدام خدمات Google Cloud في تطبيقات Kotlin.

يرشدك هذا الدرس التطبيقي إلى خطوات إعداد تطبيق تسجيل بسيط في Kotlin والذي يوضّح استخدام خدمات GCP، بما في ذلك: Cloud Pub/Sub وCloud SQL.

ما الذي ستقوم ببنائه

في هذا الدرس التطبيقي حول الترميز، سيتم إعداد تطبيق Kotlin Spring Boot الذي يقبل معلومات صاحب التسجيل وينشرها في موضوع Cloud Pub/Sub ويحتفظ بها في قاعدة بيانات Cloud MySQL.

المُعطيات

كيف يمكن الدمج مع خدمات Google Cloud في تطبيق Kotlin Spring.

المتطلبات

  • مشروع Google Cloud Platform
  • متصفح، مثل Chrome أو Firefox

كيف ستستخدم هذا البرنامج التعليمي؟

القراءة فقط اقرأها وأكمِل التمارين

كيف تقيّم تجربتك في إنشاء تطبيقات ويب بتنسيق HTML/CSS؟

حديث متوسط بارع

ما هو تقييمك لتجربتك في استخدام خدمات Google Cloud Platform؟

حديث متوسط بارع

2. الإعداد والمتطلبات

إعداد بيئة ذاتية

  1. سجِّل الدخول إلى Cloud Console وأنشِئ مشروعًا جديدًا أو أعِد استخدام مشروع حالي. (إذا لم يكن لديك حساب على Gmail أو G Suite، عليك إنشاء حساب.)

dMbN6g9RawQj_VXCSYpdYncY-DbaRzr2GbnwoV7jFf1u3avxJtmGPmKpMYgiaMH-qu80a_NJ9p2IIXFppYk8x3wyymZXavjglNLJJhuXieCem56H30hwXtd8PvXGpXJO9gEUDu3cZw

ci9Oe6PgnbNuSYlMyvbXF1JdQyiHoEgnhl4PlV_MFagm2ppzhueRkqX4eLjJllZco_2zCp0V0bpTupUSKji9KkQyWqj11pqit1K1faS1V6aFxLGQdkuzGp4rsQTan7F01iePL5DtqQ

8-tA_Lheyo8SscAVKrGii2coplQp2_D1Iosb2ViABY0UUO1A8cimXUu6Wf1R9zJIRExL5OB2j946aIiFtyKTzxDcNnuznmR45vZ2HMoK3o67jxuoUJCAnqvEX6NgPGFjCVNgASc-lg

يُرجى تذكُّر رقم تعريف المشروع، وهو اسم فريد في جميع مشاريع Google Cloud (سبق أن تم استخدام الاسم أعلاه ولن يكون مناسبًا لك). ستتم الإشارة إليها لاحقًا في هذا الدرس التطبيقي حول الترميز باسم PROJECT_ID.

  1. بعد ذلك، عليك تفعيل الفوترة في Cloud Console لاستخدام موارد Google Cloud.

إنّ تنفيذ هذا الدرس التطبيقي حول الترميز لن يكون مكلفًا أو مكلفًا على الإطلاق. احرص على اتّباع أي تعليمات في قسم "الحذف سريعًا". الذي يقدم لك نصائح حول كيفية إيقاف تشغيل الموارد حتى لا تتكبّد أي فواتير خارج نطاق هذا البرنامج التعليمي. يكون مستخدمو Google Cloud الجدد مؤهَّلون للانضمام إلى برنامج الفترة التجريبية المجانية التي تبلغ قيمتها 300 دولار أمريكي.

Google Cloud Shell

يمكن إدارة Google Cloud عن بُعد من الكمبيوتر المحمول، ولكن في هذا الدرس التطبيقي حول الترميز، سنستخدم Google Cloud Shell، وهي بيئة سطر أوامر يتم تشغيلها في السحابة الإلكترونية.

تفعيل Cloud Shell

  1. من Cloud Console، انقر على تفعيل Cloud Shell H7JlbhKGHITmsxhQIcLwoe5HXZMhDlYue4K-SPszMxUxDjIeWfOHBfxDHYpmLQTzUmQ7Xx8o6OJUlANnQF0iBuUyfp1RzVad_4nCa0Zz5LtwBlUZFXFCWFrmrWZLqg1MkZz2LdgUDQ.

zlNW0HehB_AFW1qZ4AyebSQUdWm95n7TbnOr7UVm3j9dFcg6oWApJRlC0jnU1Mvb-IQp-trP1Px8xKNwt6o3pP6fyih947sEhOFI4IRF0W7WZk6hFqZDUGXQQXrw21GuMm2ecHrbzQ

إذا لم يسبق لك بدء تشغيل Cloud Shell، ستظهر لك شاشة وسيطة (الجزء السفلي غير المرئي من الصفحة) تصف ماهيتها. وفي هذه الحالة، انقر على متابعة (ولن تظهر لك مرة أخرى). إليك ما تبدو عليه هذه الشاشة التي تُستخدم لمرة واحدة:

kEPbNAo_w5C_pi9QvhFwWwky1cX8hr_xEMGWySNIoMCdi-Djx9AQRqWn-__DmEpC7vKgUtl-feTcv-wBxJ8NwzzAp7mY65-fi2LJo4twUoewT1SUjd6Y3h81RG3rKIkqhoVlFR-G7w

من المفترَض أن تستغرق عملية توفير المتطلبات اللازمة والاتصال بخدمة Cloud Shell بضع دقائق فقط.

pTv5mEKzWMWp5VBrg2eGcuRPv9dLInPToS-mohlrqDASyYGWnZ_SwE-MzOWHe76ZdCSmw0kgWogSJv27lrQE8pvA5OD6P1I47nz8vrAdK7yR1NseZKJvcxAZrPb8wRxoqyTpD-gbhA

يتم تحميل هذه الآلة الافتراضية مزوّدة بكل أدوات التطوير التي ستحتاج إليها. وتوفّر هذه الشبكة دليلاً رئيسيًا دائمًا بسعة 5 غيغابايت ويتم تشغيله في Google Cloud، ما يحسّن بشكل كبير من أداء الشبكة والمصادقة. يمكنك تنفيذ معظم عملك، إن لم يكن كلّه، في هذا الدرس التطبيقي حول الترميز باستخدام متصفّح أو جهاز Chromebook.

بعد الربط بخدمة Cloud Shell، من المفترَض أن يظهر لك أنّه سبق أن تمت مصادقتك وأنّ المشروع قد تم ضبطه على رقم تعريف مشروعك.

  1. شغِّل الأمر التالي في Cloud Shell لتأكيد مصادقتك:
gcloud auth list

مخرجات الأمر

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
gcloud config list project

مخرجات الأمر

[core]
project = <PROJECT_ID>

إذا لم يكن كذلك، يمكنك تعيينه من خلال هذا الأمر:

gcloud config set project <PROJECT_ID>

مخرجات الأمر

Updated property [core/project].

3- توفير موارد النشر/الاشتراك

أولاً، سنحتاج إلى إعداد موضوع خدمة Cloud Pub/Sub والاشتراك. في هذا الطلب، سننشر معلومات التسجيل في موضوع النشر/الاشتراك. ثم تتم قراءة المعلومات من هذا الموضوع والاحتفاظ بها في قاعدة البيانات.

في هذا البرنامج التعليمي، سنعتمد على Cloud Shell لتوفير مواردنا. يُرجى العِلم أنّه يمكن للمستخدم أيضًا إعداد موارد النشر/الاشتراك من خلال قسم Cloud Pub/Sub في Google Cloud Console.

في الوحدة الطرفية في Cloud Shell، فعِّل أولاً واجهة برمجة تطبيقات Pub/Sub.

$ gcloud services enable pubsub.googleapis.com

بعد ذلك، سننشئ موضوع النشر/الاشتراك باسم registrations لهذا التطبيق. سيتم نشر معلومات التسجيل المقدّمة من خلال الطلب في هذا الموضوع.

$ gcloud pubsub topics create registrations

أخيرًا، قم بإنشاء اشتراك للموضوع. يتيح لك الاشتراك في خدمة "النشر/الاشتراكات" تلقّي رسائل من موضوع معيّن.

$ gcloud pubsub subscriptions create registrations-sub --topic=registrations

لقد أكملت الآن إنشاء اشتراك وموضوع في Cloud Pub/Sub.

4. إنشاء مثيل وقاعدة بيانات Cloud SQL (MySQL)

بالنسبة إلى نموذج التطبيق، نحتاج أيضًا إلى إعداد مثيل قاعدة بيانات للاحتفاظ بمعلومات صاحب التسجيل. ستعتمد هذه الخطوة أيضًا على الوحدة الطرفية في Cloud Shell لتوفير موارد Cloud SQL. تجدر الإشارة إلى أنّه يمكنك عرض مثيلات Cloud SQL وضبطها من خلال Google Cloud Console أيضًا.

أولاً، عليك تفعيل واجهة برمجة التطبيقات Admin API في Cloud SQL.

$ gcloud services enable sqladmin.googleapis.com

بعد ذلك، سنوفّر مثيل Cloud SQL (MySQL). قد يستغرق تنفيذ هذا الأمر بعض الوقت.

$ gcloud sql instances create codelab-instance --region=us-east1

بعد إنشاء مثيل Cloud SQL بنجاح، أنشِئ قاعدة بيانات جديدة في المثيل باسم registrants.

$ gcloud sql databases create registrants --instance codelab-instance

لقد أكملت الآن إعداد مثيل Cloud SQL وإعداد قاعدة البيانات لتطبيقك.

5- إعداد تطبيق Spring Boot

نحن الآن جاهزون لبدء كتابة الطلب. ستواصل الخطوات التالية استخدام Cloud Shell الموضح في خطوات الإعداد.

أولاً، سنستخدم Initializr لإنشاء رمز التجميع للمشروع. في نافذة Cloud Shell، شغِّل:

$ 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

يؤدّي هذا الأمر إلى إنشاء إعداد أوّلي لمشروع Maven بالإضافة إلى رمز تخزين لتطبيقك في دليل registrations-codelab/. تصف الأقسام التالية تعديلات التعليمات البرمجية اللازمة لإنتاج تطبيق عامل.

محرّر رموز Cloud Shell

أسهل طريقة لبدء تعديل الرموز البرمجية وعرضها في بيئة Cloud Shell هي استخدام أداة تعديل الرموز في Cloud Shell المدمجة.

بعد فتح مثيل Cloud Shell، انقر على رمز القلم الرصاص لفتح محرِّر الرموز. ينبغي أن يسمح لك المحرر بتعديل ملفات المشروع التي تنتجها Initialzr مباشرةً.

cce293b40119c37b.png

6- تكوين قاعدة البيانات

أولاً، اضبط تطبيقك بحيث يمكنه الاتصال بقاعدة بيانات Cloud MySQL التي أعددتها. توفّر مكتبات Spring Cloud GCP إجراء تفعيل Cloud MySQL الذي يوفر الاعتماديات اللازمة للاتصال بمثيل Cloud MySQL.

أضِف تبعية spring-cloud-gcp-starter-sql-mysql إلى المشروع 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>

بالإضافة إلى ذلك، يجب تعديل ملف الإعداد application.properties لوصف إعدادات قاعدة البيانات. انسخ السمات التالية إلى ملف application.properties.

ابحث عن اسم اتصال المثيل بقاعدة البيانات:

$ gcloud sql instances describe codelab-instance \
  --format 'value(connectionName)'

وسيتم استخدام ناتج هذا في ملف application.properties لضبط معلومات الاتصال.

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

الخاصية الوحيدة التي يجب تعديلها هي اسم اتصال المثيل. يجب تنسيق هذه القيمة كقيمة مفصولة بنقطتين بالتنسيق: YOUR_GCP_PROJECT_ID:REGION:DATABASE_INSTANCE_NAME.

7. إنشاء المحتوى الثابت

أولاً، سننشئ الواجهة الأمامية لتطبيقنا. يجب أن يحتوي الطلب على نموذج يتيح لشخص ما تسجيل الأفراد، وكذلك طريقة عرض تعرض جميع المسجلين الناجحين.

بالنسبة إلى الصفحة الرئيسية، أنشئ index.html يحتوي على نموذج التسجيل.

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>

بعد ذلك، سننشئ نموذج Thymeleaf باسم registrants.html لعرض المستخدمين المسجَّلين. Thymeleaf هو إطار عمل نماذج نستخدمه لإنشاء وعرض محتوى HTML تم إنشاؤه ديناميكيًا. سترى أن النموذج يبدو مثل HTML، باستثناء أنّه يحتوي على بعض عناصر Markdown الإضافية للتعامل مع المحتوى الديناميكي. يقبل هذا النموذج مَعلمة واحدة باسم personsList تحتوي على جميع أصحاب التسجيل الذين تم تسجيلهم من خلال التطبيق.

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>

في هذه المرحلة، يمكنك التحقّق من عرض المحتوى الثابت.

إنشاء التطبيق وتشغيله باستخدام Maven:

$ ./mvnw spring-boot:run

انقر على زر المعاينة في نافذة Cloud Shell وتحقَّق من ظهور الصفحة الرئيسية. لن تعمل أي من الوظائف على واجهة المستخدم لأننا نفتقد وحدة تحكم الويب. ستتم إضافة هذه المعلومات في الخطوة التالية.

5e38bb0d0e93002e.png

بعد معاينة التطبيق، اضغط على CTRL+C لإنهاء التطبيق.

8. إرسال المسجلين إلى موضوع نشر/اشتراك

في هذه الخطوة، سنطبّق الميزة التي تتيح نشر المسجّلين الذين تم إرسالهم من خلال نموذج الويب في موضوع Cloud Pub/Sub.

إضافة فئات البيانات

أولاً، سنقوم بإنشاء بعض فئات بيانات Kotlin، ستكون هذه الجهات بمثابة كيانات JPA وتعمل أيضًا كتمثيل وسيط للمسجّلين الذين تم إرسالهم من خلال النموذج.

في حزمة الإصدار التجريبي، أضِف ملفَين جديدَين: فئة Person وفئة بيانات Spring PersonRepository. تتيح لنا هاتان الفئتان تخزين إدخالات التسجيل واستردادها بسهولة من قاعدة بيانات MySQL باستخدام 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>

إضافة Web Controller

بعد ذلك، سننشئ فئة مسؤول التحكّم بالبيانات تعالج أصحاب التسجيل من النموذج وترسل المعلومات إلى موضوع Cloud Pub/Sub الذي أنشأته سابقًا. تنشئ وحدة التحكّم هذه نقطتَي نهاية:

  • /registerPerson: نقطة نهاية POST التي يتم فيها إرسال معلومات صاحب التسجيل ثم إرسالها إلى موضوع النشر/الاشتراك. في دالة registerPerson(..)، يتم إرسال معلومات صاحب التسجيل إلى موضوع النشر/الاشتراك باستخدام PubSubTemplate، وهي فئة ملائمة من عمليات دمج خدمة النشر/الاشتراك في Cloud Cloud Platform في Spring Cloud التي تقلّل الرمز النموذجي المطلوب لبدء التفاعل مع Cloud Pub/Sub.
  • /registrants: يعرض هذا الخيار جميع المستخدمين المسجّلين بنجاح في قاعدة البيانات. تم استرداد هذه المعلومات من مثيل MySQL باستخدام مستودع بيانات Spring الذي أنشأناه في الخطوة السابقة.

أنشئ فئة وحدة التحكم التالية في الحزمة التجريبية:

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))
  }
}

يقرأ مسؤول التحكّم معلومات صاحب التسجيل المرسَلة من خلال نموذج الويب، ثم ينشر المعلومات في موضوع النشر/الاشتراك.

إضافة أداة خرائط لكائنات JSON

ربما لاحظت في وحدة التحكّم أننا ننشر كائن Person لموضوع النشر/الاشتراك وليس لسلسلة. هذا ممكن لأنّنا نستفيد من دعم Spring Cloud GCP في إرسال حمولات JSON المخصصة إلى المواضيع، حيث تتيح لك المكتبات تسلسل العناصر إلى JSON، وإرسال حمولات JSON إلى أحد المواضيع وإلغاء تسلسل حمولة البيانات عند استلامها.

للاستفادة من هذه الميزة، يجب أن نضيف علامة ObjectMapper إلى سياق تطبيقك. سيتم استخدام حبوب ObjectMapper هذه لإنشاء تسلسل بين العناصر من وإلى JSON عندما يرسل تطبيقك الرسائل ويستلمها. في الفئة DemoApplication.kt، أضف 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)
}

عند هذه النقطة، يمكنك محاولة تشغيل التطبيق مرة أخرى عن طريق تشغيل:

$ ./mvnw spring-boot:run

من نموذج الويب على الصفحة الرئيسية، سيرسل التطبيق الآن المعلومات إلى موضوع النشر/الاشتراك الذي أنشأته. مع ذلك، لا يزال الفيديو غير مفيد لأنّنا ما زلنا بحاجة إلى القراءة من موضوع النشر/الاشتراك. يتم تحقيق ذلك في الخطوة التالية.

9. قراءة بيانات المسجّلين من خلال موضوع النشر/الاشتراك

في الخطوة الأخيرة، سنعالج معلومات صاحب التسجيل من موضوع النشر/الاشتراك ونواصل حفظ المعلومات في قاعدة بيانات Cloud MySQL. سيؤدي هذا الإجراء إلى إكمال طلب الانضمام، ما يتيح لك إرسال مستخدمين مسجَّلين جدد من خلال النموذج وعرض جميع المستخدمين المسجَّلين من خلال نقطة نهاية /registrants.

سيتمكن هذا التطبيق من الاستفادة من Spring Integration، والتي توفر العديد من التجريدات المناسبة للتعامل مع الرسائل. سنضيف PubSubInboundChannelAdapter لنتمكّن من قراءة الرسائل من موضوع النشر/الاشتراك ووضعها في pubsubInputChannel لإجراء مزيد من المعالجة. بعد ذلك، سيتم ضبط الدالة messageReceiver باستخدام @ServiceActivator ليتم استدعاؤها مع الرسائل التي تصل إلى 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)
}

في هذه المرحلة، تكون قد أكملت إعداد التطبيق. للتأكّد من عمل التطبيق بشكل صحيح، شغِّل:

$ ./mvnw spring-boot:run

انقر على الزر معاينة مرة أخرى وحاول تسجيل مستخدم من خلال ملء النموذج وإرساله.

e0d0b0f0c94120c2.png

انقر على رابط الأشخاص المسجَّلون للتحقق من ظهور صاحب التسجيل الجديد في الجدول.

ab3b980423d0c51.png

تهانينا، لقد انتهيت الآن! أنهِ التطبيق بالضغط على CTRL+C في النافذة الطرفية.

10. تنظيف

لتنظيف البيئة، عليك حذف موضوع Pub/Sub ومثيل Cloud MySQL الذي أنشأته.

حذف مثيل Cloud MySQL

$ gcloud sql instances delete codelab-instance

حذف مراجع النشر/الاشتراك

$ gcloud pubsub subscriptions delete registrations-sub
$ gcloud pubsub topics delete registrations

11. تهانينا!

لقد أكملت الآن كتابة تطبيق Spring Kotlin الذي يتكامل مع Cloud Pub/Sub وCloud SQL (MySQL).

مزيد من المعلومات

الترخيص

هذا العمل مرخّص بموجب رخصة المشاع الإبداعي 2.0 مع نسب العمل إلى مؤلف عام.