如果您不想使用 QueryDSL,则必须编写自己的规范。首先,您需要像您一样从JpaSpecificationExecutor 扩展您的存储库。不过请确保添加泛型 (JpaSpecificationExecutor<Some>)。
之后,您必须创建三个规范(每列一个),在the Spring docs 他们将这些规范定义为类中的静态方法。基本上,创建规范意味着您必须继承 Specification<Some>,它只有一种方法可以实现,toPredicate(Root<Some>, CriteriaQuery<?>, CriteriaBuilder)。
如果您使用的是 Java 8,则可以使用 lambdas 创建匿名内部类,例如:
public class SomeSpecs {
public static Specification<Some> withAddress(String address) {
return (root, query, builder) -> {
// ...
};
}
}
对于实际实现,您可以使用Root 来获取特定节点,例如。 root.get("address")。另一方面,CriteriaBuilder 是定义 where 子句,例如。 builder.equal(..., ...).
在你的情况下,你想要这样的东西:
public class SomeSpecs {
public static Specification<Some> withAddress(String address) {
return (root, query, builder) -> builder.equal(root.get("address"), address);
}
}
或者,如果您想使用LIKE 查询,您可以使用:
public class SomeSpecs {
public static Specification<Some> withAddress(String address) {
return (root, query, builder) -> builder.like(root.get("address"), "%" + address + "%");
}
}
现在您必须对要过滤的其他字段重复此操作。之后,您必须一起使用所有规范(使用and()、or(),...)。然后可以使用repository.findAll(Specification)方法根据该规范进行查询,例如:
public List<Some> getSome(String address, String name, Date date) {
return repository.findAll(where(withAddress(address))
.and(withName(name))
.and(withDate(date));
}
您可以使用静态导入来导入withAddress()、withName() 和withDate(),使其更易于阅读。 where() 方法也可以静态导入(来自Specification.where())。
请注意,上述方法可能需要调整,因为如果地址字段为null,您不希望对其进行过滤。您可以通过返回 null 来执行此操作,例如:
public List<Some> getSome(String address, String name, Date date) {
return repository.findAll(where(address == null ? null : withAddress(address))
.and(name == null ? null : withName(name))
.and(date == null ? null : withDate(date));
}