แอปพลิเคชัน Spring Boot ที่มี Cloud Datastore

Google Cloud Datastore คือฐานข้อมูลเอกสาร NoSQL ที่สร้างขึ้นมาสำหรับการปรับขนาดอัตโนมัติโดยมีประสิทธิภาพสูงและพัฒนาแอปพลิเคชันได้อย่างง่ายดาย

สิ่งที่คุณจะได้เรียนรู้

  • วิธีใช้ Cloud Datastore เพื่อบันทึกและเรียกออบเจ็กต์ Java ใน Spring Boot

สิ่งที่คุณต้องมี

  • โปรเจ็กต์ Google Cloud Platform
  • เบราว์เซอร์ เช่น Chrome หรือ Firefox

คุณจะใช้บทแนะนำนี้อย่างไร

อ่านอย่างเดียว อ่านและทำแบบฝึกหัด

คุณจะให้คะแนนประสบการณ์การใช้บริการ Google Cloud Platform เท่าใด

ผู้เริ่มต้น ระดับกลาง ผู้ชำนาญ

การตั้งค่าสภาพแวดล้อมแบบเรียนรู้ด้วยตนเอง

หากยังไม่มีบัญชี Google (Gmail หรือ Google Apps) คุณต้องสร้างบัญชี ลงชื่อเข้าใช้คอนโซล Google Cloud Platform (console.cloud.google.com) แล้วสร้างโปรเจ็กต์ใหม่โดยทำดังนี้

ภาพหน้าจอจาก 2016-02-10 12:45:26.png

โปรดจดจำรหัสโปรเจ็กต์ ซึ่งเป็นชื่อที่ไม่ซ้ำกันในโปรเจ็กต์ Google Cloud ทั้งหมด (ชื่อด้านบนถูกใช้ไปแล้วและจะใช้ไม่ได้ ขออภัย) ซึ่งจะเรียกว่า PROJECT_ID ในภายหลังใน Codelab นี้

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

การทำ Codelab นี้ไม่ควรมีค่าใช้จ่ายเกิน 2-3 ดอลลาร์ แต่ก็อาจมีค่าใช้จ่ายมากกว่านี้หากคุณตัดสินใจใช้ทรัพยากรเพิ่มเติมหรือปล่อยให้ทรัพยากรทำงานต่อไป (ดูส่วน "การล้างข้อมูล" ที่ท้ายเอกสารนี้)

ผู้ใช้ใหม่ของ Google Cloud Platform มีสิทธิ์ทดลองใช้ฟรี$300

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

จาก GCP Console ให้คลิกไอคอน Cloud Shell ในแถบเครื่องมือด้านขวาบน

จากนั้นคลิก "เริ่ม Cloud Shell"

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

เครื่องเสมือนนี้มาพร้อมเครื่องมือพัฒนาทั้งหมดที่คุณต้องการ โดยมีไดเรกทอรีหลักขนาด 5 GB ที่คงอยู่ถาวร และทำงานบน Google Cloud ซึ่งช่วยเพิ่มประสิทธิภาพเครือข่ายและการตรวจสอบสิทธิ์ได้อย่างมาก คุณสามารถทำงานส่วนใหญ่ในแล็บนี้ได้โดยใช้เพียงเบราว์เซอร์หรือ Google Chromebook

เมื่อเชื่อมต่อกับ Cloud Shell แล้ว คุณควรเห็นว่าคุณได้รับการตรวจสอบสิทธิ์แล้วและระบบได้ตั้งค่าโปรเจ็กต์เป็น PROJECT_ID แล้ว

เรียกใช้คำสั่งต่อไปนี้ใน Cloud Shell เพื่อยืนยันว่าคุณได้รับการตรวจสอบสิทธิ์แล้ว

gcloud auth list

เอาต์พุตของคำสั่ง

Credentialed accounts:
 - <myaccount>@<mydomain>.com (active)
gcloud config list project

เอาต์พุตของคำสั่ง

[core]
project = <PROJECT_ID>

หากไม่ได้ตั้งค่าไว้ คุณตั้งค่าได้ด้วยคำสั่งนี้

gcloud config set project <PROJECT_ID>

เอาต์พุตของคำสั่ง

Updated property [core/project].

ในคอนโซล GCP ให้ไปที่เมนู -> Datastore (ในส่วนพื้นที่เก็บข้อมูล)

