如何在Spring GraphQL、Spring Data与QueryDSL中实现非等值查询操作
Spring GraphQL + QueryDSL 进阶实现示例
以下是结合Spring GraphQL与QueryDSL实现模糊搜索、范围查询的完整示例,无需完全自定义Repository方法,基于QuerydslDataFetcher和QuerydslBinderCustomizer实现参数绑定定制。
1. 基础依赖(已配置可跳过)
确保项目中引入核心依赖:
spring-boot-starter-graphqlspring-boot-starter-data-jpacom.querydsl:querydsl-jpacom.querydsl:querydsl-apt(用于生成Q类)
2. 实体类与Q类
定义示例实体Product,QueryDSL会自动生成对应的QProduct类:
import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import java.math.BigDecimal; import java.time.LocalDateTime; @Entity public class Product { @Id @GeneratedValue private Long id; private String name; private BigDecimal price; private LocalDateTime createdAt; // Getter、Setter、构造方法省略 }
3. GraphQL Schema定义
在src/main/resources/graphql/schema.graphqls中定义带进阶查询参数的Schema:
type Query { products( nameContains: String, priceMin: Float, priceMax: Float, createdAtAfter: String, createdAtBefore: String ): [Product!]! } type Product { id: ID! name: String! price: Float! createdAt: String! }
4. 定制Querydsl参数绑定核心逻辑
实现QuerydslBinderCustomizer,将GraphQL参数映射为QueryDSL的Predicate:
import com.querydsl.core.types.dsl.StringPath; import com.querydsl.jpa.QProduct; import org.springframework.data.querydsl.binding.QuerydslBinderCustomizer; import org.springframework.data.querydsl.binding.QuerydslBindings; import org.springframework.stereotype.Component; import java.math.BigDecimal; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @Component public class ProductQuerydslBinderCustomizer implements QuerydslBinderCustomizer<QProduct> { private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME; @Override public void customize(QuerydslBindings bindings, QProduct root) { // 模糊搜索:nameContains参数 → 不区分大小写的like查询 bindings.bind(root.name).first((StringPath path, String value) -> path.containsIgnoreCase(value) ); // 价格范围:priceMin/priceMax → 区间查询 bindings.bind(root.price).all((path, values) -> { var iterator = values.iterator(); BigDecimal minPrice = BigDecimal.valueOf(iterator.next().floatValue()); if (iterator.hasNext()) { BigDecimal maxPrice = BigDecimal.valueOf(iterator.next().floatValue()); return path.between(minPrice, maxPrice); } return path.goe(minPrice); // 仅传min时,匹配>=min的价格 }); // 创建时间范围:createdAtAfter/createdAtBefore → 时间区间查询 bindings.bind(root.createdAt).all((path, values) -> { var iterator = values.iterator(); LocalDateTime after = LocalDateTime.parse(iterator.next(), DATE_FORMATTER); if (iterator.hasNext()) { LocalDateTime before = LocalDateTime.parse(iterator.next(), DATE_FORMATTER); return path.between(after, before); } return path.after(after); // 仅传after时,匹配晚于该时间的记录 }); // 忽略id的默认等值绑定(如果不需要通过id查询) bindings.excluding(root.id); } }
5. 配置QuerydslDataFetcher
将定制的绑定逻辑注入到DataFetcher中,关联Repository:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.querydsl.QuerydslPredicateExecutor; import org.springframework.graphql.data.query.QuerydslDataFetcher; @Configuration public class GraphQLDataFetcherConfig { @Bean public QuerydslDataFetcher<Product> productsDataFetcher( QuerydslPredicateExecutor<Product> productRepository, ProductQuerydslBinderCustomizer customizer) { return QuerydslDataFetcher.builder(productRepository) .customizer(customizer) // 应用定制的参数绑定 .build(); } }
6. Repository接口
继承QuerydslPredicateExecutor以支持Predicate查询:
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.querydsl.QuerydslPredicateExecutor; public interface ProductRepository extends JpaRepository<Product, Long>, QuerydslPredicateExecutor<Product> { }
7. 测试查询示例
执行以下GraphQL查询,验证模糊搜索+价格+时间范围的组合查询:
query { products( nameContains: "phone", priceMin: 1000.0, priceMax: 5000.0, createdAtAfter: "2023-01-01T00:00:00" ) { id name price createdAt } }
关键逻辑说明
QuerydslBinderCustomizer的customize方法是核心:通过bind关联GraphQL参数与实体属性,用first处理单值参数,all处理多值范围参数。- QueryDSL提供了丰富的Predicate方法:
containsIgnoreCase(模糊匹配)、between(区间)、goe(大于等于)、after(时间晚于)等,满足各类查询场景。 - 无需自定义Repository方法,所有查询逻辑通过参数绑定自动生成Predicate,由
QuerydslPredicateExecutor执行。
内容的提问来源于stack exchange,提问作者Anthony Lofton
相关产品推荐
相关产品推荐

