אתחול אפליקציית Spring עם Cloud Datastore

1. סקירה כללית

Google Cloud Datastore הוא מסד נתונים מסוג NoSQL לאחסון מסמכים שמיועד להתאמה לעומס (automatic scaling), לביצועים גבוהים ולפיתוח אפליקציות בקלות.

מה תלמדו

  • איך משתמשים ב-Cloud Datastore כדי לשמור ולאחזר אובייקטים של Java ב-Spring Boot

הדרישות

  • פרויקט ב-Google Cloud Platform
  • דפדפן, כמו Chrome או Firefox

איך תשתמשו במדריך הזה?

רק לקרוא לקרוא ולבצע את התרגילים

איזה דירוג מגיע לדעתך לחוויית השימוש שלך בשירותים של Google Cloud Platform?

מתחילים ביניים מומחים

2. הגדרה ודרישות

הגדרת סביבה בקצב אישי

  1. נכנסים ל-מסוף Google Cloud ויוצרים פרויקט חדש או משתמשים בפרויקט קיים. אם עדיין אין לכם חשבון Gmail או Google Workspace, אתם צריכים ליצור חשבון.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • שם הפרויקט הוא השם המוצג של הפרויקט הזה למשתתפים. זו מחרוזת תווים שלא נמצאת בשימוש ב-Google APIs. תמיד אפשר לעדכן את המיקום.
  • מזהה הפרויקט הוא ייחודי לכל הפרויקטים ב-Google Cloud, והוא קבוע (אי אפשר לשנות אותו אחרי שהוא מוגדר). מסוף Cloud יוצר באופן אוטומטי מחרוזת ייחודית, ובדרך כלל לא צריך לדעת מה היא. ברוב ה-Codelabs, תצטרכו להפנות למזהה הפרויקט (בדרך כלל מסומן כ-PROJECT_ID). אם אתם לא אוהבים את המזהה שנוצר, אתם יכולים ליצור מזהה אקראי אחר. אפשר גם לנסות שם משתמש משלכם ולבדוק אם הוא זמין. אי אפשר לשנות את ההגדרה הזו אחרי השלב הזה, והיא תישאר לאורך הפרויקט.
  • לידיעתכם, יש ערך שלישי, מספר פרויקט, שחלק מממשקי ה-API משתמשים בו. במאמרי העזרה מפורט מידע נוסף על שלושת הערכים האלה.
  1. בשלב הבא, תצטרכו להפעיל את החיוב במסוף Cloud כדי להשתמש במשאבי Cloud או בממשקי API של Cloud. השלמת ה-codelab הזה לא תעלה לכם הרבה, אם בכלל. כדי להשבית את המשאבים ולמנוע חיובים נוספים אחרי שתסיימו את המדריך הזה, תוכלו למחוק את המשאבים שיצרתם או למחוק את הפרויקט. משתמשים חדשים ב-Google Cloud זכאים לתוכנית תקופת ניסיון בחינם בשווי 300$.

הפעלת Cloud Shell

  1. ב-Cloud Console, לוחצים על Activate Cloud Shell 853e55310c205094.png.

55efc1aaa7a4d3ad.png

אם זו הפעם הראשונה שאתם מפעילים את Cloud Shell, יוצג לכם מסך ביניים עם תיאור של השירות. אם הוצג לכם מסך ביניים, לחצו על המשך.

9c92662c6a846a5c.png

הקצאת המשאבים והחיבור ל-Cloud Shell נמשכים רק כמה רגעים.

9f0e51b578fecce5.png

המכונה הווירטואלית הזו כוללת את כל הכלים הדרושים למפתחים. יש בה ספריית בית בנפח מתמיד של 5GB והיא פועלת ב-Google Cloud, מה שמשפר מאוד את הביצועים והאימות ברשת. אפשר לבצע את רוב העבודה ב-codelab הזה, אם לא את כולה, באמצעות דפדפן.

