สร้างแอปพลิเคชัน Kotlin Spring ด้วย Google Cloud Platform

1. บทนำ

Spring Framework 5.0 เพิ่มการรองรับ Kotlin โดยเฉพาะเพื่อให้นักพัฒนาซอฟต์แวร์ Kotlin ใช้ Spring ได้โดยง่าย การเปลี่ยนแปลงเหล่านี้ส่งผลให้การผสานรวม Google Cloud จาก Spring Cloud GCP ทำงานใน Kotlin ได้อย่างราบรื่น ใน Codelab นี้ คุณจะได้ทราบว่าการเริ่มใช้บริการของ Google Cloud ในแอปพลิเคชัน Kotlin นั้นทำได้ง่ายเพียงใด

Codelab นี้จะแนะนำการตั้งค่าแอปพลิเคชันการลงทะเบียนอย่างง่ายใน Kotlin ซึ่งสาธิตการใช้บริการ GCP ซึ่งรวมถึง Cloud Pub/Sub และ Cloud SQL

สิ่งที่คุณจะสร้าง

ใน Codelab นี้ คุณจะต้องตั้งค่าแอปพลิเคชัน 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 ทั้งหมด (ชื่อด้านบนมีคนใช้แล้ว และจะใช้ไม่ได้ ขออภัย) และจะมีการอ้างอิงใน Codelab ว่า PROJECT_ID ในภายหลัง

  1. ถัดไป คุณจะต้องเปิดใช้การเรียกเก็บเงินใน Cloud Console เพื่อใช้ทรัพยากร Google Cloud

การใช้งาน Codelab นี้น่าจะไม่มีค่าใช้จ่ายใดๆ หากมี ตรวจสอบว่าคุณได้ทำตามวิธีการใน "การล้างข้อมูล" ซึ่งจะแนะนำคุณเกี่ยวกับวิธีปิดทรัพยากรเพื่อไม่ให้มีการเรียกเก็บเงินนอกเหนือจากบทแนะนำนี้ ผู้ใช้ใหม่ของ Google Cloud จะมีสิทธิ์เข้าร่วมโปรแกรมทดลองใช้ฟรี$300 USD

Google Cloud Shell

แม้ Google Cloud จะทำงานจากระยะไกลได้จากแล็ปท็อป แต่ใน Codelab นี้ เราจะใช้ Google Cloud Shell ซึ่งเป็นสภาพแวดล้อมแบบบรรทัดคำสั่งที่ทำงานในระบบคลาวด์

เปิดใช้งาน Cloud Shell

  1. คลิกเปิดใช้งาน Cloud Shell กริ๊งๆๆๆ จาก Cloud Console

zlNW0HehB_AFW1qZ4AyebSQUdWm95n7TbnOr7UVm3j9dFcg6oWApJRlC0jnU1Mvb-IQp-trP1Px8xKNwt6o3pP6fyih947sEhOFI4IRF0W7WZk6hFqZDUGXQQXrw21GuMm2ecHrbzQ

หากคุณไม่เคยเริ่มต้นใช้งาน Cloud Shell มาก่อน คุณจะเห็นหน้าจอตรงกลาง (ครึ่งหน้าล่าง) ซึ่งอธิบายว่านี่คืออะไร หากเป็นเช่นนั้น ให้คลิกดำเนินการต่อ (คุณจะไม่เห็นการดำเนินการนี้อีก) หน้าจอแบบครั้งเดียวมีลักษณะดังนี้

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

การจัดสรรและเชื่อมต่อกับ Cloud Shell ใช้เวลาเพียงไม่กี่นาที

pTv5mEKzWMWp5VBrg2eGcuRPv9dLInPToS-mohlrqDASyYGWnZ_SwE-MzOWHe76ZdCSmw0kgWogSJv27lrQE8pvA5OD6P1I47nz8vrAdK7yR1NseZKJvcxAZrPb8wRxoqyTpD-gbhA

เครื่องเสมือนนี้เต็มไปด้วยเครื่องมือการพัฒนาทั้งหมดที่คุณต้องการ โดยมีไดเรกทอรีหลักขนาด 5 GB ที่ทำงานอย่างต่อเนื่องใน Google Cloud ซึ่งจะช่วยเพิ่มประสิทธิภาพของเครือข่ายและการตรวจสอบสิทธิ์ได้อย่างมาก งานส่วนใหญ่ใน Codelab นี้สามารถทำได้โดยใช้เบราว์เซอร์หรือ 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. จัดสรรทรัพยากร Pub/Sub

