概述
但在我们可以查询我们的服务器以获取一些房源数据之前,我们需要定义如何准确地检索这些数据。
在本课中,我们将
- 了解 数据获取器 以及它们在 DGS 中的工作原理
- 探索 DGS 代码生成
- 返回一些硬编码的模拟数据
🛠 数据获取器第一步
我们正在构建一个 GraphQL 服务器,它可以:
- 接收来自客户端的传入 GraphQL 查询
- 根据我们的模式验证 查询
- 检索查询模式 字段 的数据
- 并以响应形式返回数据
我们已经定义了我们的模式,因此 DGS 可以开箱即用地处理步骤 1 和步骤 2。
我们现在需要定义如何实际 检索 和 返回 当 字段 被查询时的数据。我们将把所有这些指令封装在一个名为 数据获取器 的方法中。(在其他框架中,您可能会看到数据获取器被描述为 解析器函数。)
我们使用数据获取器将 字段 映射到可以完成它们的逻辑。换句话说,我们可以编写单独的方法,这些方法在查询某些模式字段(例如我们的 Query
类型的 featuredListings
字段)时调用。
type Query {featuredListings: [Listing!]!}
这些方法有责任以我们的模式所期望的形状返回数据——例如,我们为 featuredListings
编写的 数据获取器应该返回一个与 Listing
类型匹配的对象列表。
让我们定义一个类来包含我们的数据获取器方法。
✏️ 编写数据获取器
为了使我们的代码井井有条,让我们在我们的 java/com.example.listings
包中创建一个新的 datafetchers
目录。
📂 main┣ 📂 java┃ ┣ 📂 com.example.listings┃ ┃ ┃ ┣ 📂 datafetchers┃ ┃ ┃ ┣ 📄 ListingsApplication┃ ┃ ┃ ┣ 📄 WebConfiguration
在里面,我们可以创建一个名为 ListingDataFetcher
的新类文件。
package com.example.listings.datafetchers;public class ListingDataFetcher {}
我们的空类已准备好进行一些方法来执行实际的数据获取,但我们首先需要使用一个特殊的注释来标记它,该注释告诉 DGS 在组装我们的 GraphQL API 的部分时将其包含在内。
此注释称为 @DgsComponent
,我们所需要做的就是从 DGS 包中导入它,并将其放在类定义的顶部。现在,它正式成为 DGS 团队的一员了!
package com.example.listings.datafetchers;import com.netflix.graphql.dgs.DgsComponent;@DgsComponentpublic class ListingDataFetcher {}
接下来,让我们给这个类一个名为 featuredListings
的基本方法,以匹配我们模式中的 Query
字段。
public void featuredListings() {// specific featuredListings-fetching logic goes here}
为了作为一个数据获取器,一个方法需要指定 哪个 字段 它负责。为了澄清这一点,我们有额外的 DGS 注释,可以为我们完成大部分繁重的工作。
因为 featuredListings
方法负责 Query
类型上的 featuredListings
字段,我们可以使用 @DgsQuery
注释。(不要忘记从我们的 DGS 包中导入它!)
package com.example.listings.datafetchers;import com.netflix.graphql.dgs.DgsComponent;import com.netflix.graphql.dgs.DgsQuery;@DgsComponentpublic class ListingDataFetcher {@DgsQuerypublic void featuredListings() {// specific featuredListings-fetching logic goes here}}
为了使 @DgsQuery
开箱即用,我们需要确保我们的方法具有与它解析的 Query
字段 相同的名称。这为 DGS 提供了所有必要的信息,以将 ListingDataFetcher.featuredListings
标记为 ✨官方✨ Query.featuredListings
模式 字段 的数据获取器。
还有一个大问题:我们的 featuredListings
方法实际上没有返回任何内容。但在我们的模式中,我们说对 featuredListings
字段 的查询应该返回一个 Listing
类型列表!
type Query {"A curated array of listings to feature on the homepage"featuredListings: [Listing!]!}
我们需要调整我们的方法,以便 查询 featuredListings
字段 实际上返回我们所说的数据类型。但在我们的 schema.graphqls
文件之外,我们实际上从哪里获取这些类型定义以供我们的数据获取器使用呢?
代码生成
我们知道我们的 Listing
类型需要哪些属性,因此我们 可以 定义一个相应的 Listing
类来表示 Java 中的每个对象。这种方法允许我们设置所有属性,包括 getter 和 setter 方法,同时保持对在数据传送到我们的客户端时可能需要执行的任何转换的精细控制。
另一种选择是使用 DGS 的代码生成插件。此工具会读取我们的模式文件,并根据我们编写的 GraphQL 类型生成类。使用这种方法, 字段 在 GraphQL 类型上(如 Listing
的 title
或 description
)将成为相应类上的可获取和可设置的属性。
每种方法都有其优点,因此我们将从两者中汲取一些精华。我们将使用代码生成作为起点,并在开发过程中将自定义逻辑附加到我们的类。让我们开始吧!
生成基本类
打开项目的 build.gradle
文件并查看顶部的 plugins
。启用 DGS 中代码生成的包,dgs.codegen
,已在此处列出。
plugins {id 'java'id 'org.springframework.boot' version '3.2.5'id 'io.spring.dependency-management' version '1.1.4'id 'com.netflix.dgs.codegen' version '6.0.3'}
插件在代码构建过程中自动运行,实际上它在我们运行代码时生效。
再次启动您的服务器,可以使用 IDE 的运行按钮,也可以在终端运行以下命令。
./gradlew bootRun
在 build.generated.sources
文件夹中,我们将找到一些新的包,包括 dgs-codegen
和 dgs-codegen-generated-examples
。
📂 build┣ 📂 classes┣ 📂 generated┃ ┣ 📂 sources┃ ┃ ┣ 📂 annotationProcessor┃ ┃ ┣ 📂 dgs-codegen┃ ┃ ┣ 📂 dgs-codegen-generated-examples┃ ┃ ┣ 📂 headers┣ 📂 resources┗ 📂 tmp
该 dgs-codegen
包包含插件从读取我们的 schema.graphqls
文件生成的 Java 类型。如果我们深入到 dgs-codegen.com.example.listings.generated.types
文件中,我们将看到生成的 Listing
文件。
📂 dgs-codegen┣ 📂 com.example.listings.generated┃ ┣ 📂 types┃ ┃ ┣ 📄 Listing
仔细观察生成的 Listing
类,它揭示了属性、getter 和 setter 的集合,使我们能够创建与架构中 Listing
类型规范匹配的对象。我们还将发现插件为我们添加了许多其他方法,使使用该类和构建新实例变得更加容易。
我们将基于此生成的 Listing
类进行构建,并在子类中扩展它。
让我们在代码中创建一个子类所在的位置。回到 java/com.example.listings
中,我们将定义一个名为 models
的新包,放在 datafetchers
旁边。此目录将保存我们在使用来自 数据源 的数据时使用的类。
📂 main┣ 📂 java┃ ┣ 📂 com.example.listings┃ ┃ ┃ ┣ 📂 datafetchers┃ ┃ ┃ ┣ 📂 models┃ ┃ ┃ ┣ 📄 ListingsApplication┃ ┃ ┃ ┣ 📄 WebConfiguration
接下来,我们将定义一个名为 ListingModel
的新类。此类将扩展生成的 Listing
类。以下是它的样子:
package com.example.listings.models;import com.example.listings.generated.types.Listing;public class ListingModel extends Listing {// custom logic will live here}
我们可以立即使用 ListingModel
类——回到我们的 featuredListings
数据提取器中。
返回数据
现在回到我们的 datafetchers/ListingDataFetcher
文件中,我们将导入 models/ListingModel
类,以及 Java List
实用程序。
import com.example.listings.models.ListingModel;import java.util.List;
立即,我们可以将方法的返回类型更新为 List
的 ListingModel
类型。
@DgsQuerypublic List<ListingModel> featuredListings() {}
首先,让我们从新生成的类中创建一些新的 ListingModel
实例。
@DgsQuerypublic List<ListingModel> featuredListings() {ListingModel meteorListing = new ListingModel();}
我们需要为我们的 ListingModel
实例提供一些属性,例如 id
、title
和 costPerNight
;我们可以通过调用属性 setter 方法将它们链接起来。(为这些 字段 随意指定值,但请记住要与我们在架构中为它们指定的类型匹配!
ListingModel meteorListing = new ListingModel();meteorListing.setId("1");meteorListing.setTitle("Beach house on the edge of the Laertes meteor");meteorListing.setCostPerNight(360.00);meteorListing.setClosedForBookings(false);meteorListing.setNumOfBeds(3);
太好了!这是一个新的 ListingModel
实例,所有属性都已准备就绪。
为了使我们的 List
更健壮,我们将添加至少一个 ListingModel
实例。
@DgsQuerypublic List<ListingModel> featuredListings() {ListingModel meteorListing = new ListingModel();meteorListing.setId("1");meteorListing.setTitle("Beach house on the edge of the Laertes meteor");meteorListing.setCostPerNight(360.00);meteorListing.setClosedForBookings(false);meteorListing.setNumOfBeds(3);ListingModel gasGiantListing = new ListingModel();gasGiantListing.setId("2");gasGiantListing.setTitle("Unforgettable atmosphere, unbeatable heat, tasteful furnishings");gasGiantListing.setCostPerNight(124.00);gasGiantListing.setClosedForBookings(true);gasGiantListing.setNumOfBeds(4);return List.of(meteorListing, gasGiantListing);}
这样,我们就设置了第一个数据提取器,准备被查询。以下是完成后的整个数据提取器文件的外观。
练习
主要收获
- 我们使用数据提取器方法在查询特定架构 字段 时返回数据。
- DGS 代码生成插件为我们提供了有用的起点,用于映射到我们 GraphQL 类型的 Java 类。
下一节
哇!在下一节课中,我们将看到所有部分是如何组合在一起的——通过发送我们的第一个查询!
分享您对此课的疑问和评论
本课程目前处于
您需要一个 GitHub 帐户才能在下方发帖。没有? 请在我们的 Odyssey 论坛中发帖。