Annotated Controllers

Spring for GraphQL 提供了一个基于注解的编程模型,其中 @Controller 组件使用注解来声明具有灵活方法签名的处理程序方法,以获取特定 GraphQL 字段的数据。例如:

Spring for GraphQL provides an annotation-based programming model where @Controller components use annotations to declare handler methods with flexible method signatures to fetch the data for specific GraphQL fields. For example:

@Controller
public class GreetingController {

		@QueryMapping (1)
		public String hello() { (2)
			return "Hello, world!";
		}

}
1 Bind this method to a query, i.e. a field under the Query type.
2 Determine the query from the method name if not declared on the annotation.

Spring for GraphQL 使用 RuntimeWiring.Builder 将上述处理程序方法注册为名为“hello”的查询的 graphql.schema.DataFetcher

Spring for GraphQL uses RuntimeWiring.Builder to register the above handler method as a graphql.schema.DataFetcher for the query named "hello".

Declaration

你可以将 @Controller bean 定义为标准 Spring bean 定义。@Controller 刻板印象允许自动检测,这与 Spring 对检测类路径上的 @Controller@Component 类以及自动注册它们的 bean 定义的一般支持一致。它还充当注解类的刻板印象,指示其在 GraphQL 应用程序中作为数据获取组件的角色。

You can define @Controller beans as standard Spring bean definitions. The @Controller stereotype allows for auto-detection, aligned with Spring general support for detecting @Controller and @Component classes on the classpath and auto-registering bean definitions for them. It also acts as a stereotype for the annotated class, indicating its role as a data fetching component in a GraphQL application.

AnnotatedControllerConfigurer 检测 @Controller bean,并将其带注释的处理程序方法注册为 DataFetcher`s via `RuntimeWiring.Builder。它是 RuntimeWiringConfigurer 的实现,可以添加到 GraphQlSource.BuilderBoot Starter 自动声明 AnnotatedControllerConfigurer 为 bean,并将所有 RuntimeWiringConfigurer bean 添加到 GraphQlSource.Builder,这样便支持带注释的 DataFetcher,请参阅启动器文档中的 GraphQL RuntimeWiring 部分。

AnnotatedControllerConfigurer detects @Controller beans and registers their annotated handler methods as DataFetcher`s via `RuntimeWiring.Builder. It is an implementation of RuntimeWiringConfigurer which can be added to GraphQlSource.Builder. The Boot Starter automatically declares AnnotatedControllerConfigurer as a bean and adds all RuntimeWiringConfigurer beans to GraphQlSource.Builder and that enables support for annotated `DataFetcher`s, see the GraphQL RuntimeWiring section in the Boot starter documentation.

@SchemaMapping

@SchemaMapping 注解将一个处理程序方法映射到 GraphQL schema 中的一个字段,并将其声明为该字段的 DataFetcher。注解可以指定父类型名称和字段名称:

The @SchemaMapping annotation maps a handler method to a field in the GraphQL schema and declares it to be the DataFetcher for that field. The annotation can specify the parent type name, and the field name:

@Controller
public class BookController {

	@SchemaMapping(typeName="Book", field="author")
	public Author getAuthor(Book book) {
		// ...
	}
}

@SchemaMapping 注解也可以省去那些属性,在这种情况下,字段名称默认为方法名,而类型名称默认为注射到方法中的源/父对象的简单类名。例如,下面默认为类型“Book”和字段“author”:

The @SchemaMapping annotation can also leave out those attributes, in which case the field name defaults to the method name, while the type name defaults to the simple class name of the source/parent object injected into the method. For example, the below defaults to type "Book" and field "author":

@Controller
public class BookController {

	@SchemaMapping
	public Author author(Book book) {
		// ...
	}
}

@SchemaMapping 注解可以在类级别声明,为类中的所有处理程序方法指定一个默认类型名称。

The @SchemaMapping annotation can be declared at the class level to specify a default type name for all handler methods in the class.

@Controller
@SchemaMapping(typeName="Book")
public class BookController {

	// @SchemaMapping methods for fields of the "Book" type

}

@QueryMapping@MutationMapping@SubscriptionMapping 是元注解,它们本身带 @SchemaMapping 注解,并且将 typeName 预设为 QueryMutationSubscription。实际上,这些是对 Query、Mutation 和 Subscription 类型下的字段的快捷方式注解。例如:

@QueryMapping, @MutationMapping, and @SubscriptionMapping are meta annotations that are themselves annotated with @SchemaMapping and have the typeName preset to Query, Mutation, or Subscription respectively. Effectively, these are shortcut annotations for fields under the Query, Mutation, and Subscription types respectively. For example:

@Controller
public class BookController {

	@QueryMapping
	public Book bookById(@Argument Long id) {
		// ...
	}

	@MutationMapping
	public Book addBook(@Argument BookInput bookInput) {
		// ...
	}

	@SubscriptionMapping
	public Flux<Book> newPublications() {
		// ...
	}
}

@SchemaMapping 处理程序方法具有灵活的签名,并且可以在一系列方法参数和返回值中进行选择。

@SchemaMapping handler methods have flexible signatures and can choose from a range of method arguments and return values..

Method Signature

Schema 映射处理程序方法可以具有以下任何方法参数:

Schema mapping handler methods can have any of the following method arguments:

Method Argument Description

@Argument

For access to a named field argument bound to a higher-level, typed Object.

See @Argument.

@Argument Map<String, Object>

For access to the raw argument value.

See @Argument.

ArgumentValue

For access to a named field argument bound to a higher-level, typed Object along with a flag to indicate if the input argument was omitted vs set to null.

See ArgumentValue.

@Arguments

For access to all field arguments bound to a higher-level, typed Object.

See @Arguments.

@Arguments Map<String, Object>

For access to the raw map of arguments.

@ProjectedPayload Interface

For access to field arguments through a project interface.

See @ProjectedPayload Interface.

"Source"

For access to the source (i.e. parent/container) instance of the field.

See Source.

Subrange and ScrollSubrange

For access to pagination arguments.

See Pagination, Scroll, Subrange.

Sort

For access to sort details.

See Pagination, Sort.

DataLoader

For access to a DataLoader in the DataLoaderRegistry.

See DataLoader.

@ContextValue

For access to an attribute from the main GraphQLContext in DataFetchingEnvironment.

@LocalContextValue

For access to an attribute from the local GraphQLContext in DataFetchingEnvironment.

GraphQLContext

For access to the context from the DataFetchingEnvironment.

java.security.Principal

Obtained from the Spring Security context, if available.

@AuthenticationPrincipal

For access to Authentication#getPrincipal() from the Spring Security context.

DataFetchingFieldSelectionSet

For access to the selection set for the query through the DataFetchingEnvironment.

Locale, Optional<Locale>

For access to the Locale from the DataFetchingEnvironment.

DataFetchingEnvironment

For direct access to the underlying DataFetchingEnvironment.

Schema 映射处理程序方法可以返回:

Schema mapping handler methods can return:

  • A resolved value of any type.

  • Mono and Flux for asynchronous value(s). Supported for controller methods and for any DataFetcher as described in Reactive DataFetcher.

  • java.util.concurrent.Callable to have the value(s) produced asynchronously. For this to work, AnnotatedControllerConfigurer must be configured with an Executor.

@Argument

在 GraphQL Java 中,DataFetchingEnvironment 提供对特定于字段的参数值的映射的访问。这些值可以是简单的标量值(例如 String、Long)、用于更复杂的输入的 Map 或值的 List

In GraphQL Java, DataFetchingEnvironment provides access to a map of field-specific argument values. The values can be simple scalar values (e.g. String, Long), a Map of values for more complex input, or a List of values.

使用 @Argument 注解使一个参数绑定到目标对象并注入到处理程序方法中。绑定是通过将参数值映射到预期的使用方法参数类型的基本数据构造函数或使用默认构造函数创建对象然后将参数值映射到其属性来执行的。这会递归重复,使用所有嵌套参数值,并相应地创建嵌套目标对象。例如:

Use the @Argument annotation to have an argument bound to a target object and injected into the handler method. Binding is performed by mapping argument values to a primary data constructor of the expected method parameter type, or by using a default constructor to create the object and then map argument values to its properties. This is repeated recursively, using all nested argument values and creating nested target objects accordingly. For example:

@Controller
public class BookController {

	@QueryMapping
	public Book bookById(@Argument Long id) {
		// ...
	}

	@MutationMapping
	public Book addBook(@Argument BookInput bookInput) {
		// ...
	}
}

如果目标对象没有 setter,并且您无法更改它,则可以使用 AnnotatedControllerConfigurer 中的 aproperty 来允许使用直接字段访问权限进行回退绑定。

