Spring for GraphQL 允许您利用现有的 Spring 技术,遵循常见的 编程模型以通过 GraphQL 公开底层数据源。
本节讨论 Spring Data 的集成层,该集成层提供了一种简单的方法:
将 Querydsl 或 Query by Example 存储库调整为 ,包括
用于自动检测和 GraphQL 查询注册的选项,用于标记的存储库
跟。DataFetcher
@GraphQlRepository
查询 dsl
Spring for GraphQL 支持使用 Querydsl 通过 Spring Data Querydsl 扩展。 Querydsl 提供了一种灵活但类型安全的方法来表示查询谓词 使用 Annotation Processors 生成元模型。
例如,将存储库声明为 :QuerydslPredicateExecutor
public interface AccountRepository extends Repository<Account, Long>,
QuerydslPredicateExecutor<Account> {
}
然后使用它来创建一个 :DataFetcher
// For single result queries
DataFetcher<Account> dataFetcher =
QuerydslDataFetcher.builder(repository).single();
// For multi-result queries
DataFetcher<Iterable<Account>> dataFetcher =
QuerydslDataFetcher.builder(repository).many();
// For paginated queries
DataFetcher<Iterable<Account>> dataFetcher =
QuerydslDataFetcher.builder(repository).scrollable();
你现在可以通过 RuntimeWiringConfigurer
注册上述内容。DataFetcher
它从 GraphQL 参数构建一个 Querydsl,并使用它来
获取数据。Spring Data 支持 JPA、MongoDB、Neo4j 和 LDAP。DataFetcher
Predicate
QuerydslPredicateExecutor
对于作为 GraphQL 输入类型的单个参数,嵌套一个
level down 并使用参数 sub-map 中的值。QuerydslDataFetcher |
如果存储库为 ,则生成器将返回 或 。Spring Data 支持此功能
变体。ReactiveQuerydslPredicateExecutor
DataFetcher<Mono<Account>>
DataFetcher<Flux<Account>>
构建设置
要在构建中配置 Querydsl,请遵循官方参考文档:
例如:
-
Gradle
-
Maven
dependencies {
//...
annotationProcessor "com.querydsl:querydsl-apt:$querydslVersion:jpa",
'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.2.Final',
'javax.annotation:javax.annotation-api:1.3.2'
}
compileJava {
options.annotationProcessorPath = configurations.annotationProcessor
}
<dependencies>
<!-- ... -->
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
<classifier>jpa</classifier>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.2.Final</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
<plugins>
<!-- Annotation processor configuration -->
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>${apt-maven-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/java</outputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
webmvc-http 示例使用 Querydsl 进行 .artifactRepositories
定制
QuerydslDataFetcher
支持自定义 GraphQL 参数绑定到属性的方式
创建 Querydsl 。默认情况下,参数被绑定为 “is equal to”
每个 available 属性。要自定义它,您可以使用 builder
方法提供 .Predicate
QuerydslDataFetcher
QuerydslBinderCustomizer
存储库本身可以是 的实例。这是自动检测的
并在自动注册期间透明地应用。但是,当手动
构建 您需要使用 Builder 方法来应用它。QuerydslBinderCustomizer
QuerydslDataFetcher
QuerydslDataFetcher
支持接口和 DTO 投影以转换查询结果
在返回这些内容以进行进一步的 GraphQL 处理之前。
要了解什么是投影,请参阅 Spring Data 文档。 要了解如何在 GraphQL 中使用投影,请参阅选择集与投影。 |
要将 Spring Data 投影与 Querydsl 存储库一起使用,请创建一个投影接口
或目标 DTO 类,并通过该方法对其进行配置,以获取生成目标类型:projectAs
DataFetcher
class Account {
String name, identifier, description;
Person owner;
}
interface AccountProjection {
String getName();
String getIdentifier();
}
// For single result queries
DataFetcher<AccountProjection> dataFetcher =
QuerydslDataFetcher.builder(repository).projectAs(AccountProjection.class).single();
// For multi-result queries
DataFetcher<Iterable<AccountProjection>> dataFetcher =
QuerydslDataFetcher.builder(repository).projectAs(AccountProjection.class).many();
自动注册
如果存储库带有 注释,则它会自动注册
对于尚未注册且返回类型
与存储库域类型的匹配。这包括单值查询、多值
queries 和分页查询。@GraphQlRepository
DataFetcher
默认情况下,查询返回的 GraphQL 类型的名称必须与简单名称匹配
的存储库域类型。如果需要,您可以使用 的属性 of 指定目标 GraphQL 类型名称。typeName
@GraphQlRepository
对于分页查询,仓库域类型的简单名称必须与不带结尾的类型名称匹配(例如 matches 的 )。对于自动注册,分页是基于偏移的,有 20 个项目
每页。Connection
Connection
Book
BooksConnection
自动注册检测给定存储库是否实现
透明地通过 Builder 方法应用它。QuerydslBinderCustomizer
QuerydslDataFetcher
自动注册是通过内置的
从 获得。Boot Starter 自动
检测 bean 并使用它们来初始化 with.RuntimeWiringConfigurer
QuerydslDataFetcher
@GraphQlRepository
RuntimeWiringConfigurer
对于作为 GraphQL 输入类型的单个参数,嵌套一个
level down 并使用参数 sub-map 中的值。QuerydslDataFetcher |
要了解什么是投影,请参阅 Spring Data 文档。 要了解如何在 GraphQL 中使用投影,请参阅选择集与投影。 |
按示例查询
Spring Data 支持使用 Query by Example 来获取数据。Example 查询 (QBE) 是一种简单的查询技术,不需要 you 通过特定于 store 的查询语言编写查询。
首先声明一个存储库,该存储库为:QueryByExampleExecutor
public interface AccountRepository extends Repository<Account, Long>,
QueryByExampleExecutor<Account> {
}
用于将存储库转换为 :QueryByExampleDataFetcher
DataFetcher
// For single result queries
DataFetcher<Account> dataFetcher =
QueryByExampleDataFetcher.builder(repository).single();
// For multi-result queries
DataFetcher<Iterable<Account>> dataFetcher =
QueryByExampleDataFetcher.builder(repository).many();
// For paginated queries
DataFetcher<Iterable<Account>> dataFetcher =
QueryByExampleDataFetcher.builder(repository).scrollable();
你现在可以通过 RuntimeWiringConfigurer
注册上述内容。DataFetcher
使用 GraphQL 参数映射来创建
repository 并使用它作为示例对象来获取数据。Spring Data 支持 JPA、MongoDB、Neo4j 和 Redis。DataFetcher
QueryByExampleDataFetcher
对于作为 GraphQL 输入类型的单个参数,向下嵌套一层,并与参数子映射中的值绑定。QueryByExampleDataFetcher |
如果存储库为 ,则生成器将返回 或 。Spring Data 支持此功能
MongoDB、Neo4j、Redis 和 R2dbc 的变体。ReactiveQueryByExampleExecutor
DataFetcher<Mono<Account>>
DataFetcher<Flux<Account>>
定制
QueryByExampleDataFetcher
支持接口和 DTO 投影以转换查询
结果,然后再返回这些内容以供进一步的 GraphQL 处理。
要了解什么是投影,请参阅 Spring Data 文档。 要了解投影在 GraphQL 中的作用,请参阅选择集与投影。 |
要将 Spring Data 投影与 Query by Example 存储库一起使用,请创建一个投影接口
或目标 DTO 类,并通过该方法对其进行配置,以获取生成目标类型:projectAs
DataFetcher
class Account {
String name, identifier, description;
Person owner;
}
interface AccountProjection {
String getName();
String getIdentifier();
}
// For single result queries
DataFetcher<AccountProjection> dataFetcher =
QueryByExampleDataFetcher.builder(repository).projectAs(AccountProjection.class).single();
// For multi-result queries
DataFetcher<Iterable<AccountProjection>> dataFetcher =
QueryByExampleDataFetcher.builder(repository).projectAs(AccountProjection.class).many();
自动注册
如果存储库带有 注释,则它会自动注册
对于尚未注册且返回类型
与存储库域类型的匹配。这包括单值查询、多值
queries 和分页查询。@GraphQlRepository
DataFetcher
默认情况下,查询返回的 GraphQL 类型的名称必须与简单名称匹配
的存储库域类型。如果需要,您可以使用 的属性 of 指定目标 GraphQL 类型名称。typeName
@GraphQlRepository
对于分页查询,仓库域类型的简单名称必须与不带结尾的类型名称匹配(例如 matches 的 )。对于自动注册,分页是基于偏移的,有 20 个项目
每页。Connection
Connection
Book
BooksConnection
自动注册是通过内置的
从 获得。Boot Starter 自动
检测 bean 并使用它们来初始化 with.RuntimeWiringConfigurer
QueryByExampleDataFetcher
@GraphQlRepository
RuntimeWiringConfigurer
对于作为 GraphQL 输入类型的单个参数,向下嵌套一层,并与参数子映射中的值绑定。QueryByExampleDataFetcher |
要了解什么是投影,请参阅 Spring Data 文档。 要了解投影在 GraphQL 中的作用,请参阅选择集与投影。 |
选择集与投影
出现的一个常见问题是,GraphQL 选择集与 Spring Data 预测相比如何,每个选择集扮演什么角色?
简短的回答是,Spring for GraphQL 不是转换 GraphQL 的数据网关 查询直接转换为 SQL 或 JSON 查询。相反,它允许您利用现有的 Spring 技术,并且不假定 GraphQL 架构与 底层数据模型。这就是客户驱动的选择和服务器端转换的原因 的数据模型可以起到互补的作用。
为了更好地理解,请考虑 Spring Data 将域驱动 (DDD) 设计提升为 管理数据层复杂性的推荐方法。在 DDD 中,它很重要 以遵守聚合的约束。根据定义,聚合仅在以下情况下有效 load 的 聚合功能。
在 Spring Data 中,您可以选择是希望聚合按原样公开,还是 是否在将数据模型作为 GraphQL 返回之前将其应用于数据模型 结果。有时,执行前者就足够了,默认情况下,Querydsl 和 Query by Example 集成会使 GraphQL selection set 的 set 设置为 property path 提示,底层 Spring Data 模块使用 限制选择。
在其他情况下,减少甚至转换 来适应 GraphQL 架构。Spring Data 通过 Interface 支持此功能 和 DTO Projections。
接口投影定义一组固定的属性,以公开属性可能或
可能不是 ,具体取决于 Data Store 查询结果。有两种
接口投影,这两者都决定了要从底层加载哪些属性
数据来源:null
-
如果无法部分具体化聚合对象,但仍能实现封闭界面投影,则闭合界面投影会很有帮助 想要公开属性的子集。
-
开放接口投影利用 Spring 的 Comments 和 SpEL 表达式来应用轻量级 数据转换,例如串联、计算或应用静态函数 添加到属性。
@Value
DTO 投影提供了更高级别的自定义,因为您可以放置转换 代码 (code 要么在 constructor 要么 getter methods) 中。
DTO 投影从各个属性所在的查询中实现 由投影本身确定。DTO 投影通常与 full-args 一起使用 构造函数(例如 Java 记录),因此只有在所有 必填字段(或列)是数据库查询结果的一部分。
滚动
如分页中所述,GraphQL 游标连接规范定义了一个
使用 、 和 schema 类型进行分页的机制,而
GraphQL Java 提供等效的 Java 类型表示形式。Connection
Edge
PageInfo
Spring for GraphQL 提供了内置实现来适应
Spring Data 分页类型和透明。您可以配置
如下:ConnectionAdapter
Window
Slice
CursorStrategy<ScrollPosition> strategy = CursorStrategy.withEncoder(
new ScrollPositionCursorStrategy(),
CursorEncoder.base64()); (1)
GraphQLTypeVisitor visitor = ConnectionFieldTypeVisitor.create(List.of(
new WindowConnectionAdapter(strategy),
new SliceConnectionAdapter(strategy))); (2)
GraphQlSource.schemaResourceBuilder()
.schemaResources(..)
.typeDefinitionConfigurer(..)
.typeVisitors(List.of(visitor)); (3)
1 | 创建转换为 Base64 编码游标的策略。ScrollPosition |
2 | 创建类型 visitor 以适应并从 s 返回。Window Slice DataFetcher |
3 | 注册 visitor 类型。 |
在请求端,控制器方法可以声明 ScrollSubrange 方法参数以向前分页
或向后。为此,您必须将 CursorStrategy
支持声明为 bean。ScrollPosition
Boot Starter 声明一个 bean,如果 Spring Data 在 Classpath 上,则如上所述注册 。CursorStrategy<ScrollPosition>
ConnectionFieldTypeVisitor
1 | 创建转换为 Base64 编码游标的策略。ScrollPosition |
2 | 创建类型 visitor 以适应并从 s 返回。Window Slice DataFetcher |
3 | 注册 visitor 类型。 |
关键帧集位置
对于 ,游标需要从键集创建,该键集为
本质上是键值对。要决定如何从键集创建游标,请执行以下操作:
您可以使用 进行配置。
默认情况下,将密钥集写入 JSON。这适用于
简单,如 String、Boolean、Integer 和 Double,但其他无法恢复到
没有目标类型信息的相同类型。Jackson 库具有默认的键入功能
,它可以在 JSON 中包含类型信息。要安全地使用它,您必须指定一个
允许的类型。例如:KeysetScrollPosition
Map
ScrollPositionCursorStrategy
CursorStrategy<Map<String, Object>>
JsonKeysetCursorStrategy
Map
PolymorphicTypeValidator validator = BasicPolymorphicTypeValidator.builder()
.allowIfBaseType(Map.class)
.allowIfSubType(ZonedDateTime.class)
.build();
ObjectMapper mapper = new ObjectMapper();
mapper.activateDefaultTyping(validator, ObjectMapper.DefaultTyping.NON_FINAL);
然后,您可以创建 :JsonKeysetCursorStrategy
ObjectMapper mapper = ... ;
CodecConfigurer configurer = ServerCodecConfigurer.create();
configurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(mapper));
configurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(mapper));
JsonKeysetCursorStrategy strategy = new JsonKeysetCursorStrategy(configurer);
默认情况下,如果创建时没有 a 和
Jackson 库位于类路径上,则上述自定义将应用于 、 以及 中的任何类型。JsonKeysetCursorStrategy
CodecConfigurer
Date
Calendar
java.time
排序
Spring for GraphQL 定义了一个从 GraphQL 参数创建的。 使用抽象方法实现 Contract 以提取排序
direction 和 properties 的 Direction 和 Properties 进行访问。要启用对作为控制器方法参数的支持,
您需要声明一个 bean。SortStrategy
Sort
AbstractSortStrategy
Sort
SortStrategy