You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 14:10:34