我有一个端点来获取所有帖子,我还有多个@RequestParams用于过滤和搜索值等。
我遇到的问题是,当试图基于特定的@RequestParams进行筛选时,我需要进行多次检查,以查看在调用端点时是否传递了该特定参数,因此在我的控制器中,我有这样的东西。参数是可选的,我也有寻呼等参数,但我在下面省略了它。
我有以下标准:
@RequestParam(required=false) List<String> brand - Used to filter by multiple brands
@RequestParam(required=false) String province - Used to filter by province
@RequestParam(required=false) String city - Used to filter by city
// Using these 2 for getting Posts within a certain price range
@RequestParam(defaultValue = "0", required = false) String minValue - Used to filter by min price
@RequestParam(defaultValue = "5000000", required = false) String maxValue - Used to filter by max price
在检查根据传递的参数调用哪种服务方法时,我的控制器中也有这一点。
if(query != null) {
pageTuts = postService.findAllPosts(query, pagingSort);
} else if(brand != null) {
pageTuts = postService.findAllByBrandIn(brand, pagingSort);
} else if(minValue != null && maxValue != null) {
pageTuts = postService.findAllPostsByPriceBetween(minValue, maxValue, pagingSort);
} else if(brand != null & minValue != null & maxValue != null) {
pageTuts = postService.findAllPostsByPriceBetween(minValue, maxValue, pagingSort);
} else {
// if no parameters are passed in req, just get all the Posts available
pageTuts = postService.findAllPosts(pagingSort);
}
// I would need more checks to handle all parameters
问题是,如果我对每个可能的参数都需要这个条件,我很难找到,这将是基于该参数的大量检查和存储库/服务方法。
例如,在我的存储库中,我有如下抽象方法:
Page<Post> findAllByProvince(String province, Pageable pageable);
Page<Post> findAllByCity(String city, Pageable pageable);
Page<Post> findAllByProvinceAndCity(String province, String city, Pageable pageable);
Page<Post> findAllByBrandInAndProvince(List<String> brand, String province, Pageable pageable);
我需要更多的东西来处理其他潜在的值,比如findAllByPriceBetween((,findAllByCityAndPriceBetwee((,findAllByProvinceAndPriceBetween((。。。
所以我想要一些关于如何处理这个问题的建议?。
编辑
通过重写toPredicate方法使其工作,如@M所示。Deinum根据我的用例进行了一些小的调整。
@Override
public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder builder) {
List<Predicate> predicates = new ArrayList<>();
// min/max is never not set as they have default values
predicates.add(builder.between(root.get("price"), params.getMinValue(), params.getMaxValue()));
if (params.getProvince() != null) {
predicates.add(builder.equal(root.get("province"), params.getProvince()));
}
if (params.getCity() != null) {
predicates.add(builder.equal(root.get("city"), params.getCity()));
}
if (!CollectionUtils.isEmpty(params.getBrand())) {
Expression<String> userExpression = root.get("brand");
Predicate p = userExpression.in(params.getBrand());
predicates.add(p);
}
return builder.and(predicates.toArray(new Predicate[0]));
}
- 创建一个对象来保存变量,而不是单个元素
- 将逻辑移动到服务,并将对象和可分页内容传递给服务
- 从存储库中去掉那些
findAll
方法,并在extends子句中添加JpaSpecificationExecutor
- 在服务中创建
Predicate
并使用JpaSpecificationExecutor.findAll
返回您想要的内容
public class PostSearchParameters {
private String province;
private String city;
private List<String> brand;
private int minValue = 0;
private int maxValue = 500000;
//getters/setters or when on java17+ use a record instead of class
}
谓词
public class PostSearchParametersSpecification implements Specification {
private final PostSearchParameters params;
PostSearchParametersPredicate(PostSearchParameters params) {
this.params=params;
}
@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
List<Predicate> predicates = new ArrayList<>();
// min/max is never not set as they have default values
predicates.add(builder.between(root.get("price", params.getMinValue(), params.getMaxValue());
if (params.getProvince() != null) {
predicates.add(builder.equal(root.get("province"), params.getProvince());
}
if (params.getCity() != null) {
predicates.add(builder.equal(root.get("city"), params.getCity());
}
if (!CollectionUtils.isEmpty(params.getBrand()) {
predicates.add(builder.in(root.get("brand")).values( params.getBrand());
}
return builder.and(predicates.toArray(new Predicate[0]));
}
}
存储库
public interface PostRepository extends JpaRepository<Post, Long>, JpaSpecificationExecutor<Post> {}
服务方法
public Page<Post> searchPosts(PostSearchParameters params, Pageable pageSort) {
PostSearchParametersSpecification specification =
new PostSearchParametersSpecification(params)
return repository.findAll(specification, pageSort);
}
现在您可以查询所有可用的参数,添加一个参数就是扩展/修改谓词,您就可以开始了。
另请参阅规格上的Spring Data JPA参考指南