ก่อนอื่น คุณจะต้องตั้งค่าหัวข้อและการสมัครใช้บริการ Cloud Pub/Sub ในแอปพลิเคชันนี้ เราจะเผยแพร่ข้อมูลการลงทะเบียนไปยังหัวข้อ Pub/Sub จากนั้นข้อมูลจะถูกอ่านจากหัวข้อนี้และคงไว้ในฐานข้อมูล

ในบทแนะนำนี้ เราจะใช้ Cloud Shell ในการจัดสรรทรัพยากร โปรดทราบว่าผู้ดูแลระบบอาจกำหนดค่าทรัพยากร Pub/Sub ผ่านส่วน Cloud Pub/Sub ใน Google Cloud Console ได้เช่นกัน

เปิดใช้ Pub/Sub API ในเทอร์มินัล Cloud Shell ก่อน

$ gcloud services enable pubsub.googleapis.com

ต่อไปเราจะสร้างหัวข้อ Pub/Sub ชื่อ registrations สำหรับแอปพลิเคชันนี้ ระบบจะเผยแพร่ข้อมูลการลงทะเบียนที่ส่งผ่านใบสมัครไปยังหัวข้อนี้

$ gcloud pubsub topics create registrations

สุดท้ายให้สร้างการสมัครรับข้อมูลสำหรับหัวข้อนั้น การสมัครใช้บริการ Pub/Sub ช่วยให้คุณได้รับข้อความจากหัวข้อ

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

คุณสร้างหัวข้อ Cloud Pub/Sub และการสมัครใช้บริการสำหรับแอปพลิเคชันเรียบร้อยแล้ว

4. สร้างอินสแตนซ์และฐานข้อมูล Cloud SQL (MySQL)

สำหรับแอปพลิเคชันตัวอย่าง เรายังต้องตั้งค่าอินสแตนซ์ฐานข้อมูลเพื่อเก็บข้อมูลผู้จดทะเบียนด้วย ขั้นตอนนี้จะใช้เทอร์มินัล Cloud Shell ในการจัดสรรทรัพยากร Cloud SQL ด้วย โปรดทราบว่าคุณอาจดูและกำหนดค่าอินสแตนซ์ Cloud SQL ผ่าน Google Cloud Console ได้เช่นกัน

ขั้นแรก ให้เปิดใช้ Cloud SQL Admin API

$ 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 ซึ่งมีทรัพยากร Dependency ที่จำเป็นสำหรับการเชื่อมต่อกับอินสแตนซ์ Cloud MySQL

เพิ่มทรัพยากร Dependency 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 เว้นแต่ว่าจะมีองค์ประกอบมาร์กดาวน์เพิ่มเติมบางอย่างเพื่อใช้จัดการกับเนื้อหาแบบไดนามิก เทมเพลตนี้ยอมรับพารามิเตอร์เดียวที่ชื่อว่า 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 และตรวจสอบว่าคุณเห็นหน้าแรกที่แสดงผลอยู่ อย่างไรก็ตาม ฟังก์ชันใน UI จะไม่ทำงานเนื่องจากไม่มีตัวควบคุมเว็บ ระบบจะเพิ่มข้อมูลนี้ในขั้นตอนถัดไป

5e38bb0d0e93002e.png

หลังจากดูตัวอย่างแอปพลิเคชันแล้ว ให้กด CTRL+C เพื่อยุติแอปพลิเคชัน

8. การส่งผู้ลงทะเบียนไปยังหัวข้อ Pub/Sub

ในขั้นตอนนี้ เราจะใช้ฟีเจอร์ซึ่งจะมีการเผยแพร่ผู้ลงทะเบียนที่ส่งผ่านเว็บฟอร์มไปยังหัวข้อ Cloud Pub/Sub

เพิ่มคลาสข้อมูล

ก่อนอื่น เราจะสร้างคลาสข้อมูล Kotlin จำนวนหนึ่ง ข้อมูลเหล่านี้จะเป็นหน่วยงาน JPA ของเราและยังทำหน้าที่เป็นตัวแทนระดับกลางของผู้จดทะเบียนที่ส่งผ่านแบบฟอร์มนี้

