Spring 谓词多个运算符
Spring predicate multiple operators
我正在尝试使用多种过滤方法制作 sortable/pageable/filterable 存储库。这是我的相关代码现在的样子:
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name", length = 50, nullable = false)
private String name;
存储库:
@Repository
public interface UserRepository extends JpaRepository<User, Long> ,
QuerydslPredicateExecutor<User> {
}
控制器:
@RequestMapping(path="/test")
public @ResponseBody ResponseEntity<Object> foo
( @QuerydslPredicate(root = User.class) Predicate predicate, Pageable pageable) {
return userRepository.findAll(predicate,pageable);
}
它工作得很好,就像这样:
/users/?page=0&limit=1&sort=name,ASC&name=testuser
但是我不能使用任何其他过滤方法,除了像 "name=testuser" 这样的等号
我四处搜索,一直在寻找 this 之类的指南,但我必须为每个实体编写一个 PathBuilder,而且控制器看起来也更丑陋。
有没有办法解决这个问题并像现在这样简化一切?我需要基本运算符,如 eq、neq、gte、lte、like 等...
一般我用的是CriteriaBuilder API
。它给了我一个小的解决方案,您需要做的就是将存储库订阅到您的自定义规范。
public class CustomerSpecification implements Specification<CustomerDetail> {
private C2Criteria criteria;
public static CustomerSpecification of(C2Criteria criteria) {
return new CustomerSpecification(criteria);
}
private CustomerSpecification(C2Criteria criteria) {
this.criteria = criteria;
}
@Override
public Predicate toPredicate
(Root<CustomerDetail> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
return getPredicate(root, builder, criteria);
}
}
public <T> Predicate getPredicate(Root<T> root, CriteriaBuilder builder, C2Criteria criteria) {
if (criteria.getOperation().equalsIgnoreCase(">")) {
return builder.greaterThanOrEqualTo(
root.get(criteria.getKey()), criteria.getValue().toString());
} else if (criteria.getOperation().equalsIgnoreCase("<")) {
return builder.lessThanOrEqualTo(
root.get(criteria.getKey()), criteria.getValue().toString());
} else if (criteria.getOperation().equalsIgnoreCase(":")) {
if (root.get(criteria.getKey()).getJavaType().equals(String.class)) {
return builder.like(
root.get(criteria.getKey()), "%" + criteria.getValue() + "%");
} else {
return builder.equal(root.get(criteria.getKey()), criteria.getValue());
}
}
我的标准 class 是:
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class C2Criteria {
private String key;
private String operation = ":";
private Object value;
}
我的 JpaRepository
看起来像:
public interface CustomerDetailRepository extends JpaRepository<CustomerDetail, Long>, JpaSpecificationExecutor<CustomerDetail> {
}
在您的控制器中,您可以通过从 queryString 获取对象来使用它。
@GetMapping(value = "renew")
public ResponseEntity renew(@NonNull PageDto page, @NonNull C2Criteria criteria) {
Page<InsuranceRenew> renews = this.insuranceService.getRenew(page, criteria);
return ResponseEntity.ok(renews);
}
保险服务方法如下所示:
@Override
public Page<InsuranceRenew> getRenew(@NonNull PageDto page, @NonNull C2Criteria criteria) {
Pageable pageable = PageRequest.of(page.getPage(), page.getSize(), new Sort(page.getSort(), page.getOrderBy()));
InsuranceRenewSpecification specification = InsuranceRenewSpecification.of(criteria);
return this.renewRepository.findAll(specification, pageable);
}
你可以看到我使用了 PageDto
class,它只是一个 POJO,带有一些用于分页的字段,它被定义为:
@Data
public class PageDto {
private int page;
private int size = 10;
private Sort.Direction sort = Sort.Direction.DESC;
private String orderBy = "id";
}
如您所见,我曾经使用 id 作为默认顺序,以防止出现不需要的异常,并将 DESC 作为默认顺序。
希望对您有所帮助。
我正在尝试使用多种过滤方法制作 sortable/pageable/filterable 存储库。这是我的相关代码现在的样子:
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name", length = 50, nullable = false)
private String name;
存储库:
@Repository
public interface UserRepository extends JpaRepository<User, Long> ,
QuerydslPredicateExecutor<User> {
}
控制器:
@RequestMapping(path="/test")
public @ResponseBody ResponseEntity<Object> foo
( @QuerydslPredicate(root = User.class) Predicate predicate, Pageable pageable) {
return userRepository.findAll(predicate,pageable);
}
它工作得很好,就像这样: /users/?page=0&limit=1&sort=name,ASC&name=testuser 但是我不能使用任何其他过滤方法,除了像 "name=testuser" 这样的等号 我四处搜索,一直在寻找 this 之类的指南,但我必须为每个实体编写一个 PathBuilder,而且控制器看起来也更丑陋。
有没有办法解决这个问题并像现在这样简化一切?我需要基本运算符,如 eq、neq、gte、lte、like 等...
一般我用的是CriteriaBuilder API
。它给了我一个小的解决方案,您需要做的就是将存储库订阅到您的自定义规范。
public class CustomerSpecification implements Specification<CustomerDetail> {
private C2Criteria criteria;
public static CustomerSpecification of(C2Criteria criteria) {
return new CustomerSpecification(criteria);
}
private CustomerSpecification(C2Criteria criteria) {
this.criteria = criteria;
}
@Override
public Predicate toPredicate
(Root<CustomerDetail> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
return getPredicate(root, builder, criteria);
}
}
public <T> Predicate getPredicate(Root<T> root, CriteriaBuilder builder, C2Criteria criteria) {
if (criteria.getOperation().equalsIgnoreCase(">")) {
return builder.greaterThanOrEqualTo(
root.get(criteria.getKey()), criteria.getValue().toString());
} else if (criteria.getOperation().equalsIgnoreCase("<")) {
return builder.lessThanOrEqualTo(
root.get(criteria.getKey()), criteria.getValue().toString());
} else if (criteria.getOperation().equalsIgnoreCase(":")) {
if (root.get(criteria.getKey()).getJavaType().equals(String.class)) {
return builder.like(
root.get(criteria.getKey()), "%" + criteria.getValue() + "%");
} else {
return builder.equal(root.get(criteria.getKey()), criteria.getValue());
}
}
我的标准 class 是:
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class C2Criteria {
private String key;
private String operation = ":";
private Object value;
}
我的 JpaRepository
看起来像:
public interface CustomerDetailRepository extends JpaRepository<CustomerDetail, Long>, JpaSpecificationExecutor<CustomerDetail> {
}
在您的控制器中,您可以通过从 queryString 获取对象来使用它。
@GetMapping(value = "renew")
public ResponseEntity renew(@NonNull PageDto page, @NonNull C2Criteria criteria) {
Page<InsuranceRenew> renews = this.insuranceService.getRenew(page, criteria);
return ResponseEntity.ok(renews);
}
保险服务方法如下所示:
@Override
public Page<InsuranceRenew> getRenew(@NonNull PageDto page, @NonNull C2Criteria criteria) {
Pageable pageable = PageRequest.of(page.getPage(), page.getSize(), new Sort(page.getSort(), page.getOrderBy()));
InsuranceRenewSpecification specification = InsuranceRenewSpecification.of(criteria);
return this.renewRepository.findAll(specification, pageable);
}
你可以看到我使用了 PageDto
class,它只是一个 POJO,带有一些用于分页的字段,它被定义为:
@Data
public class PageDto {
private int page;
private int size = 10;
private Sort.Direction sort = Sort.Direction.DESC;
private String orderBy = "id";
}
如您所见,我曾经使用 id 作为默认顺序,以防止出现不需要的异常,并将 DESC 作为默认顺序。
希望对您有所帮助。