หากไม่เคยใช้ Datastore ในโปรเจ็กต์ปัจจุบัน คุณจะเห็นหน้าจอ "เลือกโหมด Cloud Firestore" เลือกตัวเลือก "โหมด Datastore"

หลังจากนั้น คุณจะเห็นหน้าจอ "เลือกตำแหน่งที่จะจัดเก็บข้อมูล" เลือก us-east1 หรือตำแหน่งระดับภูมิภาคอื่นๆ แล้วคลิก "สร้างฐานข้อมูล"

จากสภาพแวดล้อม Cloud Shell ให้ใช้คำสั่งต่อไปนี้เพื่อเริ่มต้นและบูตแอปพลิเคชัน Spring Boot ใหม่

$ curl https://start.spring.io/starter.tgz \
  -d packaging=war \
  -d dependencies=cloud-gcp \
  -d baseDir=datastore-example \
  -d bootVersion=2.1.1.RELEASE | tar -xzvf -

ซึ่งจะสร้างไดเรกทอรี datastore-example/ ใหม่พร้อมโปรเจ็กต์ Maven ใหม่ รวมถึง pom.xml ของ Maven, Maven Wrapper และจุดแรกเข้าของแอปพลิเคชัน

แอปพลิเคชันของเราจะมี CLI ให้ผู้ใช้ป้อนคำสั่งและดูผลลัพธ์ เราจะสร้างคลาสเพื่อแสดงหนังสือ จากนั้นจะบันทึกลงใน Cloud Datastore โดยใช้ที่เก็บ Datastore

นอกจากนี้ เรายังต้องเพิ่มการอ้างอิงที่จำเป็นอีก 1 รายการลงใน pom.xml

เปิดโปรแกรมแก้ไขโค้ดบนเว็บโดยคลิกเปิดโปรแกรมแก้ไขโค้ดจากเมนู Cloud Shell

หลังจากที่เอดิเตอร์โหลดแล้ว ให้แก้ไขไฟล์ pom.xml เพื่อเพิ่มการอ้างอิงของ Spring Data Cloud Datastore Spring Boot Starter ดังนี้

pom.xml

<project>
  ...
  <dependencies>
        ...
        <!-- Add GCP Datastore Starter -->
        <dependency>
                <groupId>org.springframework.cloud</groupId>          
                <artifactId>spring-cloud-gcp-starter-data-datastore</artifactId>
        </dependency>

        <!-- Add Spring Shell Starter -->
        <dependency>
                <groupId>org.springframework.shell</groupId>
                <artifactId>spring-shell-starter</artifactId>
                <version>2.0.0.RELEASE</version>
        </dependency>

  </dependencies>
</project>

สร้างคลาส Book โดยใช้เครื่องมือแก้ไขที่มีเนื้อหาต่อไปนี้

datastore-example/src/main/java/com/example/demo/Book.java

package com.example.demo;

import org.springframework.cloud.gcp.data.datastore.core.mapping.Entity;
import org.springframework.data.annotation.Id;


@Entity(name = "books")
public class Book {
        @Id
        Long id;

        String title;

        String author;

        int year;

        public Book(String title, String author, int year) {
                this.title = title;
                this.author = author;
                this.year = year;
        }

        public long getId() {
                return this.id;
        }

        @Override
        public String toString() {
                return "Book{" +
                                "id=" + this.id +
                                ", title='" + this.title + '\'' +
                                ", author='" + this.author + '\'' +
                                ", year=" + this.year +
                                '}';
        }
}

ดังที่คุณเห็น นี่คือ POJO แบบง่าย คลาสจะได้รับการใส่คำอธิบายประกอบด้วย @Entity เพื่อระบุว่าจัดเก็บไว้ใน Datastore ได้และระบุชื่อประเภท (คิดว่าประเภทเป็นตารางในฐานข้อมูล SQL ดูรายละเอียดเพิ่มเติมได้ในเอกสารประกอบ) ชื่อประเภทเป็นข้อมูลที่ไม่บังคับ หากไม่ระบุ ระบบจะสร้างชื่อประเภทโดยอิงตามชื่อคลาส

โปรดทราบว่าเราใส่คำอธิบายประกอบพร็อพเพอร์ตี้ id ด้วย @Id ซึ่งหมายความว่าเราต้องการให้ใช้ฟิลด์นี้เป็นส่วนตัวระบุของคีย์ Datastore เอนทิตี Datastore ทุกรายการต้องมีตัวระบุ ประเภทที่รองรับคือ String และ Long