ในแพ็กเกจเดโม ให้เพิ่มไฟล์ใหม่ 2 ไฟล์ ได้แก่ คลาส Person และข้อมูลฤดูใบไม้ผลิ PersonRepository ทั้ง 2 คลาสนี้จะช่วยให้เราจัดเก็บและเรียกข้อมูลรายการลงทะเบียนจากฐานข้อมูล 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 ที่คุณสร้างไว้ก่อนหน้านี้ ตัวควบคุมนี้จะสร้างปลายทาง 2 จุด ได้แก่

  • /registerPerson: ปลายทาง POST ที่ส่งข้อมูลผู้จดทะเบียนแล้วส่งไปยังหัวข้อ Pub/Sub ในฟังก์ชัน registerPerson(..) ระบบจะส่งข้อมูลผู้จดทะเบียนไปยังหัวข้อ Pub/Sub โดยใช้ PubSubTemplate ซึ่งเป็นคลาสอำนวยความสะดวกจากการผสานรวม Pub/Sub ของ GCP สำหรับ Cloud ในฤดูใบไม้ผลิซึ่งจะลดโค้ดต้นแบบที่ต้องใช้เพื่อเริ่มโต้ตอบกับ Cloud Pub/Sub
  • /registrants: แสดงผู้จดทะเบียนทั้งหมดที่ลงทะเบียนในฐานข้อมูลเรียบร้อยแล้ว ข้อมูลนี้ดึงมาจากอินสแตนซ์ MySQL โดยใช้ที่เก็บ Spring Data ที่เราสร้างไว้ในขั้นตอนก่อนหน้า

สร้างคลาสตัวควบคุมต่อไปนี้ในแพ็กเกจเดโม:

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

ตัวควบคุมจะอ่านข้อมูลผู้จดทะเบียนที่ส่งผ่านเว็บฟอร์ม แล้วเผยแพร่ข้อมูลไปยังหัวข้อ Pub/Sub

การเพิ่มบีนการแมปออบเจ็กต์ JSON

คุณอาจสังเกตเห็นในตัวควบคุมว่าเราเผยแพร่ออบเจ็กต์ Person ไปยังหัวข้อ Pub/Sub และไม่ใช่สตริง ซึ่งเป็นไปได้เพราะเราใช้ประโยชน์จากการสนับสนุน 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

จากแบบฟอร์มบนเว็บในหน้าหลัก จากนี้ไปแอปพลิเคชันจะส่งข้อมูลไปยังหัวข้อ Pub/Sub ที่คุณสร้างขึ้น อย่างไรก็ตาม ยังไม่เกิดประโยชน์ใดๆ เพราะเรายังต้องอ่านจากหัวข้อ Pub/Sub นั้นอยู่ โดยดำเนินการได้ในขั้นตอนถัดไป

9. กำลังอ่านผู้ลงทะเบียนจากหัวข้อ Pub/Sub

ในขั้นตอนสุดท้าย เราจะประมวลผลข้อมูลผู้จดทะเบียนจากหัวข้อ Pub/Sub และยืนยันข้อมูลลงในฐานข้อมูล Cloud MySQL การดำเนินการนี้จะกรอกใบสมัครให้เสร็จสมบูรณ์ ซึ่งทำให้คุณส่งผู้จดทะเบียนใหม่ผ่านแบบฟอร์มและดูผู้ใช้ที่ลงทะเบียนทั้งหมดผ่านปลายทาง /registrants ได้

แอปพลิเคชันนี้จะใช้ประโยชน์จาก Spring Integration ซึ่งมีเนื้อหาแอบสแตรกต์ที่สะดวกรวดเร็วในการจัดการกับการรับส่งข้อความ เราจะเพิ่ม PubSubInboundChannelAdapter เพื่อให้เราอ่านข้อความจากหัวข้อ Pub/Sub ได้ และใส่ไว้ใน 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

การลบทรัพยากร Pub/Sub

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

11. ยินดีด้วย

ตอนนี้คุณเขียนแอปพลิเคชัน Spring Kotlin ที่ผสานรวมกับ Cloud Pub/Sub และ Cloud SQL (MySQL) เรียบร้อยแล้ว

ดูข้อมูลเพิ่มเติม

ใบอนุญาต

ผลงานนี้ได้รับอนุญาตภายใต้ใบอนุญาตทั่วไปครีเอทีฟคอมมอนส์แบบระบุแหล่งที่มา 2.0