使用 Cloud Datastore 的 Spring Boot 应用

1. 概览

Google Cloud Datastore 是一个 NoSQL 文档数据库,能够自动扩缩、具备出色的性能,并且易于进行应用开发。

学习内容

  • 如何在 Spring Boot 中使用 Cloud Datastore 保存和检索 Java 对象

所需条件

  • 一个 Google Cloud Platform 项目
  • 一个浏览器,例如 ChromeFirefox

您打算如何使用本教程?

仅阅读教程内容 阅读并完成练习

您如何评价自己在使用 Google Cloud Platform 服务方面的经验水平?

<ph type="x-smartling-placeholder"></ph> 新手 中级 熟练

2. 设置和要求

自定进度的环境设置

  1. 登录 Google Cloud 控制台,然后创建一个新项目或重复使用现有项目。如果您还没有 Gmail 或 Google Workspace 账号,则必须创建一个

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • 项目名称是此项目参与者的显示名称。它是 Google API 尚未使用的字符串。您可以随时对其进行更新。
  • 项目 ID 在所有 Google Cloud 项目中是唯一的,并且是不可变的(一经设置便无法更改)。Cloud 控制台会自动生成一个唯一字符串;通常情况下,您无需关注该字符串。在大多数 Codelab 中,您都需要引用项目 ID(通常用 PROJECT_ID 标识)。如果您不喜欢生成的 ID,可以再随机生成一个 ID。或者,您也可以尝试自己的项目 ID,看看是否可用。完成此步骤后便无法更改该 ID,并且此 ID 在项目期间会一直保留。
  • 此外,还有第三个值,即部分 API 使用的项目编号,供您参考。如需详细了解所有这三个值,请参阅文档
  1. 接下来,您需要在 Cloud 控制台中启用结算功能,以便使用 Cloud 资源/API。运行此 Codelab 应该不会产生太多的费用(如果有的话)。若要关闭资源以避免产生超出本教程范围的结算费用,您可以删除自己创建的资源或删除项目。Google Cloud 新用户符合参与 300 美元免费试用计划的条件。

激活 Cloud Shell

  1. 在 Cloud Console 中,点击激活 Cloud Shell853e55310c205094

55efc1aaa7a4d3ad.png

如果这是您第一次启动 Cloud Shell,系统会显示一个中间屏幕,说明它是什么。如果您看到中间屏幕,请点击继续

9c92662c6a846a5c

预配和连接到 Cloud Shell 只需花几分钟时间。

9f0e51b578fecce5

这个虚拟机装有所需的所有开发工具。它提供了一个持久的 5 GB 主目录,并在 Google Cloud 中运行,大大增强了网络性能和身份验证功能。您在此 Codelab 中的大部分(即使不是全部)工作都可以通过浏览器完成。

在连接到 Cloud Shell 后,您应该会看到自己已通过身份验证,并且相关项目已设为您的项目 ID。

  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 中,导航到菜单 ->Datastore(位于“Storage”部分)或点击此处

如果您从未在当前项目中使用过 Datastore,则会看到“选择 Cloud Firestore 模式”屏幕。选择“Datastore 模式”选项。

f938295c7ff297f4.png

然后,您会看到“选择数据的存储位置”屏幕。选择 us-east1 或任何其他地区位置,然后点击“创建数据库”:

916ac84fec10fae7

4. 引导新的 Spring Boot Java 应用

在 CloudShell 环境中,使用以下命令初始化和启动新的 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 项目,以及 Maven 的 pom.xml、一个 Maven 封装容器和一个应用入口点。

我们的应用将提供一个 CLI 供用户输入命令和查看结果。我们将创建一个类来表示图书,然后使用 Datastore Repository 将其保存到 Cloud Datastore。

我们还需要向 pom.xml 再添加一个必要的依赖项。

点击 Cloud Shell 菜单中的打开编辑器,打开 Web 代码编辑器。

6d823258c76a7452

编辑器加载后,修改 pom.xml 文件以添加 Google Cloud Datastore 入门版和 Spring Shell 入门版依赖项:

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 注解,以表明它可以存储在 Datastore 中并提供种类名称(将种类视为 SQL 数据库中的表,请参阅文档了解详情)。种类名称是可选的 - 如果省略它,系统将根据类名称生成种类名称。

请注意,我们为 id 属性添加了 @Id 注解。这表示我们希望将此字段用作 Datastore 键的标识符部分。每个 Datastore 实体都需要一个标识符。支持的类型为 StringLong

我们替换 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 是网域类,LongId 类型。我们在代码库中声明了三种查询方法,系统将在后台为其自动生成实现。

第一种是 findByAuthor。如您所料,此方法的实现将执行一个查询,该查询将在条件过滤器中使用用户提供的值,以与作者字段相等。

findByYearGreaterThan 方法会执行一个查询,过滤出大于用户提供的值的年份字段。

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 接口中声明的方法:findByAuthorfindByYearGreaterThanfindByAuthorAndYear。此外,我们还使用三种内置方法:savefindAlldeleteAll

我们来看一下 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 中(从 pom.xml 所在的项目 datastore-example/ 的根目录)执行此命令:

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

构建阶段成功后,系统将显示 Spring 徽标并显示 Shell 提示:

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



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. 使用 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 Console。输入“books”(如有必要)。

5fab21a6c89f45a

10. 清理

如需进行清理,请从 App Shell 中使用适当命名的 remove-all-books 命令移除所有图书。

shell:> remove-all-books

如需退出应用,请使用 quit 命令,然后按 Ctrl+C

11. 恭喜!

在此 Codelab 中,您创建了一个交互式 CLI 应用,该应用可以在 Cloud Datastore 中存储和检索对象!

了解详情

许可

此作品已获得 Creative Commons Attribution 2.0 通用许可授权。