您可以使用 Spring-data 开箱即用的规范。并能够使用标准 API 以编程方式构建查询。要支持规范,您可以使用 JpaSpecificationExecutor 接口扩展存储库接口
public interface CustomerRepository extends SimpleJpaRepository<T, ID>, JpaSpecificationExecutor {
}
附加接口 (JpaSpecificationExecutor ) 带有允许您以多种方式执行规范的方法。
例如 findAll 方法将返回所有符合规范的实体:
List<T> findAll(Specification<T> spec);
规范界面如下:
public interface Specification<T> {
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,
CriteriaBuilder builder);
}
好的,那么典型的用例是什么?规范可以很容易地用于在实体之上构建一组可扩展的谓词,然后可以将其与 JpaRepository 组合并使用,而无需为每个需要的组合声明查询(方法)。这是一个示例:示例 2.15。客户规格
public class CustomerSpecs {
public static Specification<Customer> isLongTermCustomer() {
return new Specification<Customer>() {
public Predicate toPredicate(
Root<Customer> root, CriteriaQuery<?> query,
CriteriaBuilder builder) {
LocalDate date = new LocalDate().minusYears(2);
return builder.lessThan(root.get('dateField'), date);
}
};
}
public static Specification<Customer> hasSalesOfMoreThan(MontaryAmount value) {
return new Specification<Customer>() {
public Predicate toPredicate(
Root<T> root, CriteriaQuery<?> query,
CriteriaBuilder builder) {
// build query here
}
};
}
}
您在业务需求抽象级别上表达了一些标准并创建了可执行的规范。因此,客户可能会使用如下规范:
List customers = customerRepository.findAll(isLongTermCustomer());
您还可以结合规范示例 2.17。组合规格
MonetaryAmount amount = new MonetaryAmount(200.0, Currencies.DOLLAR);
List<Customer> customers = customerRepository.findAll(
where(isLongTermCustomer()).or(hasSalesOfMoreThan(amount)));
如您所见,规范提供了一些粘合代码方法来链接
并结合规格。因此扩展您的数据访问层是
只需创建新的规范实现和
将它们与现有的结合起来。
您可以创建复杂的规范,这是一个示例
public class WorkInProgressSpecification {
public static Specification<WorkInProgress> findByCriteria(final SearchCriteria searchCriteria) {
return new Specification<WorkInProgress>() {
@Override
public Predicate toPredicate(
Root<WorkInProgress> root,
CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> predicates = new ArrayList<Predicate>();
if (searchCriteria.getView() != null && !searchCriteria.getView().isEmpty()) {
predicates.add(cb.equal(root.get("viewType"), searchCriteria.getView()));
}
if (searchCriteria.getFeature() != null && !searchCriteria.getFeature().isEmpty()) {
predicates.add(cb.equal(root.get("title"), searchCriteria.getFeature()));
}
if (searchCriteria.getEpic() != null && !searchCriteria.getEpic().isEmpty()) {
predicates.add(cb.equal(root.get("epic"), searchCriteria.getEpic()));
}
if (searchCriteria.getPerformingGroup() != null && !searchCriteria.getPerformingGroup().isEmpty()) {
predicates.add(cb.equal(root.get("performingGroup"), searchCriteria.getPerformingGroup()));
}
if (searchCriteria.getPlannedStartDate() != null) {
System.out.println("searchCriteria.getPlannedStartDate():" + searchCriteria.getPlannedStartDate());
predicates.add(cb.greaterThanOrEqualTo(root.<Date>get("plndStartDate"), searchCriteria.getPlannedStartDate()));
}
if (searchCriteria.getPlannedCompletionDate() != null) {
predicates.add(cb.lessThanOrEqualTo(root.<Date>get("plndComplDate"), searchCriteria.getPlannedCompletionDate()));
}
if (searchCriteria.getTeam() != null && !searchCriteria.getTeam().isEmpty()) {
predicates.add(cb.equal(root.get("agileTeam"), searchCriteria.getTeam()));
}
return cb.and(predicates.toArray(new Predicate[] {}));
}
};
}
}
这里是JPA Respositories docs