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

如何在Spring GraphQL、Spring Data与QueryDSL中实现非等值查询操作

Spring GraphQL + QueryDSL 进阶实现示例

以下是结合Spring GraphQL与QueryDSL实现模糊搜索、范围查询的完整示例,无需完全自定义Repository方法,基于QuerydslDataFetcher和QuerydslBinderCustomizer实现参数绑定定制。

1. 基础依赖(已配置可跳过)

确保项目中引入核心依赖:

  • spring-boot-starter-graphql
  • spring-boot-starter-data-jpa
  • com.querydsl:querydsl-jpa
  • com.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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 17:33:15