如何在Spring GraphQL中实现自定义类型字段的带参分页查询
Spring GraphQL 实现自定义类型字段的带参分页
问题原因
你之前在AuthorDto中使用@SchemaMapping无效的核心原因是:@SchemaMapping注解只能被Spring管理的Bean识别(比如标注了@Controller、@Component的类),而AuthorDto是数据传输类,不属于Spring Bean,因此Spring无法扫描到该注解,也就不会执行对应的解析逻辑。当GraphQL查询books字段时,没有找到对应的解析器,默认返回null,而你的Schema中books被定义为非空类型[Book!]!,这就触发了NullValueInNonNullableField错误。
解决方案:创建独立的字段解析器类
你需要创建一个由Spring管理的Bean类,专门处理Author类型的books字段解析,以下是Java实现代码:
1. 编写字段解析器Controller
import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.Parent; import org.springframework.graphql.data.method.annotation.SchemaMapping; import org.springframework.stereotype.Controller; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import java.util.Collections; import java.util.List; @Controller public class AuthorFieldResolver { // 注入你的书籍数据访问组件(比如Repository) private final BookRepository bookRepository; // 构造注入依赖 public AuthorFieldResolver(BookRepository bookRepository) { this.bookRepository = bookRepository; } @SchemaMapping(typeName = "Author", field = "books") public List<Book> resolveBooks( // 父对象:当前查询到的Author/AuthorDto实例 @Parent AuthorDto authorDto, // 分页参数,设置required=false允许不传,后续设置默认值 @Argument(required = false) Integer page, @Argument(required = false) Integer size, @Argument(required = false) String sort) { // 为参数设置默认值,避免null int targetPage = page != null ? page : 0; int targetSize = size != null ? size : 10; String targetSort = sort != null ? sort : "year"; // 从父对象中获取作者标识,用于关联查询 Long authorId = authorDto.getAuthor().getId(); // 构建分页查询条件 Pageable pageable = PageRequest.of(targetPage, targetSize, Sort.by(targetSort)); Page<Book> bookPage = bookRepository.findByAuthorId(authorId, pageable); // 必须返回非空列表:即使没有书籍,也要返回空列表而非null return bookPage.getContent() != null ? bookPage.getContent() : Collections.emptyList(); } }
2. 关键注意点
@Controller注解:确保该类被Spring扫描并管理为Bean,这样@SchemaMapping才能被识别。@Parent参数:用于获取当前上下文的父对象(也就是allAuthors查询返回的每个AuthorDto实例),以此确定要查询哪个作者的书籍。- 参数默认值:由于GraphQL中
page、size、sort是可选参数,需要在方法内部设置默认值,避免后续逻辑出现NullPointerException。 - 非空返回值:严格遵循Schema定义,必须返回
List<Book>类型的非空对象,哪怕查询结果为空,也要返回Collections.emptyList(),不能返回null。
3. 适配实体类场景
如果你的allAuthors查询直接返回Author实体类而非AuthorDto,只需将@Parent参数的类型改为Author即可:
public List<Book> resolveBooks( @Parent Author author, @Argument(required = false) Integer page, // ... 其余参数不变 ) { Long authorId = author.getId(); // ... 后续逻辑不变 }
内容的提问来源于stack exchange,提问作者t00manysecrets
相关产品推荐
相关产品推荐

