如何在GraphQL Spring Boot中实现列表查询的过滤、排序与分页?
Hey Martin, let's walk through how to add filtering, sorting, and pagination (like the first:3 example you mentioned) to your allCars query using the GraphQL Spring Boot library. Here's a step-by-step breakdown that fits your existing setup:
1. Update Your GraphQL Schema
First, we need to extend the schema to define parameters for filtering, sorting, and pagination. We'll add input types for filters, enums for sorting options, and update the allCars query to accept these new parameters:
# Define input type for car filters (add more fields as needed) input CarFilterInput { modelContains: String # Filter cars where model contains this string brandEquals: String # Filter cars where brand matches exactly } # Enum for sortable fields enum CarSortBy { ID MODEL BRAND } # Enum for sort direction enum SortDirection { ASC DESC } type Car { id: ID! model: String brand: String } type Query { allCars( filter: CarFilterInput, # Optional filter parameters sortBy: CarSortBy = ID, # Default sort by ID sortDirection: SortDirection = ASC, # Default ascending order first: Int # Optional: Return only top N results ): [Car]! }
2. Create Corresponding Java Classes
Next, map the schema's new types to Java classes so Spring can handle them:
Enums for Sorting
public enum CarSortBy { ID, MODEL, BRAND } public enum SortDirection { ASC, DESC }
Filter Input DTO
import graphql.schema.annotations.GraphQLInputType; import graphql.schema.annotations.GraphQLField; @GraphQLInputType public class CarFilterInput { private String modelContains; private String brandEquals; @GraphQLField public String getModelContains() { return modelContains; } public void setModelContains(String modelContains) { this.modelContains = modelContains; } @GraphQLField public String getBrandEquals() { return brandEquals; } public void setBrandEquals(String brandEquals) { this.brandEquals = brandEquals; } }
Note: If you're using the newer Spring GraphQL integration, you might use @InputType instead of @GraphQLInputType—adjust based on your library version.
3. Modify Your Query Resolver
Now update your Query class to accept the new parameters and implement filtering, sorting, and pagination logic. Also, I noticed a small mismatch: your resolver returns List<Machine> but your schema defines Car—I've adjusted that to List<Car> here.
import org.springframework.stereotype.Component; import java.util.List; import java.util.stream.Collectors; @Component public class Query implements GraphQLQueryResolver { // Inject your data source (e.g., a Spring Data JPA repository) private final CarRepository carRepository; public Query(CarRepository carRepository) { this.carRepository = carRepository; } public List<Car> allCars( CarFilterInput filter, CarSortBy sortBy, SortDirection sortDirection, Integer first ) { // 1. Fetch all cars from your data source List<Car> cars = carRepository.findAll(); // 2. Apply filtering if filter parameters are provided if (filter != null) { cars = cars.stream() .filter(car -> { // Filter by model containing the input string (case-insensitive) if (filter.getModelContains() != null && !filter.getModelContains().isEmpty()) { return car.getModel().toLowerCase().contains(filter.getModelContains().toLowerCase()); } return true; }) .filter(car -> { // Filter by exact brand match (case-insensitive) if (filter.getBrandEquals() != null && !filter.getBrandEquals().isEmpty()) { return car.getBrand().equalsIgnoreCase(filter.getBrandEquals()); } return true; }) .collect(Collectors.toList()); } // 3. Apply sorting cars = cars.stream() .sorted((car1, car2) -> { int comparison = 0; switch (sortBy) { case MODEL: comparison = car1.getModel().compareToIgnoreCase(car2.getModel()); break; case BRAND: comparison = car1.getBrand().compareToIgnoreCase(car2.getBrand()); break; case ID: default: comparison = car1.getId().compareTo(car2.getId()); break; } // Reverse order if direction is DESC return sortDirection == SortDirection.DESC ? -comparison : comparison; }) .collect(Collectors.toList()); // 4. Apply pagination (return first N results) if (first != null && first > 0) { int endIndex = Math.min(first, cars.size()); cars = cars.subList(0, endIndex); } return cars; } }
Performance Note
If you're dealing with large datasets, avoid filtering/sorting in memory like the example above. Instead, push these operations down to the database using Spring Data JPA Specification, Querydsl, or custom repository methods—this will be much more efficient.
4. Test Your Queries
You can now run queries like these:
Fetch top 3 cars
query { allCars(first: 3) { id model } }
Filter, sort, and paginate
query { allCars( filter: {brandEquals: "Toyota", modelContains: "Camry"} sortBy: MODEL sortDirection: DESC first: 5 ) { id model brand } }
内容的提问来源于stack exchange,提问作者Martin

