تطبيق Spring Boot مع خدمة تخزين البيانات في السحابة الإلكترونية

‫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.

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

لن تكلفك تجربة هذا الدرس البرمجي أكثر من بضعة دولارات، ولكن قد تكون التكلفة أعلى إذا قررت استخدام المزيد من الموارد أو إذا تركتها قيد التشغيل (راجِع قسم "التنظيف" في نهاية هذا المستند).

يمكن للمستخدمين الجدد في Google Cloud Platform الاستفادة من فترة تجريبية مجانية بقيمة 300 دولار أمريكي.

تفعيل Google Cloud Shell

من وحدة تحكّم Google Cloud Platform، انقر على رمز Cloud Shell في شريط الأدوات العلوي الأيسر:

ثم انقر على "بدء Cloud Shell":

ينبغي ألا تستغرق إدارة الحسابات والاتصال بالبيئة أكثر من بضع لحظات.

يتم تحميل هذه الآلة الافتراضية مزوّدة بكل أدوات التطوير التي ستحتاج إليها. وتوفِّر هذه الآلة دليلاً رئيسيًا دائمًا بسعة 5 غيغابايت ويتمّ تشغيله على 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].

في وحدة تحكّم Google Cloud Platform، انتقِل إلى القائمة -> Datastore (في قسم "مساحة التخزين").

إذا لم يسبق لك استخدام Datastore في المشروع الحالي، ستظهر لك شاشة "اختيار وضع Cloud Firestore". اختَر الخيار "وضع Datastore".

بعد ذلك، ستظهر لك شاشة "اختيار مكان تخزين البيانات". اختَر us-east1 أو أي موقع جغرافي إقليمي آخر وانقر على "إنشاء قاعدة بيانات":

من بيئة CloudShell، استخدِم الأمر التالي لتهيئة تطبيق 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، فضلاً عن نقطة دخول التطبيق.

سيوفر تطبيقنا واجهة سطر أوامر للمستخدمين لإدخال الأوامر والاطّلاع على النتائج. سننشئ فئة لتمثيل كتاب ثم نحفظها في Cloud Datastore باستخدام Datastore Repository.

علينا أيضًا إضافة تبعية ضرورية أخرى إلى 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. نحدّد ثلاث طرق طلب بحث في مستودعنا يتم إنشاء عمليات التنفيذ لها تلقائيًا في الخلفية.

الرقم الأول هو findByAuthor. كما يمكنك تخمين ذلك، سيؤدي تنفيذ هذه الطريقة إلى تنفيذ طلب بحث سيستخدم قيمة يقدّمها المستخدم في فلتر الشرط للمساواة مع حقل المؤلف.

ينفّذ findByYearGreaterThan طريقة طلب بحث يفلتر حقل السنة ليكون أكبر من القيمة التي يقدّمها المستخدم.

ينفّذ findByAuthorAndYear طلب بحث عن الكيانات التي تتطابق فيها حقول المؤلف والسنة مع القيم التي يقدّمها المستخدم.

افتح فئة التطبيق الرئيسية 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 بأنّنا نريد استخدام هذه الفئة كمصدر لأوامر واجهة سطر الأوامر. سيتم عرض الطرق التي تمّت إضافة التعليقات التوضيحية إليها باستخدام @ShellMethod كأوامر لواجهة سطر الأوامر في تطبيقنا.

نستخدم هنا الطرق التي حدّدناها في واجهة BookRepository: findByAuthor وfindByYearGreaterThan وfindByAuthorAndYear. نستخدم أيضًا ثلاث طرق مدمجة: 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:> 

يمكنك الآن تجربة الأوامر التي حدّدناها سابقًا. للاطّلاع على قائمة الأوامر، استخدِم أمر المساعدة:

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

للاطّلاع على كيفية تخزين الكيانات في Cloud Datastore، انتقِل إلى GCP Console وانتقِل إلى القائمة -> Datastore (في قسم "مساحة التخزين") -> الكيانات (اختَر مساحة الاسم "[default]" ونوع "الكتب"، إذا لزم الأمر).

لإجراء عملية تنظيف، أزِل جميع الكتب باستخدام الأمر remove-all-books الذي يحمل الاسم المناسب من واجهة التطبيق.

shell:> remove-all-books

للخروج من التطبيق، استخدِم أمر الإنهاء، ثم Ctrl+C.

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

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

الترخيص

يخضع هذا العمل لترخيص Creative Commons Attribution 2.0 Generic License.