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

如何在GraphQL中复用通用findAll方法,无需为各实体编写单独方法

在Spring GraphQL中实现通用CRUD的嵌套查询方案

1. 设计GraphQL Schema结构

先定义嵌套式的查询结构,把每个实体作为顶层Query的一个字段,实体字段下再挂载通用的CRUD查询方法,这样就能实现query{Customer{findAll{...}}}的调用形式:

type Query {
  Customer: CustomerQueryRoot
  Product: ProductQueryRoot
}

# 实体专属的查询根,挂载通用CRUD方法
type CustomerQueryRoot {
  findAll: [Customer!]!
  findById(id: ID!): Customer
}

type ProductQueryRoot {
  findAll: [Product!]!
  findById(id: ID!): Product
}

# 实体类型定义
type Customer {
  id: ID!
  name: String!
  email: String!
}

type Product {
  id: ID!
  name: String!
  price: Float!
}

2. 实现通用CRUD基础逻辑

先抽离通用的CRUD服务和Resolver基类,避免重复代码:

通用CRUD服务类

// 通用CRUD服务接口
public interface GenericCrudService<T, ID> {
    List<T> findAll();
    T findById(ID id);
    // 按需添加create/update/delete方法
}

// 通用CRUD服务实现,复用JPA逻辑
public abstract class GenericCrudServiceImpl<T, ID> implements GenericCrudService<T, ID> {
    protected final JpaRepository<T, ID> repository;

    protected GenericCrudServiceImpl(JpaRepository<T, ID> repository) {
        this.repository = repository;
    }

    @Override
    public List<T> findAll() {
        return repository.findAll();
    }

    @Override
    public T findById(ID id) {
        return repository.findById(id).orElse(null);
    }
}

通用实体Resolver基类

public abstract class GenericEntityQueryResolver<T, ID> {
    protected final GenericCrudService<T, ID> crudService;

    protected GenericEntityQueryResolver(GenericCrudService<T, ID> crudService) {
        this.crudService = crudService;
    }

    // 通用findAll方法
    public List<T> findAll() {
        return crudService.findAll();
    }

    // 通用findById方法
    public T findById(ID id) {
        return crudService.findById(id);
    }
}

3. 为每个实体实现具体组件

以Customer和Product为例,只需要继承通用基类,不需要重复写CRUD方法:

Customer相关组件

// Customer的JPA仓库
public interface CustomerRepository extends JpaRepository<Customer, Long> {}

// Customer服务,继承通用实现
@Service
public class CustomerService extends GenericCrudServiceImpl<Customer, Long> {
    public CustomerService(CustomerRepository repository) {
        super(repository);
    }
}

// Customer的查询Resolver,继承通用Resolver
@Component
public class CustomerQueryResolver extends GenericEntityQueryResolver<Customer, Long> {
    public CustomerQueryResolver(CustomerService customerService) {
        super(customerService);
    }
}

Product相关组件

public interface ProductRepository extends JpaRepository<Product, Long> {}

@Service
public class ProductService extends GenericCrudServiceImpl<Product, Long> {
    public ProductService(ProductRepository repository) {
        super(repository);
    }
}

@Component
public class ProductQueryResolver extends GenericEntityQueryResolver<Product, Long> {
    public ProductQueryResolver(ProductService productService) {
        super(productService);
    }
}

4. 实现顶层Query Resolver

把各个实体的Resolver注入进来,提供顶层Query到实体查询根的映射:

@Component
public class RootQueryResolver {
    private final CustomerQueryResolver customerQueryResolver;
    private final ProductQueryResolver productQueryResolver;

    public RootQueryResolver(CustomerQueryResolver customerQueryResolver, ProductQueryResolver productQueryResolver) {
        this.customerQueryResolver = customerQueryResolver;
        this.productQueryResolver = productQueryResolver;
    }

    public CustomerQueryResolver getCustomer() {
        return customerQueryResolver;
    }

    public ProductQueryResolver getProduct() {
        return productQueryResolver;
    }
}

完成以上配置后,就可以通过嵌套查询调用通用方法,比如:

  • 查询所有客户:query{Customer{findAll{id name email}}}
  • 查询指定ID的产品:query{Product{findById(id:1){name price}}}

内容的提问来源于stack exchange,提问作者Tùng Huynh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 15:50:38