Spring boot[starter](https://docs.spring.io/spring-boot/docs/2.7.0-SNAPSHOT/reference/html/web.html#web.graphql)通过默认的`GraphQlSource.Builder`初始化`GraphQlSource`实例,并启用以下功能:
默认情况下, Spring 引导启动器[查找架构文件](https://docs.spring.io/spring-boot/docs/2.7.0-SNAPSHOT/reference/html/web.html#web.graphql.schema)来自一个众所周知的 Classpath 位置,但是你可以通过`FileSystemResource`将其更改为文件系统上的一个位置,通过`ByteArrayResource`将字节内容更改为通过`ByteArrayResource`,或者实现一个自定义的`Resource`从远程位置或存储空间加载模式文件。
在 Spring GraphQL 中,可以通过[`RuntimeWiringConfigurer`](#execution-graphqlsource-runtimewilling-configurer)注册`SchemaDirectiveWiring`。 Spring 引导启动器会检测到这样的 bean,因此你可能会有如下内容:
```
@Configuration
public class GraphQlConfig {
@Bean
public RuntimeWiringConfigurer runtimeWiringConfigurer() {
Spring 对于 GraphQL,有一个内置的`DataFetcherExceptionHandler`,它被配置为由[`GraphQLSource`](#execution-grapqlsource)生成器使用。它使应用程序能够注册一个或多个 Spring `DataFetcherExceptionResolver`按顺序调用的组件,直到将`Exception`解析为`graphql.GraphQLError`对象的列表。
Spring 引导启动器声明一个`BatchLoaderRegistry` Bean,你可以将其注入到你的配置中,如上面所示,或注入到任何组件中,例如控制器中的顺序寄存器批处理加载功能。然后,将`BatchLoaderRegistry`注入`ExecutionGraphQlService`,从而确保每个请求的注册量`DataLoader`。
Spring 对于 GraphQL,你可以利用现有的 Spring 技术,遵循常见的编程模型来通过 GraphQL 公开底层数据源。
本节讨论了用于 Spring 数据的集成层,该集成层提供了一种简单的方法,将 QueryDSL 或查询 by example 存储库调整为`DataFetcher`,包括用于标记为`@GraphQlRepository`的存储库的自动检测和 GraphQL 查询注册的选项。
### 5.1. QueryDSL
Spring 对于 GraphQL 支持使用[Querydsl](http://www.querydsl.com/)来通过 Spring 数据获取数据[QueryDSL 扩展](https://docs.spring.io/spring-data/commons/docs/current/reference/html/#core.extensions)。QueryDSL 提供了一种灵活的 TypeSafe 方法,通过使用注释处理器生成元模型来表示查询谓词。
例如,将存储库声明为`QuerydslPredicateExecutor`:
```
public interface AccountRepository extends Repository<Account, Long>,
Spring 数据支持使用[示例查询](https://docs.spring.io/spring-data/commons/docs/current/reference/html/#query-by-example)来获取数据。Query by Example 是一种简单的查询技术,不需要你通过特定于存储的查询语言编写查询。
从声明`QueryByExampleExecutor`的存储库开始:
```
public interface AccountRepository extends Repository<Account, Long>,
出现的一个常见问题是,GraphQL 选择集与[Spring Data projections](https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections)相比如何,每个选择集起什么作用?
简短的回答是, Spring for GraphQL 不是将 GraphQL 查询直接转换为 SQL 或 JSON 查询的数据网关。相反,它允许你利用现有的 Spring 技术,并且不假定 GraphQL 模式和底层数据模型之间存在一对一的映射。这就是为什么客户机驱动的选择和数据模型的服务器端转换可以发挥互补作用的原因。
为了更好地理解,考虑 Spring 数据促进了域驱动(DDD)设计,作为管理数据层中复杂性的推荐方法。在 DDD 中,坚持总量约束是很重要的。根据定义,聚合只有在全部加载的情况下才是有效的,因为部分加载的聚合可能会对聚合功能施加限制。
在 Spring 数据中,你可以选择是希望将聚合按原样公开,还是在将其作为 GraphQL 结果返回之前将转换应用于数据模型。有时,做前者就足够了,默认情况下,[Querydsl](#data-querydsl)和[示例查询](#data-querybyexample)集成将 GraphQL 选择集转换为属性路径提示,底层 Spring 数据模块使用这些属性路径提示来限制选择。
在其他情况下,为了适应 GraphQL 模式,减少甚至转换底层数据模型是有用的。 Spring 数据通过接口和 DTO 投影来支持这一点。
*[开放接口投影](https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections.interfaces.open)利用 Spring 的`@Value`注释和[SpEL](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#expressions)表达式来应用轻量级数据转换,例如连接、计算或将静态函数应用于属性。
要应用更细粒度的安全性,可以在获取 GraphQL 响应的特定部分所涉及的服务方法中添加 Spring 安全性注释,例如`@PreAuthorize`或`@Secured`。由于[上下文传播](#execution-context)的目的是使安全性和其他上下文在数据获取级别可用,所以这种方法应该有效。
Spring for GraphQL 存储库包含[Spring MVC](https://github.com/spring-projects/spring-graphql/tree/main/samples/webmvc-http-security)和[WebFlux](https://github.com/spring-projects/spring-graphql/tree/main/samples/webflux-security)的示例。
## 8. 测试
用 Spring 的`WebTestClient`测试 GraphQL 请求是可能的,只需要发送和接收 JSON,但是许多 GraphQL 特定的细节使得这种方法比必要的更麻烦。
*`WebGraphQlHandler`——通过[网络拦截](#web-interception)和[WebSocket](#web-websocket)处理程序都使用的[网络拦截](#web-interception)链执行请求,这实际上是在没有 Web 框架的情况下进行的测试。使用这个的一个原因是[订阅](#testing-subscriptions)。