אחרי שמתחברים ל-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`
  1. מריצים את הפקודה הבאה ב-Cloud Shell כדי לוודא שפקודת gcloud מכירה את הפרויקט:
gcloud config list project

פלט הפקודה

[core]
project = <PROJECT_ID>

אם לא, אפשר להגדיר אותו באמצעות הפקודה הבאה:

gcloud config set project <PROJECT_ID>

פלט הפקודה

Updated property [core/project].

3. איך מאתחלים את Cloud Datastore

ב-GCP Console, עוברים אל Menu -> Datastore (בקטע Storage) או לוחצים כאן.

אם אף פעם לא השתמשתם ב-Datastore בפרויקט הנוכחי, יופיע המסך Select a Cloud Firestore mode (בחירת מצב של Cloud Firestore). בוחרים באפשרות מצב Datastore.

f938295c7ff297f4.png

אחרי כן, יוצג המסך "בחירת המיקום לאחסון הנתונים". בוחרים באפשרות us-east1 או בכל מיקום אזורי אחר ולוחצים על 'יצירת מסד נתונים':

916ac84fec10fae7.png

4. אתחול של אפליקציית Java חדשה ב-Spring Boot

בסביבת Cloud Shell, משתמשים בפקודה הבאה כדי לאתחל ולבצע bootstrap לאפליקציית Spring Boot חדשה:

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

הפעולה הזו תיצור ספרייה חדשה בשם datastore-example/ עם פרויקט Maven חדש, יחד עם pom.xml של Maven, Maven Wrapper ונקודת כניסה לאפליקציה.

האפליקציה שלנו תספק למשתמשים CLI שבו הם יוכלו להזין פקודות ולראות את התוצאות. ניצור מחלקה שתייצג ספר, ואז נשמור אותה ב-Cloud Datastore באמצעות Datastore Repository.

צריך גם להוסיף עוד תלות נדרשת ל-pom.xml.

כדי לפתוח את עורך הקוד לאתרים, לוחצים על Open editor (פתיחת העורך) בתפריט Cloud Shell.

6d823258c76a7452.png

אחרי שהעורך נטען, משנים את הקובץ pom.xml כדי להוסיף את התלות של Google Cloud Datastore Starter ושל Spring Shell Starter:

pom.xml

<project>
  ...
  <dependencies>
        ...
        <!-- Add GCP Datastore Starter -->
        <dependency>
                <groupId>com.google.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>3.0.2</version>
        </dependency>

  </dependencies>
</project>

5. יצירת המחלקה Book

בעזרת העורך, יוצרים את המחלקה Book עם התוכן הבא:

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

package com.example.demo;

import com.google.cloud.spring.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 כדי לציין שאפשר לאחסן אותן ב-מאגר נתונים ולספק את שם ה-סיווג (אפשר לחשוב על סיווג כטבלה במסדי נתונים של SQL, מידע נוסף זמין במאמרי עזרה). שם הסוג הוא אופציונלי – אם לא מציינים אותו, שם הסוג ייווצר על סמך שם המחלקה.

שימו לב שהוספנו הערה לנכס id באמצעות @Id. המשמעות היא שאנחנו רוצים שהשדה הזה ישמש כחלק המזהה של מפתח Datastore. לכל ישות ב-Datastore צריך להיות מזהה. הסוגים הנתמכים הם String ו-Long.

אנחנו מבטלים את השיטה toString כדי שהייצוג של האובייקטים כמחרוזת יהיה קריא יותר. זה יהיה שימושי כשנדפיס אותם.

6. יצירת הממשק BookRepository

יוצרים את המחלקה BookRepository עם התוכן הבא:

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

package com.example.demo;

import java.util.List;

import com.google.cloud.spring.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. הגדרנו במאגר שלוש שיטות לשאילתות, שהיישומים שלהן נוצרים אוטומטית מאחורי הקלעים.

הראשון הוא findByAuthor. כפי שאפשר לנחש, ההטמעה של השיטה הזו תבצע שאילתה שתשתמש בערך שסופק על ידי המשתמש במסנן התנאים כדי לבדוק אם הוא שווה לערך בשדה המחבר.

השיטה findByYearGreaterThan מריצה שאילתה שמסננת את השדה year (שנה) לפי ערך שגדול מהערך שהמשתמש סיפק.

findByAuthorAndYear מבצע שאילתה שמחפשת ישויות שבהן השדות של המחבר והשנה תואמים לערכים שהמשתמש סיפק.

7. יצירת אפליקציית CLI אינטראקטיבית

פותחים את המחלקה הראשית DemoApplication של האפליקציה ומשנים אותה כך שתיראה כמו הקוד הבא:

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. בנוסף, אנחנו משתמשים בשלוש שיטות מובנות: save,‏ findAll ו-deleteAll.

נבחן את השיטה saveBook. אנחנו יוצרים אובייקט Book באמצעות ערכים שסופקו על ידי המשתמשים עבור שם הפריט, המחבר והשנה. כפי שאפשר לראות, לא ציינו ערך ל-id, ולכן הוא יוקצה ויוגדר אוטומטית בשדה id כשנשמור את השינויים. השיטה save מקבלת אובייקט מסוג Book ושומרת אותו ב-Cloud Datastore. הפונקציה מחזירה אובייקט Book עם כל השדות מאוכלסים, כולל השדה id. בסופו של דבר, הפונקציה מחזירה ייצוג מחרוזתי של האובייקט הזה.

שאר השיטות פועלות באופן דומה: הן מקבלות פרמטרים שמועברים לשיטות המתאימות במאגר ומחזירות תוצאות בפורמט מחרוזת.

8. הפעלת האפליקציה

כדי לבנות ולהפעיל את האפליקציה, קודם מוודאים ש-JAVA_HOME מוגדר לגרסה הנכונה:

$ export JAVA_HOME=/usr/lib/jvm/java-1.17.0-openjdk-amd64

מריצים את הפקודה הזו ב-Cloud Shell (מהרמה הבסיסית של הפרויקט datastore-example/ שבו נמצא הקובץ pom.xml):

$ ./mvnw spring-boot:run
export JAVA_HOME=/usr/lib/jvm/java-1.17.0-openjdk-amd64

אחרי שלב בנייה מוצלח, הלוגו של Spring יופיע וההנחיה של המעטפת תופיע:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.0.5)



shell:>

עכשיו אפשר להתנסות בפקודות שהגדרנו קודם. כדי לראות את רשימת הפקודות, משתמשים בפקודת העזרה:

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. יצירת כמה ספרים באמצעות הפקודה save-book
  2. הפעלת חיפוש באמצעות הפקודה find-all-books
  3. כדי למצוא ספרים של מחבר מסוים: find-by-author <author>
  4. כדי למצוא ספרים שפורסמו אחרי שנה מסוימת: find-by-year-after <year>
  5. כדי למצוא ספרים של מחבר מסוים משנה מסוימת: find-by-author-year <author> <year>

9. איך רואים מה מאוחסן ב-Datastore באמצעות ממשק אינטרנט

כדי לראות איך הישויות מאוחסנות ב-Cloud Datastore, עוברים אל מסוף GCP. אם צריך, מזינים 'books' בשדה 'סוג'.

5fab21a6c89f45a.png

10. הסרת המשאבים

כדי לנקות, מסירים את כל הספרים באמצעות הפקודה remove-all-books ממעטפת האפליקציה.

shell:> remove-all-books

כדי לצאת מהאפליקציה, משתמשים בפקודה quit ואז ב-Ctrl+C.

‫11. מעולה!

ב-codelab הזה יצרתם אפליקציית CLI אינטראקטיבית שיכולה לאחסן ולאחזר אובייקטים מ-Cloud Datastore.

מידע נוסף

רישיון

עבודה זו מורשית תחת רישיון Creative Commons שמותנה בייחוס 2.0 כללי.