If the target object doesn’t have setters, and you can’t change that, you can use a property on AnnotatedControllerConfigurer to allow falling back on binding via direct field access.

如果没有给出 method 参数名(Java 8 以上版本中需要使用 -parameters 编译器标记,或者要求编译器的调试信息),那么将使用它来查找参数。如果需要,您可以通过注释来自定义名称,例如:@Argument("bookInput").

By default, if the method parameter name is available (requires the -parameters compiler flag with Java 8+ or debugging info from the compiler), it is used to look up the argument. If needed, you can customize the name through the annotation, e.g. @Argument("bookInput").

@Argument 注释没有 “required” 标志,也没有指定默认值。可在 GraphQL Schema 级别指定这两者,并由 GraphQL Java 强制执行。

The @Argument annotation does not have a "required" flag, nor the option to specify a default value. Both of these can be specified at the GraphQL schema level and are enforced by GraphQL Java.

如果绑定失败,则会抛出一个 BindException,它会将绑定问题积累为 field 错误,其中每个错误的 field 都是出现问题后的参数路径。

If binding fails, a BindException is raised with binding issues accumulated as field errors where the field of each error is the argument path where the issue occurred.

使用一个 Map<String, Object> 参数,并配以 @Argument,就能获取参数的原始值。例如:

You can use @Argument with a Map<String, Object> argument, to obtain the raw value of the argument. For example:

@Controller
public class BookController {

	@MutationMapping
	public Book addBook(@Argument Map<String, Object> bookInput) {
		// ...
	}
}

在 1.2 之前,如果注释未指定名称,@Argument Map<String, Object> 将返回完整参数映射。在 1.2 之后,使用 Map<String, Object>@Argument 将始终返回原始参数值,匹配注释中指定的名称或参数名称。如需访问完整参数映射,请改为使用 xref:controllers.adoc#controllers.schema-mapping.arguments[@Arguments

Prior to 1.2, @Argument Map<String, Object> returned the full arguments map if the annotation did not specify a name. After 1.2, @Argument with Map<String, Object> always returns the raw argument value, matching either to the name specified in the annotation, or to the parameter name. For access to the full arguments map, please use @Arguments instead.

ArgumentValue

默认情况下,GraphQL 中的输入参数是可空的和可选的,这意味着可以在 null 文字中设置参数,或者根本不提供参数。这种区分对部分更新很有用,其中底层数据也可以相应地设置成 null 或根本不更改。当使用 xref:controllers.adoc#controllers.schema-mapping.argument[@Argument 时,无法做出这种区分,因为在两种情况下你都会得到 null 或一个空 Optional

By default, input arguments in GraphQL are nullable and optional, which means an argument can be set to the null literal, or not provided at all. This distinction is useful for partial updates with a mutation where the underlying data may also be, either set to null or not changed at all accordingly. When using @Argument there is no way to make such a distinction, because you would get null or an empty Optional in both cases.

如果您想了解一个值是否根本没有提供,则可以声明一个 ArgumentValue 方法参数,它是一个结果值的一个简单容器,并带有标志,以表示输入参数是否全部都已省略。您可以使用它来代替 @Argument,在这种情况下,参数名将根据方法参数名来决定,或者与 @Argument 一起使用来指定参数名。

If you want to know not whether a value was not provided at all, you can declare an ArgumentValue method parameter, which is a simple container for the resulting value, along with a flag to indicate whether the input argument was omitted altogether. You can use this instead of @Argument, in which case the argument name is determined from the method parameter name, or together with @Argument to specify the argument name.

例如:

For example:

@Controller
public class BookController {

	@MutationMapping
	public void addBook(ArgumentValue<BookInput> bookInput) {
		if (!bookInput.isOmitted()) {
			BookInput value = bookInput.value();
			// ...
		}
	}
}

ArgumentValue 也被支持为一个 @Argument 方法参数的对象结构中的一个字段,可以经由一个构造器参数或一个 setter 来初始化,包括作为位于顶层对象下任何级别的对象的字段。

ArgumentValue is also supported as a field within the object structure of an @Argument method parameter, either initialized via a constructor argument or via a setter, including as a field of an object nested at any level below the top level object.

@Arguments

如果您想将完整的参数映射捆绑到一个单独的目标对象上,而不是捆绑一个特定的带名字的参数,那么请使用 @Arguments 注释。

Use the @Arguments annotation, if you want to bind the full arguments map onto a single target Object, in contrast to @Argument, which binds a specific, named argument.