เราจะลบล้างเมธอด toString เพื่อให้การแสดงสตริงของออบเจ็กต์อ่านง่ายขึ้น ซึ่งจะเป็นประโยชน์เมื่อเราพิมพ์ออบเจ็กต์เหล่านั้น

อย่าลืมบันทึกไฟล์

สร้างBookRepository คลาสที่มีเนื้อหาต่อไปนี้

datastore-example/src/main/java/com/example/demo/BookRepository.java

package com.example.demo;

import java.util.List;

import org.springframework.cloud.gcp.data.datastore.repository.DatastoreRepository;


public interface BookRepository extends DatastoreRepository<Book, Long> {

  List<Book> findByAuthor(String author);

  List<Book> findByYearGreaterThan(int year);

  List<Book> findByAuthorAndYear(String author, int year);

}

อินเทอร์เฟซจะขยาย DatastoreRepository<Book, Long> โดยที่ Book คือคลาสโดเมน และ Long คือประเภท Id เราประกาศเมธอดการค้นหา 3 รายการในที่เก็บของเรา ซึ่งระบบจะสร้างการใช้งานโดยอัตโนมัติในเบื้องหลัง

ข้อความแรกคือ findByAuthor อย่างที่คุณทราบ การติดตั้งใช้งานเมธอดนี้จะเรียกใช้คําค้นหาที่ใช้ค่าที่ผู้ใช้ระบุในตัวกรองเงื่อนไขเพื่อความเท่าเทียมกับฟิลด์ผู้เขียน

findByYearGreaterThan จะเรียกใช้การค้นหาที่กรองฟิลด์ปีให้มีค่ามากกว่าค่าที่ผู้ใช้ระบุ

findByAuthorAndYear จะเรียกใช้การค้นหาที่มองหาเอนทิตีซึ่งฟิลด์ผู้แต่งและปีตรงกับค่าที่ผู้ใช้ระบุ

เปิดแอปพลิเคชันหลัก DemoApplication class แล้วแก้ไขให้มีลักษณะดังนี้

datastore-example/src/main/java/com/example/demo/DemoApplication.java

package com.example.demo;

import java.util.List;

import com.google.common.collect.Lists;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.shell.standard.ShellComponent;
import org.springframework.shell.standard.ShellMethod;

@ShellComponent
@SpringBootApplication
public class DemoApplication {
  @Autowired
  BookRepository bookRepository;

  public static void main(String[] args) {
     SpringApplication.run(DemoApplication.class, args);
  }

  @ShellMethod("Saves a book to Cloud Datastore: save-book <title> <author> <year>")
  public String saveBook(String title, String author, int year) {
     Book savedBook = this.bookRepository.save(new Book(title, author, year));
     return savedBook.toString();
  }

  @ShellMethod("Loads all books")
  public String findAllBooks() {
     Iterable<Book> books = this.bookRepository.findAll();
     return Lists.newArrayList(books).toString();
  }

  @ShellMethod("Loads books by author: find-by-author <author>")
  public String findByAuthor(String author) {
     List<Book> books = this.bookRepository.findByAuthor(author);
     return books.toString();
  }

  @ShellMethod("Loads books published after a given year: find-by-year-after <year>")
  public String findByYearAfter(int year) {
     List<Book> books = this.bookRepository.findByYearGreaterThan(year);
     return books.toString();
  }

  @ShellMethod("Loads books by author and year: find-by-author-year <author> <year>")
  public String findByAuthorYear(String author, int year) {
     List<Book> books = this.bookRepository.findByAuthorAndYear(author, year);
     return books.toString();
  }

  @ShellMethod("Removes all books")
  public void removeAllBooks() {
     this.bookRepository.deleteAll();
  }
}

โปรดสังเกตวิธีที่เราใส่คำอธิบายประกอบในคลาสด้วย @ShellComponent ซึ่งจะแจ้งให้ Spring ทราบว่าเราต้องการใช้คลาสนี้เป็นแหล่งที่มาสำหรับคำสั่ง CLI วิธีการที่มีคำอธิบายประกอบ @ShellMethod จะแสดงเป็นคำสั่ง CLI ในแอปพลิเคชันของเรา

