Spring for GraphQL 允许您利用现有的 Spring 技术,遵循常见的 对模型进行编程,以通过 GraphQL 公开基础数据源。
本节讨论 Spring Data 的集成层,该集成层提供了一种简单的方法
将 Querydsl 或 Query by Example 存储库改编为 ,包括
用于自动检测和 GraphQL 查询注册标记的存储库的选项
跟。DataFetcher@GraphQlRepository
查询
Spring for GraphQL 支持使用 Querydsl 通过 Spring Data Querydsl 扩展。 Querydsl 提供了一种灵活且类型安全的方法,可以通过以下方式表达查询谓词 使用注释处理器生成元模型。
例如,将存储库声明为: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。DataFetcherPredicateQuerydslPredicateExecutor
对于作为 GraphQL 输入类型的单个参数,嵌套一个
降低水平,并使用参数子映射中的值。QuerydslDataFetcher |
如果存储库为 ,则构建器返回 或 。Spring Data 支持这一点
MongoDB 和 Neo4j 的变体。ReactiveQuerydslPredicateExecutorDataFetcher<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 。默认情况下,参数绑定为“等于”
每个可用属性。要自定义它,您可以使用构建器
提供 .PredicateQuerydslDataFetcherQuerydslBinderCustomizer
存储库本身可以是 的实例。这是自动检测的
并在自动注册期间透明地应用。但是,当手动
构建 您需要使用构建器方法来应用它。QuerydslBinderCustomizerQuerydslDataFetcher
QuerydslDataFetcher支持接口和 DTO 投影来转换查询结果
在返回这些以进行进一步的 GraphQL 处理之前。
| 要了解什么是预测,请参阅 Spring Data 文档。 要了解如何在 GraphQL 中使用投影,请参阅选择集与投影。 |
要将 Spring Data 投影与 Querydsl 存储库一起使用,请创建投影接口
或目标 DTO 类,并通过该方法对其进行配置,以获得生成目标类型:projectAsDataFetcher
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();
自动注册
如果存储库使用 注释,则会自动注册
对于尚未注册且返回类型尚未注册的查询
与存储库域类型匹配。这包括单值查询、多值查询
查询和分页查询。@GraphQlRepositoryDataFetcher
默认情况下,查询返回的 GraphQL 类型的名称必须与简单名称匹配
存储库域类型。如果需要,可以使用 的属性来指定目标 GraphQL 类型名称。typeName@GraphQlRepository
对于分页查询,存储库域类型的简单名称必须与类型名称匹配,而不带结尾(例如 匹配)。对于自动注册,分页是基于偏移量的,有 20 个项目
每页。ConnectionConnectionBookBooksConnection
自动注册检测给定存储库是否实现和
通过构建器方法透明地应用它。QuerydslBinderCustomizerQuerydslDataFetcher
自动注册是通过内置的
从 获得。Boot Starter 自动
检测 Bean 并使用它们来初始化 with。RuntimeWiringConfigurerQuerydslDataFetcher@GraphQlRepositoryRuntimeWiringConfigurer
自动注册通过调用存储库实例来应用自定义项,如果您的存储库
分别实现或。customize(Builder)QuerydslBuilderCustomizerReactiveQuerydslBuilderCustomizer
对于作为 GraphQL 输入类型的单个参数,嵌套一个
降低水平,并使用参数子映射中的值。QuerydslDataFetcher |
| 要了解什么是预测,请参阅 Spring Data 文档。 要了解如何在 GraphQL 中使用投影,请参阅选择集与投影。 |
按示例查询
Spring Data 支持使用 Query by Example 来获取数据。示例查询 (QBE) 是一种简单的查询技术,不需要 通过特定于存储的查询语言编写查询。
首先声明一个存储库,该存储库是:QueryByExampleExecutor
public interface AccountRepository extends Repository<Account, Long>,
QueryByExampleExecutor<Account> {
}
用于将存储库转换为:QueryByExampleDataFetcherDataFetcher
// 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 参数映射创建域类型
存储库,并将其用作获取数据的示例对象。Spring Data 支持 JPA、MongoDB、Neo4j 和 Redis。DataFetcherQueryByExampleDataFetcher
对于作为 GraphQL 输入类型的单个参数,向下嵌套一级,并与参数子映射中的值绑定。QueryByExampleDataFetcher |
如果存储库为 ,则构建器返回 或 。Spring Data 支持这一点
MongoDB、Neo4j、Redis 和 R2dbc 的变体。ReactiveQueryByExampleExecutorDataFetcher<Mono<Account>>DataFetcher<Flux<Account>>
定制
QueryByExampleDataFetcher支持接口和 DTO 投影来转换查询
结果,然后返回这些结果以进行进一步的 GraphQL 处理。
| 要了解什么是投影,请参阅 Spring Data 文档。 要了解投影在 GraphQL 中的作用,请参阅选择集与投影。 |
要将 Spring Data 投影与 Query by Example 存储库一起使用,请创建投影接口
或目标 DTO 类,并通过该方法对其进行配置,以获得生成目标类型:projectAsDataFetcher
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();
自动注册
如果存储库使用 注释,则会自动注册
对于尚未注册且返回类型尚未注册的查询
与存储库域类型匹配。这包括单值查询、多值查询
查询和分页查询。@GraphQlRepositoryDataFetcher
默认情况下,查询返回的 GraphQL 类型的名称必须与简单名称匹配
存储库域类型。如果需要,可以使用 的属性来指定目标 GraphQL 类型名称。typeName@GraphQlRepository
对于分页查询,存储库域类型的简单名称必须与类型名称匹配,而不带结尾(例如 匹配)。对于自动注册,分页是基于偏移量的,有 20 个项目
每页。ConnectionConnectionBookBooksConnection
自动注册是通过内置的
从 获得。Boot Starter 自动
检测 Bean 并使用它们来初始化 with。RuntimeWiringConfigurerQueryByExampleDataFetcher@GraphQlRepositoryRuntimeWiringConfigurer
自动注册通过调用存储库实例来应用自定义项,如果您的存储库
分别实现或。customize(Builder)QueryByExampleBuilderCustomizerReactiveQueryByExampleBuilderCustomizer
对于作为 GraphQL 输入类型的单个参数,向下嵌套一级,并与参数子映射中的值绑定。QueryByExampleDataFetcher |
| 要了解什么是投影,请参阅 Spring Data 文档。 要了解投影在 GraphQL 中的作用,请参阅选择集与投影。 |
选择集与投影
出现的一个常见问题是,GraphQL 选择集与 Spring Data 投影相比如何,每个预测集扮演什么角色?
简短的回答是,Spring for GraphQL 不是翻译 GraphQL 的数据网关 直接查询到 SQL 或 JSON 查询中。相反,它允许您利用现有的 Spring 技术,并且不假设 GraphQL 模式和 基础数据模型。这就是客户端驱动的选择和服务器端转换的原因 的数据模型可以起到互补的作用。
为了更好地理解,请考虑 Spring Data 将领域驱动 (DDD) 设计提升为 管理数据层复杂性的推荐方法。在 DDD 中,这很重要 遵守聚合的约束。根据定义,聚合仅在以下情况下才有效 整体加载,因为部分加载的聚合可能会对 聚合功能。
在 Spring Data 中,您可以选择是否希望聚合按原样公开,或者 是否在将数据模型作为 GraphQL 返回之前将其应用于数据模型 结果。有时,执行前者就足够了,默认情况下,Querydsl 和 Query by Example 集成会将 GraphQL 转换为 GraphQL 选择设置到属性路径中提示底层 Spring Data 模块用于 限制选择。
在其他情况下,减少甚至转换基础数据模型很有用 order 以适应 GraphQL 模式。Spring Data通过接口支持这一点 和 DTO 预测。
接口投影定义一组固定的属性,以公开属性可能或
可能不是 ,具体取决于数据存储查询结果。有两种
接口投影都决定了要从基础加载哪些属性
数据来源:null
DTO 投影提供更高级别的自定义,因为您可以放置转换 在构造函数或 getter 方法中编写代码。
DTO 投影从各个属性所在的查询中实现 由投影本身决定。DTO 投影通常与全参数一起使用 构造函数(例如 Java 记录),因此它们只能在以下情况下构造 必填字段(或列)是数据库查询结果的一部分。
滚动
如分页中所述,GraphQL 游标连接规范定义了一个
使用 、 和 模式类型进行分页的机制,而
GraphQL Java 提供等效的 Java 类型表示。ConnectionEdgePageInfo
Spring for GraphQL 提供了内置的实现来适应
Spring Data 分页类型和透明。您可以对其进行配置
如下:ConnectionAdapterWindowSlice
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 返回。WindowSliceDataFetcher |
| 3 | 注册类型访客。 |
在请求端,控制器方法可以声明 ScrollSubrange 方法参数以向前分页
或向后。为此,您必须将 CursorStrategy 支持声明为 Bean。ScrollPosition
Boot Starter 声明一个 bean,如果 Spring Data 在类路径上,则如上所示注册 bean。CursorStrategy<ScrollPosition>ConnectionFieldTypeVisitor
| 1 | 创建转换为 Base64 编码游标的策略。ScrollPosition |
| 2 | 创建类型 visitor 进行适应并从 s 返回。WindowSliceDataFetcher |
| 3 | 注册类型访客。 |
键集位置
对于 ,需要从键集创建游标,该键集是
本质上是键值对的 a。要决定如何从键集创建游标,
您可以使用 .
默认情况下,将密钥集写入 JSON。这适用于
像 String、Boolean、Integer 和 Double 一样简单,但其他的无法恢复到
没有目标类型信息的相同类型。Jackson 库具有默认的打字功能
可以在 JSON 中包含类型信息。为了安全地使用它,您必须指定一个列表
允许的类型。例如:KeysetScrollPositionMapScrollPositionCursorStrategyCursorStrategy<Map<String, Object>>JsonKeysetCursorStrategyMap
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 库位于类路径上,如上所述的自定义项适用于 、 和 中的任何类型。JsonKeysetCursorStrategyCodecConfigurerDateCalendarjava.time
排序
Spring for GraphQL 定义了一个要从 GraphQL 参数创建的参数。 使用抽象方法实现合约以提取排序
方向和属性。若要启用对 as a controller 方法参数的支持,
您需要声明一个 Bean。SortStrategySortAbstractSortStrategySortSortStrategy