结合前两个答案:如果您不想将 API 和数据库架构耦合起来,或者换句话说,您不希望用户提供字符串列名 - 您可以过滤掉那些不是字符串的属性并将like 应用于所有这些。在以下示例中,它将尝试在列值中搜索 text:name、field1、field2 和 field3。
实体示例:
@Entity
public class MyEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public int id;
public String name;
public String field2;
public String field3;
public String field4;
}
规格示例:
public class EntitySpecification {
public static Specification<MyEntity> textInAllColumns(String text) {
if (!text.contains("%")) {
text = "%"+text+"%";
}
final String finalText = text;
return new Specification<MyEntity>() {
@Override
public Predicate toPredicate(Root<MyEntity> root, CriteriaQuery<?> cq, CriteriaBuilder builder) {
return builder.or(root.getModel().getDeclaredSingularAttributes().stream().filter(a-> {
if (a.getJavaType().getSimpleName().equalsIgnoreCase("string")) {
return true;
}
else {
return false;
}}).map(a -> builder.like(root.get(a.getName()), finalText)
).toArray(Predicate[]::new)
);
}
};
}
}
存储库示例:
public interface MyEntityRepository extends PagingAndSortingRepository<MyEntity, Integer> {
List<MyEntity> findAll(Specification<MyEntity> spec);
}
使用示例:
List<MyEntity> res = failureRepository.findAll(Specifications.where(FailureSpecification.textInAllColumns(text)));
另一个更新(在所有类型的列中搜索带有 lambda 字段的白名单 - 未检查代码)
public class EmployeeSpecification {
public static Specification<Employee> textInAllColumns(String text, Set<String> fields) {
if (!text.contains("%")) {
text = "%" + text + "%";
}
final String finalText = text;
return (Specification<Employee>) (root, query, builder) ->
builder.or(root.getModel().getDeclaredSingularAttributes().stream().filter(a -> {
return fields.contains(a.getName());
}).map(a -> builder.like(root.get(a.getName()), finalText)).toArray(Predicate[]::new));
}
}