ในที่นี้ เราจะใช้วิธีการที่ประกาศไว้ในอินเทอร์เฟซ BookRepository ได้แก่ findByAuthor, findByYearGreaterThan, findByAuthorAndYear นอกจากนี้ เรายังใช้วิธีการในตัว 3 วิธี ได้แก่ save, findAll และ deleteAll

มาดูวิธีการ saveBook กัน เราสร้างออบเจ็กต์ Book โดยใช้ค่าที่ผู้ใช้ระบุสำหรับชื่อ ผู้แต่ง และปี ดังที่คุณเห็น เราไม่ได้ระบุค่า id ดังนั้นระบบจะจัดสรรและกำหนดค่าให้กับช่องรหัสโดยอัตโนมัติเมื่อบันทึก เมธอด save รับออบเจ็กต์ประเภท Book และบันทึกไปยัง Cloud Datastore โดยจะแสดงผลBookออบเจ็กต์ที่มีการกรอกข้อมูลในช่องทั้งหมด รวมถึงช่อง id สุดท้ายเราจะแสดงผลการแสดงสตริงของออบเจ็กต์นี้

ส่วนวิธีการอื่นๆ จะทำงานคล้ายกัน คือยอมรับพารามิเตอร์ที่ส่งไปยังวิธีการที่เหมาะสมในที่เก็บ และส่งคืนผลลัพธ์ที่แปลงเป็นสตริง

หากต้องการสร้างและเริ่มแอปพลิเคชัน ให้เรียกใช้คำสั่งนี้ใน Cloud Shell (จากรูทของโปรเจ็กต์ datastore-example/ ที่มี pom.xml)

$ mvn spring-boot:run

หลังจากขั้นตอนการสร้างเสร็จสมบูรณ์ โลโก้ Spring จะปรากฏขึ้นและพรอมต์เชลล์จะปรากฏขึ้น

 .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.1.RELEASE)


shell:> 

ตอนนี้คุณสามารถทดลองใช้คำสั่งที่เรากำหนดไว้ก่อนหน้านี้ได้แล้ว หากต้องการดูรายการคำสั่ง ให้ใช้คำสั่ง help ดังนี้

shell:> help
...
find-all-books: Loads all books
find-by-author: Loads books by author: find-by-author <author>
find-by-author-year: Loads books by author and year: find-by-author-year <author> <year>
find-by-year-after: Loads books published after a given year: find-by-year-after <year>
remove-all-books: Removes all books
save-book: Saves a book to Cloud Datastore: save-book <title> <author> <year>

ลองทำตามขั้นตอนต่อไปนี้

  1. สร้างบุ๊กมาร์ก 2-3 รายการโดยใช้คำสั่ง save-book
  2. เรียกใช้การค้นหาโดยใช้คำสั่ง find-all-books
  3. ค้นหาหนังสือโดยผู้เขียนที่เฉพาะเจาะจง (find-by-author <author>)
  4. ค้นหาหนังสือที่เผยแพร่หลังจากปีที่ระบุ (find-by-year-after <year>)
  5. ค้นหาหนังสือตามผู้แต่งและปีที่เฉพาะเจาะจง (find-by-author-year <author> <year>)

หากต้องการดูวิธีจัดเก็บเอนทิตีใน Cloud Datastore ให้ไปที่ GCP Console แล้วไปที่เมนู -> Datastore (ในส่วนพื้นที่เก็บข้อมูล) -> เอนทิตี (เลือกเนมสเปซ "[default]" และประเภท "books" หากจำเป็น)

หากต้องการล้างข้อมูล ให้นำหนังสือทั้งหมดออกโดยใช้คำสั่ง remove-all-books ที่ตั้งชื่อไว้อย่างเหมาะสมจากเชลล์ของแอปพลิเคชัน

shell:> remove-all-books

หากต้องการออกจากแอปพลิเคชัน ให้ใช้คำสั่ง quit แล้วกด Ctrl+C

ใน Codelab นี้ คุณได้สร้างแอปพลิเคชัน CLI แบบอินเทอร์แอกทีฟที่จัดเก็บและเรียกข้อมูลออบเจ็กต์จาก Cloud Datastore ได้แล้ว

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

ใบอนุญาต

ผลงานนี้ได้รับอนุญาตภายใต้สัญญาอนุญาตครีเอทีฟคอมมอนส์สำหรับยอมรับสิทธิของผู้สร้าง (Creative Commons Attribution License) 2.0 แบบทั่วไป