例如,@Argument BookInput bookInput 使用参数 "bookInput" 的值来初始化 BookInput,而 @Arguments 使用完整的参数映射,在这种情况下,顶层参数将被捆绑到 BookInput 属性。

For example, @Argument BookInput bookInput uses the value of the argument "bookInput" to initialize BookInput, while @Arguments uses the full arguments map and in that case, top-level arguments are bound to BookInput properties.

使用一个 Map<String, Object> 参数,并配以 @Arguments,就能获取所有参数值的原始映射。

You can use @Arguments with a Map<String, Object> argument, to obtain the raw map of all argument values.

@ProjectedPayload Interface

作为使用具有 @Argument 的完整对象的备选方案,您还可以使用投影接口通过明确定义的最小接口访问 GraphQL 请求参数。当 Spring Data 位于类路径中时,参数投影由 Spring Data’s Interface projections 提供。

As an alternative to using complete Objects with @Argument, you can also use a projection interface to access GraphQL request arguments through a well-defined, minimal interface. Argument projections are provided by Spring Data’s Interface projections when Spring Data is on the class path.

要使用此方法,请创建一个带有 @ProjectedPayload 注释的接口,并将其声明为一个控制器方法参数。如果参数带 @Argument 注释了,那么它将适用于 DataFetchingEnvironment.getArguments() 映射中的单个参数。当在没有 @Argument 的情况下声明该映射时,该投影将在完整的参数映射中的顶层参数上起作用。

To make use of this, create an interface annotated with @ProjectedPayload and declare it as a controller method parameter. If the parameter is annotated with @Argument, it applies to an individual argument within the DataFetchingEnvironment.getArguments() map. When declared without @Argument, the projection works on top-level arguments in the complete arguments map.

例如:

For example:

@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();
}

Source

在 GraphQL Java 中,DataFetchingEnvironment 提供对字段的来源(即父级/容器)实例的访问权限。要访问此方法,只需声明一个带有目标类型的预期方法参数。

In GraphQL Java, the DataFetchingEnvironment provides access to the source (i.e. parent/container) instance of the field. To access this, simply declare a method parameter of the expected target type.

@Controller
public class BookController {

	@SchemaMapping
	public Author author(Book book) {
		// ...
	}
}

源方法参数也有助于确定映射的类型名称。如果 Java 类的简单名称与 GraphQL 类型匹配,那么不需要在 @SchemaMapping 注释中显式指定类型名称。

The source method argument also helps to determine the type name for the mapping. If the simple name of the Java class matches the GraphQL type, then there is no need to explicitly specify the type name in the @SchemaMapping annotation.

@BatchMapping 处理程序方法可以批量加载给定源/父级书籍对象列表的查询的所有作者。

A @BatchMapping handler method can batch load all authors for a query, given a list of source/parent books objects.

Subrange

当 Spring 配置中有一个 xref:request-execution.adoc#execution.pagination.cursor.strategy[CursorStrategy bean 时,控制器方法支持 Subrange<P> 参数,其中 <P> 是从游标转换后的相对位置。对于 Spring Data,ScrollSubrange 引出 ScrollPosition。例如:

When there is a CursorStrategy bean in Spring configuration, controller methods support a Subrange<P> argument where <P> is a relative position converted from a cursor. For Spring Data, ScrollSubrange exposes ScrollPosition. For example:

@Controller
public class BookController {

	@QueryMapping
	public Window<Book> books(ScrollSubrange subrange) {
		ScrollPosition position = subrange.position().orElse(ScrollPosition.offset());
		int count = subrange.count().orElse(20);
		// ...
	}

}

有关分页和内置机制的概述,请参见 Pagination

See Pagination for an overview of pagination and of built-in mechanisms.

Sort

当 Spring 配置中存在 SortStrategy bean 时,控制器方法支持将 Sort 作为方法参数。例如:

When there is a SortStrategy bean in Spring configuration, controller methods support Sort as a method argument. For example:

@Controller
public class BookController {

	@QueryMapping
	public Window<Book> books(Optional<Sort> optionalSort) {
		Sort sort = optionalSort.orElse(Sort.by(..));
	}

}

DataLoader

当为实体注册批量加载函数(如 Batch Loading 中所述)时,可以通过声明 DataLoader 类型的 method 参数来访问该实体的 DataLoader,并使用它来加载该实体:

When you register a batch loading function for an entity, as explained in Batch Loading, you can access the DataLoader for the entity by declaring a method argument of type DataLoader and use it to load the entity:

@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 方法参数就能提供足够的信息在 DataLoaderRegistry 中找到它。作为备选方案,DataLoader 方法参数解析器还会尝试使用方法参数名作为密钥,但一般来说,这是没有必要的。

By default, BatchLoaderRegistry uses the full class name of the value type (e.g. the class name for Author) for the key of the registration, and therefore simply declaring the DataLoader method argument with generic types provides enough information to locate it in the DataLoaderRegistry. As a fallback, the DataLoader method argument resolver will also try the method argument name as the key but typically that should not be necessary.

请注意,对于许多与加载相关实体的情况,其中 @SchemaMapping 仅仅委派给 DataLoader,你可以通过使用下一节中所述的 @BatchMapping 方法来减少样板代码。

Note that for many cases with loading related entities, where the @SchemaMapping simply delegates to a DataLoader, you can reduce boilerplate by using a @BatchMapping method as described in the next section.

Validation

当找到 javax.validation.Validator bean 时, AnnotatedControllerConfigurer 允许在带注释的控制器方法上使用 Bean Validation。通常,bean 的类型为 LocalValidatorFactoryBean

When a javax.validation.Validator bean is found, AnnotatedControllerConfigurer enables support for Bean Validation on annotated controller methods. Typically, the bean is of type LocalValidatorFactoryBean.

Bean Validation 让你可以声明类型约束:

Bean validation lets you declare constraints on types:

public class BookInput {

	@NotNull
	private String title;

	@NotNull
	@Size(max=13)
	private String isbn;
}

然后,你可以在方法调用之前使用 @Valid 注释控制器方法参数,对其进行验证:

You can then annotate a controller method parameter with @Valid to validate it before method invocation:

@Controller
public class BookController {

	@MutationMapping
	public Book addBook(@Argument @Valid BookInput bookInput) {
		// ...
	}
}

如果在验证过程中发生错误,则会引发 ConstraintViolationException。你可以使用 Exceptions 链来决定如何将其显示给客户端,方法是将其转换为包含在 GraphQL 响应中的错误。

If an error occurs during validation, a ConstraintViolationException is raised. You can use the Exceptions chain to decide how to present that to clients by turning it into an error to include in the GraphQL response.

@Valid 之外,您还可以使用 Spring 的 @Validated,它允许指定验证组。

In addition to @Valid, you can also use Spring’s @Validated that allows specifying validation groups.

Bean 验证适用于 @Argument`、`@Arguments`` 和 @ProjectedPayload 方法参数,但更普遍地适用于任何方法参数。

Bean validation is useful for @Argument, @Arguments, and @ProjectedPayload method parameters, but applies more generally to any method parameter.

Example 1. Validation and Kotlin Coroutines

Hibernate Validator 与 Kotlin 协程方法不兼容,在内省其方法参数时会失败。请参阅 spring-projects/spring-graphql#344 (comment) 以获取相关问题的链接和建议的解决方法。

Hibernate Validator is not compatible with Kotlin Coroutine methods and fails when introspecting their method parameters. Please see spring-projects/spring-graphql#344 (comment) for links to relevant issues and a suggested workaround.

@BatchMapping

Batch Loading 通过使用 org.dataloader.DataLoader 来延迟加载各个实体实例,以便可以将它们一起加载,从而解决了 N+1 选择问题。例如:

Batch Loading addresses the N+1 select problem through the use of an org.dataloader.DataLoader to defer the loading of individual entity instances, so they can be loaded together. For example:

@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 方法避免的样板。例如:

For the straight-forward case of loading an associated entity, shown above, the @SchemaMapping method does nothing more than delegate to the DataLoader. This is boilerplate that can be avoided with a @BatchMapping method. For example:

@Controller
public class BookController {

	@BatchMapping
	public Mono<Map<Book, Author>> author(List<Book> books) {
		// ...
	}
}

上面的代码在 BatchLoaderRegistry 中成为一个批处理加载函数,其中键为 Book 实例,加载的值为其作者。此外,还将`DataFetcher` 透明地绑定到 Book 类型的 author 字段,它只是给定其源/父 Book 实例,委派给作者的`DataLoader`。

The above becomes a batch loading function in the BatchLoaderRegistry where keys are Book instances and the loaded values their authors. In addition, a DataFetcher is also transparently bound to the author field of the type Book, which simply delegates to the DataLoader for authors, given its source/parent Book instance.

