6. 带注释的控制器
Spring for GraphQL 提供了一个基于注释的编程模型,其中@Controller
组件使用注解来声明具有灵活方法签名的处理程序方法,以
获取特定 GraphQL 字段的数据。例如:
@Controller
public class GreetingController {
@QueryMapping (1)
public String hello() { (2)
return "Hello, world!";
}
}
1 | 将此方法绑定到查询,即 Query 类型下的字段。 |
2 | 如果未在注释上声明,则从方法名称确定查询。 |
Spring for GraphQL 使用RuntimeWiring.Builder
要将上述处理程序方法注册为graphql.schema.DataFetcher
对于名为 “hello” 的查询。
6.1. 声明
您可以定义@Controller
beans 作为标准的 Spring bean 定义。这@Controller
stereotype 允许自动检测,与 Spring 通用一致
支持检测@Controller
和@Component
类路径和
为它们自动注册 bean 定义。它还充当带注释的
类,指示其在 GraphQL 应用程序中作为数据获取组件的角色。
AnnotatedControllerConfigurer
检测@Controller
bean 并注册其
注解的处理程序方法为DataFetcher
S 通过RuntimeWiring.Builder
.它是一个
实现RuntimeWiringConfigurer
可以添加到GraphQlSource.Builder
.
Spring Boot Starters会自动声明AnnotatedControllerConfigurer
作为 Bean
并添加所有RuntimeWiringConfigurer
beans 设置为GraphQlSource.Builder
这使得
支持 AnnotatedDataFetcher
,请参阅 GraphQL RuntimeWiring 部分
在 Boot Starter 文档中。
6.2.@SchemaMapping
这@SchemaMapping
annotation 将处理程序方法映射到 GraphQL 架构中的字段
并声明它是DataFetcher
对于该字段。注解可以指定
父类型名称,以及字段名称:
@Controller
public class BookController {
@SchemaMapping(typeName="Book", field="author")
public Author getAuthor(Book book) {
// ...
}
}
这@SchemaMapping
annotation 也可以省略这些属性,在这种情况下,
field name 默认为 method name,而 type name 默认为 simple 类
注入方法的源/父对象的名称。例如,下面的
默认为 type “Book” 和字段 “author”:
@Controller
public class BookController {
@SchemaMapping
public Author author(Book book) {
// ...
}
}
这@SchemaMapping
注解可以在类级别声明以指定默认的
键入类中所有处理程序方法的 name。
@Controller
@SchemaMapping(typeName="Book")
public class BookController {
// @SchemaMapping methods for fields of the "Book" type
}
@QueryMapping
,@MutationMapping
和@SubscriptionMapping
是元注释,这些
本身被注释为@SchemaMapping
并将 typeName 预设为Query
,Mutation
或Subscription
分别。实际上,这些是快捷方式注释
for 字段 Query, Mutation 和 Subscription 类型。例如:
@Controller
public class BookController {
@QueryMapping
public Book bookById(@Argument Long id) {
// ...
}
@MutationMapping
public Book addBook(@Argument BookInput bookInput) {
// ...
}
@SubscriptionMapping
public Flux<Book> newPublications() {
// ...
}
}
@SchemaMapping
处理程序方法具有灵活的签名,并且可以从一系列
方法参数和返回值..
6.2.1. 方法签名
架构映射处理程序方法可以具有以下任何方法参数:
方法参数 | 描述 |
---|---|
|
用于访问绑定到更高级别类型化 Object 的命名字段参数。
看 |
|
用于访问绑定到更高级别类型化 Object 的所有字段参数。
看 |
|
要访问参数的原始映射,其中 |
|
用于访问参数的原始映射。 |
|
用于通过项目接口访问字段参数。
看 |
“来源” |
用于访问字段的源(即父级/容器)实例。 请参阅源代码。 |
|
要访问 |
|
要从主 |
|
要从本地 |
|
要从 |
|
从 Spring Security 上下文获取(如果可用)。 |
|
要访问 |
|
要通过 |
|
要访问 |
|
用于直接访问底层 |
架构映射处理程序方法可以返回:
-
任何类型的 resolved 值。
-
Mono
和Flux
对于异步值。支持控制器方法和 任何DataFetcher
如反应性的DataFetcher
. -
java.util.concurrent.Callable
以异步方式生成值。 要使其正常工作,AnnotatedControllerConfigurer
必须配置Executor
.
6.2.2.@Argument
在 GraphQL Java 中,DataFetchingEnvironment
提供对特定于字段的映射的访问权限
argument 值。这些值可以是简单的标量值(例如 String、Long)、一个Map
之
值进行更复杂的输入,或者List
的值。
使用@Argument
annotation 将参数绑定到目标对象,并将
注入到 handler 方法中。通过将参数值映射到
primary data 构造函数,或者使用默认的
constructor 创建对象,然后将 argument 值映射到其属性。这是
递归重复,使用所有嵌套参数值并创建嵌套目标对象
因此。例如:
@Controller
public class BookController {
@QueryMapping
public Book bookById(@Argument Long id) {
// ...
}
@MutationMapping
public Book addBook(@Argument BookInput bookInput) {
// ...
}
}
默认情况下,如果方法参数名称可用(需要-parameters
编译器
标志替换为 Java 8+ 或编译器中的调试信息),它用于查找参数。
如果需要,您可以通过 annotation 自定义名称,例如@Argument("bookInput")
.
这@Argument annotation 没有 “required” 标志,也没有
指定 Default (默认值)。这两者都可以在 GraphQL 架构级别指定,并且
由 GraphQL Java 强制执行。 |
如果绑定失败,则BindException
引发时,绑定问题累积为字段
错误,其中field
是出现问题的参数路径。
您可以使用@Argument
替换为Map<String, Object>
参数获取
all 参数值。的 name 属性@Argument
不得设置。
6.2.3.@Arguments
使用@Arguments
注解,如果要将完整的 arguments 映射到单个
target Object 与@Argument
,它绑定一个特定的命名参数。
例如@Argument BookInput bookInput
使用参数 “bookInput” 的值
初始化BookInput
而@Arguments
使用完整的参数 map,并在该
case 时,顶级参数绑定到BookInput
性能。
您可以使用@Arguments
替换为Map<String, Object>
参数获取
all 参数值。
6.2.4.@ProjectedPayload
接口
作为使用 完整 Object 的替代方法@Argument
,
您还可以使用投影接口通过
定义明确的最小接口。当 Spring Data 位于 class path 上时,参数投影由 Spring Data 的接口投影提供。
要使用此功能,请创建一个带有@ProjectedPayload
并声明
it 作为控制器方法参数。如果参数带有@Argument
,
它适用于DataFetchingEnvironment.getArguments()
地图。当声明时没有@Argument
,则投影适用于
完整的 arguments 映射。
例如:
@Controller
public class BookController {
@QueryMapping
public Book bookById(BookIdProjection bookId) {
// ...
}
@MutationMapping
public Book addBook(@Argument BookInputProjection bookInput) {
// ...
}
}
@ProjectedPayload
interface BookIdProjection {
Long getId();
}
@ProjectedPayload
interface BookInputProjection {
String getName();
@Value("#{target.author + ' ' + target.name}")
String getAuthorAndName();
}
6.2.5. 源码
在 GraphQL Java 中,DataFetchingEnvironment
提供对源(即
parent/container) 实例。要访问它,只需声明一个 method 参数
的预期目标类型。
@Controller
public class BookController {
@SchemaMapping
public Author author(Book book) {
// ...
}
}
source method 参数还有助于确定 Map 的类型名称。
如果 Java 类的简单名称与 GraphQL 类型匹配,则无需
在@SchemaMapping
注解。
一个 |
6.2.6.DataLoader
当您为实体注册批量加载函数时,如批量加载中所述,您可以访问DataLoader
通过声明
method 参数DataLoader
并使用它来加载实体:
@Controller
public class BookController {
public BookController(BatchLoaderRegistry registry) {
registry.forTypePair(Long.class, Author.class).registerMappedBatchLoader((authorIds, env) -> {
// return Map<Long, Author>
});
}
@SchemaMapping
public CompletableFuture<Author> author(Book book, DataLoader<Long, Author> loader) {
return loader.load(book.getAuthorId());
}
}
默认情况下,BatchLoaderRegistry
使用值类型的完整类名(例如
的类名Author
) 作为注册的密钥,因此只需声明
这DataLoader
method 参数提供足够的信息
要在DataLoaderRegistry
.作为回退,DataLoader
method 参数
Resolver 还会尝试将方法参数 name 作为键,但通常不应这样做
是必要的。
请注意,对于加载相关实体的许多情况,其中@SchemaMapping
只是
delegates 传递给DataLoader
,您可以使用@BatchMapping方法减少样板,如下一节所述。
6.2.7. 验证
当javax.validation.Validator
bean 的AnnotatedControllerConfigurer
启用对带 Comments 的 Controller 方法的 Bean 验证的支持。通常,该 bean 的类型为LocalValidatorFactoryBean
.
Bean 验证允许你对类型声明约束:
public class BookInput {
@NotNull
private String title;
@NotNull
@Size(max=13)
private String isbn;
}
然后,您可以使用@Valid
之前验证它
方法调用:
@Controller
public class BookController {
@MutationMapping
public Book addBook(@Argument @Valid BookInput bookInput) {
// ...
}
}
如果在验证过程中发生错误,则ConstraintViolationException
被提升。
您可以使用 Exception Resolution 链来决定如何向客户端呈现该消息
将其转换为错误以包含在 GraphQL 响应中。
除了@Valid ,您还可以使用 Spring 的@Validated 这允许
指定验证组。 |
Bean 验证可用于@Argument
,@Arguments
@ProjectedPayload方法参数,但更普遍地适用于任何方法参数。
验证和 Kotlin 协程
Hibernate Validator 与 Kotlin 协程方法不兼容,并且在 内省他们的方法参数。请参阅 spring-projects/spring-graphql#344 (评论) 以获取相关问题的链接和建议的解决方法。 |
6.3.@BatchMapping
批量加载通过使用org.dataloader.DataLoader
来延迟单个实体实例的加载,因此它们
可以一起加载。例如:
@Controller
public class BookController {
public BookController(BatchLoaderRegistry registry) {
registry.forTypePair(Long.class, Author.class).registerMappedBatchLoader((authorIds, env) -> {
// return Map<Long, Author>
});
}
@SchemaMapping
public CompletableFuture<Author> author(Book book, DataLoader<Long, Author> loader) {
return loader.load(book.getAuthorId());
}
}
对于加载关联实体的直接情况(如上所示),@SchemaMapping
方法只不过是将DataLoader
.这是
样板,可以使用@BatchMapping
方法。例如:
@Controller
public class BookController {
@BatchMapping
public Mono<Map<Book, Author>> author(List<Book> books) {
// ...
}
}
以上就变成了BatchLoaderRegistry
键所在的位置Book
实例和 loaded 的值的作者。此外,一个DataFetcher
也透明地绑定到author
类型为Book
哪
只需将DataLoader
对于作者,给定其源/父级Book
实例。
要用作唯一键, |
默认情况下,字段名称默认为方法名称,而类型名称默认为
输入的简单类名List
元素类型。两者都可以通过以下方式进行定制
annotation 属性。类型名称也可以从类级别继承@SchemaMapping
.
6.3.1. 方法签名
批量映射方法支持以下参数:
方法参数 | 描述 |
---|---|
|
源/父对象。 |
|
从 Spring Security 上下文获取(如果可用)。 |
|
要从 |
|
要从 |
|
GraphQL Java 中可用的环境到 |
批量映射方法可以返回:
返回类型 | 描述 |
---|---|
|
一个映射,其中父对象作为键,批量加载的对象作为值。 |
|
批量加载的对象序列,必须与源/父对象的顺序相同 对象。 |
|
命令式变体,例如,无需远程调用。 |
|
异步调用的命令式变体。要使其正常工作, |