如何在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
相关产品推荐
相关产品推荐