为了用作唯一键,Book 必须实现 hashcode 和`equals`。

To be used as a unique key, Book must implement hashcode and equals.

默认情况下,字段名称默认为方法名称,而类型名称默认为输入 List 元素类型的简单类名称。两者都可以通过注释属性自定义。类型名称也可以从类级别的`@SchemaMapping` 继承。

By default, the field name defaults to the method name, while the type name defaults to the simple class name of the input List element type. Both can be customized through annotation attributes. The type name can also be inherited from a class level @SchemaMapping.

Method Signature

批处理映射方法支持以下参数:

Batch mapping methods support the following arguments:

Method Argument Description

List<K>

The source/parent objects.

java.security.Principal

Obtained from Spring Security context, if available.

@ContextValue

For access to a value from the GraphQLContext of BatchLoaderEnvironment, which is the same context as the one from the DataFetchingEnvironment.

GraphQLContext

For access to the context from the BatchLoaderEnvironment, which is the same context as the one from the DataFetchingEnvironment.

BatchLoaderEnvironment

The environment that is available in GraphQL Java to a org.dataloader.BatchLoaderWithContext.

批处理映射方法可以返回:

Batch mapping methods can return:

Return Type Description

Mono<Map<K,V>>

A map with parent objects as keys, and batch loaded objects as values.

Flux<V>

A sequence of batch loaded objects that must be in the same order as the source/parent objects passed into the method.

Map<K,V>, Collection<V>

Imperative variants, e.g. without remote calls to make.

Callable<Map<K,V>>, Callable<Collection<V>>

Imperative variants to be invoked asynchronously. For this to work, AnnotatedControllerConfigurer must be configured with an Executor.

@GraphQlExceptionHandler

使用 @GraphQlExceptionHandler 方法来使用灵活的 method signature 处理数据获取异常。当在控制器中声明时,异常处理程序方法适用于来自同一控制器的异常:

Use @GraphQlExceptionHandler methods to handle exceptions from data fetching with a flexible method signature. When declared in a controller, exception handler methods apply to exceptions from the same controller:

@Controller
public class BookController {

	@QueryMapping
	public Book bookById(@Argument Long id) {
		// ...
	}

	@GraphQlExceptionHandler
	public GraphQLError handle(BindException ex) {
		return GraphQLError.newError().errorType(ErrorType.BAD_REQUEST).message("...").build();
	}

}

@ControllerAdvice 中声明时,异常处理程序方法应用于所有控制器:

When declared in an @ControllerAdvice, exception handler methods apply across controllers:

@ControllerAdvice
public class GlobalExceptionHandler {

	@GraphQlExceptionHandler
	public GraphQLError handle(BindException ex) {
		return GraphQLError.newError().errorType(ErrorType.BAD_REQUEST).message("...").build();
	}

}

通过 @GraphQlExceptionHandler 方法进行异常处理会自动应用于控制器调用。要处理来自其他 graphql.schema.DataFetcher 实现的异常(不基于控制器方法),请从 AnnotatedControllerConfigurer 获取 DataFetcherExceptionResolver,并将其作为 DataFetcherExceptionResolver 注册到 GraphQlSource.Builder 中。

Exception handling via @GraphQlExceptionHandler methods is applied automatically to controller invocations. To handle exceptions from other graphql.schema.DataFetcher implementations, not based on controller methods, obtain a DataFetcherExceptionResolver from AnnotatedControllerConfigurer, and register it in GraphQlSource.Builder as a DataFetcherExceptionResolver.

Method Signature

异常处理方法支持灵活的方法签名,其中方法参数从 DataFetchingEnvironment, 中解析,并与 @SchemaMapping methods 的方法参数匹配。

Exception handler methods support a flexible method signature with method arguments resolved from a DataFetchingEnvironment, and matching to those of @SchemaMapping methods.

支持的返回类型如下列出:

Supported return types are listed below:

Return Type Description

graphql.GraphQLError

Resolve the exception to a single field error.

Collection<GraphQLError>

Resolve the exception to multiple field errors.

void

Resolve the exception without response errors.

Object

Resolve the exception to a single error, to multiple errors, or none. The return value must be GraphQLError, Collection<GraphQLError>, or null.

Mono<T>

For asynchronous resolution where <T> is one of the supported, synchronous, return types.