MySpecification package import org.apache.commons.lang3.StringUtils;import org.springframework.data.domain.Sort;import org.springframework.data.jpa.domain.Specification;import org.springframework.util.CollectionUtils;import javax.persistenc
package import org.apache.commons.lang3.StringUtils; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.Specification; import org.springframework.util.CollectionUtils; import javax.persistence.criteria.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; /** * Created By mx1014 On 17-11-23 * * @author Mx1014 * 使用示例 * PageRequest pr = new PageRequest(0, 10); * Page pageData = userDao.findAll(new MySpecification().and( * QueryParams.like("id", id), * QueryParams.like("Name",Name)).asc("id"), pr); */ public class MySpecification implements Specification { //属性分隔 private static final String PROPERTY_SEPARATOR = "."; //AND List andConditions = new ArrayList<>(); //OR List orConditions = new ArrayList<>(); //排序 List orders = new ArrayList<>(); @Override public Predicate toPredicate(Root root, CriteriaQuery cq, CriteriaBuilder cb) { Predicate restrictions = cb.and(getAndPredicates(root, cb)); restrictions = cb.and(restrictions, getOrPredicates(root, cb)); cq.orderBy(getOrders(root, cb)); return restrictions; } public MySpecification and(Collection conditions) { andConditions.addAll(conditions); return this; } public MySpecification and(QueryParams... conditions) { for (QueryParams condition : conditions) { andConditions.add(condition); } return this; } public MySpecification or(Collection conditions) { orConditions.addAll(conditions); return this; } public MySpecification or(QueryParams... conditions) { for (QueryParams condition : conditions) { orConditions.add(condition); } return this; } public MySpecification desc(String property) { this.orders.add(Order.desc(property)); return this; } public MySpecification asc(String property) { this.orders.add(Order.asc(property)); return this; } public MySpecification order(String property, Sort.Direction direction) { this.orders.add(new Order(property, direction)); return this; } public MySpecification orders(Order... orders) { this.orders.addAll(Arrays.asList(orders)); return this; } public MySpecification orders(Collection orders) { this.orders.addAll(orders); return this; } private Predicate getAndPredicates(Root root, CriteriaBuilder cb) { Predicate restrictions = cb.conjunction(); for (QueryParams condition : andConditions) { if (condition == null) { continue; } Path path = this.getPath(root, condition.property); if (path == null) { continue; } switch (condition.operator) { case eq: if (condition.value != null) { if (String.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof String) { if (!((String) condition.value).isEmpty()) { restrictions = cb.and(restrictions, cb.equal(path, condition.value)); } } else { restrictions = cb.and(restrictions, cb.equal(path, condition.value)); } } break; case ge: if (Number.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof Number) { restrictions = cb.and(restrictions, cb.ge((Path ) path, (Number) condition.value)); } break; case gt: if (Number.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof Number) { restrictions = cb.and(restrictions, cb.gt((Path ) path, (Number) condition.value)); } break; case in: restrictions = cb.and(restrictions, path.in(condition.value)); break; case le: if (Number.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof Number) { restrictions = cb.and(restrictions, cb.le((Path ) path, (Number) condition.value)); } break; case lt: if (Number.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof Number) { restrictions = cb.and(restrictions, cb.lt((Path ) path, (Number) condition.value)); } break; case ne: if (condition.value != null) { if (String.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof String && !((String) condition.value).isEmpty()) { restrictions = cb.and(restrictions, cb.notEqual(path, condition.value)); } else { restrictions = cb.and(restrictions, cb.notEqual(path, condition.value)); } } break; case like: if (condition.value != null) { if (String.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof String && !((String) condition.value).isEmpty()) { restrictions = cb.and(restrictions, cb.like((Path ) path, "%" + condition.value + "%")); } } break; case ilike: if (condition.value != null) { if (String.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof String && !((String) condition.value).isEmpty()) { restrictions = cb.and(restrictions, cb.like((Path ) path, (String) condition.value)); } } break; case llike: if (condition.value != null) { if (String.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof String && !((String) condition.value).isEmpty()) { restrictions = cb.and(restrictions, cb.like((Path ) path, "%" + condition.value)); } } break; case rlike: if (condition.value != null) { if (String.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof String && !((String) condition.value).isEmpty()) { restrictions = cb.and(restrictions, cb.like((Path ) path, condition.value + "%")); } } break; case notIn: restrictions = cb.and(restrictions, path.in(condition.value).not()); break; case isNull: restrictions = cb.and(restrictions, path.isNull()); break; case isNotNull: restrictions = cb.and(restrictions, path.isNotNull()); break; default: break; } } return restrictions; } private Predicate getOrPredicates(Root root, CriteriaBuilder cb) { Predicate restrictions = cb.conjunction(); for (QueryParams condition : orConditions) { if (condition == null) { continue; } Path path = this.getPath(root, condition.property); if (path == null) { continue; } switch (condition.operator) { case eq: if (condition.value != null) { if (String.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof String) { if (!((String) condition.value).isEmpty()) { restrictions = cb.or(restrictions, cb.equal(path, condition.value)); } } } else { restrictions = cb.or(restrictions, path.isNull()); } break; case ge: if (Number.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof Number) { restrictions = cb.or(restrictions, cb.ge((Path ) path, (Number) condition.value)); } break; case gt: if (Number.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof Number) { restrictions = cb.or(restrictions, cb.gt((Path ) path, (Number) condition.value)); } break; case in: restrictions = cb.or(restrictions, path.in(condition.value)); break; case le: if (Number.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof Number) { restrictions = cb.or(restrictions, cb.le((Path ) path, (Number) condition.value)); } break; case lt: if (Number.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof Number) { restrictions = cb.or(restrictions, cb.lt((Path ) path, (Number) condition.value)); } break; case ne: if (condition.value != null) { if (String.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof String && !((String) condition.value).isEmpty()) { restrictions = cb.or(restrictions, cb.notEqual(path, condition.value)); } else { restrictions = cb.or(restrictions, cb.notEqual(path, condition.value)); } } break; case like: if (condition.value != null) { if (String.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof String && !((String) condition.value).isEmpty()) { restrictions = cb.or(restrictions, cb.like((Path ) path, "%" + condition.value + "%")); } } break; case ilike: if (condition.value != null) { if (String.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof String && !((String) condition.value).isEmpty()) { restrictions = cb.or(restrictions, cb.like((Path ) path, (String) condition.value)); } } break; case llike: if (condition.value != null) { if (String.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof String && !((String) condition.value).isEmpty()) { restrictions = cb.or(restrictions, cb.like((Path ) path, "%" + condition.value)); } } break; case rlike: if (condition.value != null) { if (String.class.isAssignableFrom(path.getJavaType()) && condition.value instanceof String && !((String) condition.value).isEmpty()) { restrictions = cb.or(restrictions, cb.like((Path ) path, condition.value + "%")); } } break; case notIn: restrictions = cb.or(restrictions, path.in(condition.value).not()); break; case isNull: restrictions = cb.or(restrictions, path.isNull()); break; case isNotNull: restrictions = cb.or(restrictions, path.isNotNull()); break; default: break; } } return restrictions; } private List getOrders(Root root, CriteriaBuilder cb) { List orderList = new ArrayList<>(); if (root == null || CollectionUtils.isEmpty(orders)) { return orderList; } for (Order order : orders) { if (order == null) { continue; } String property = order.getProperty(); Sort.Direction direction = order.getDirection(); Path path = this.getPath(root, property); if (path == null || direction == null) { continue; } switch (direction) { case ASC: orderList.add(cb.asc(path)); break; case DESC: orderList.add(cb.desc(path)); break; default: break; } } return orderList; } /** * 获取Path * * @param path Path * @param propertyPath 属性路径 * @return Path */ private Path getPath(Path path, String propertyPath) { if (path == null || StringUtils.isEmpty(propertyPath)) { return (Path ) path; } String property = StringUtils.substringBefore(propertyPath, PROPERTY_SEPARATOR); return getPath(path.get(property), StringUtils.substringAfter(propertyPath, PROPERTY_SEPARATOR)); } /** * 运算符 */ public enum Operator { /** * 等于 */ eq(" = "), /** * 不等于 */ ne(" != "), /** * 大于 */ gt(" > "), /** * 小于 */ lt(" < "), /** * 大于等于 */ ge(" >= "), /** * 小于等于 */ le(" <= "), /** * 类似 */ like(" like "), /** * 类似 */ rlike("like "), /** * 类似 */ llike(" like "), /** * 类似 */ ilike(" like "), /** * 包含 */ in(" in "), /** * 包含 */ notIn(" not in "), /** * 为Null */ isNull(" is NULL "), /** * 不为Null */ isNotNull(" is not NULL "); private String operator; Operator(String operator) { this.operator = operator; } public String getOperator() { return operator; } public void setOperator(String operator) { this.operator = operator; } } /** * 条件 */ public static class QueryParams { Operator operator; String property; Object value; public QueryParams(String property, Operator operator, Object value) { this.operator = operator; this.property = property; this.value = value; } public QueryParams(String property, Operator operator) { this.operator = operator; this.property = property; } /** * 相等 * * @param property * @param value * @return */ public static QueryParams eq(String property, Object value) { return new QueryParams(property, Operator.eq, value); } /** * 不相等 * * @param property * @param value * @return */ public static QueryParams ne(String property, Object value) { return new QueryParams(property, Operator.ne, value); } /** * 大于 * * @param property * @param value * @return */ public static QueryParams gt(String property, Object value) { return new QueryParams(property, Operator.gt, value); } /** * 小于 * * @param property * @param value * @return */ public static QueryParams lt(String property, Object value) { return new QueryParams(property, Operator.lt, value); } /** * 大于等于 * * @param property * @param value * @return */ public static QueryParams ge(String property, Object value) { return new QueryParams(property, Operator.ge, value); } /** * 小于等于 * * @param property * @param value * @return */ public static QueryParams le(String property, Object value) { return new QueryParams(property, Operator.le, value); } /** * like %% * * @param property * @param value * @return */ public static QueryParams like(String property, Object value) { return new QueryParams(property, Operator.like, value); } /** * 右like xxx% * * @param property * @param value * @return */ public static QueryParams rlike(String property, Object value) { return new QueryParams(property, Operator.rlike, value); } /** *左like %xxx * * @param property * @param value * @return */ public static QueryParams llike(String property, Object value) { return new QueryParams(property, Operator.llike, value); } /** * 自定义模糊 * * @param property * @param value * @return */ public static QueryParams ilike(String property, Object value) { return new QueryParams(property, Operator.ilike, value); } /** * 集合中 * * @param property * @param value * @return */ public static QueryParams in(String property, Object value) { return new QueryParams(property, Operator.in, value); } /** * 不在集合中 * * @param property * @param value * @return */ public static QueryParams notIn(String property, Object value) { return new QueryParams(property, Operator.notIn, value); } /** * 是空 * * @param property * @return */ public static QueryParams isNull(String property) { return new QueryParams(property, Operator.isNull); } /** * 不是空 * * @param property * @return */ public static QueryParams isNotNull(String property) { return new QueryParams(property, Operator.isNotNull); } } /** * 排序 */ public static class Order { private String property; private Sort.Direction direction = Sort.Direction.ASC; /** * 构造方法 */ public Order() { } /** * 构造方法 * * @param property 属性 * @param direction 方向 */ public Order(String property, Sort.Direction direction) { this.property = property; this.direction = direction; } /** * 返回递增排序 * * @param property 属性 * @return 递增排序 */ public static Order asc(String property) { return new Order(property, Sort.Direction.ASC); } /** * 返回递减排序 * * @param property 属性 * @return 递减排序 */ public static Order desc(String property) { return new Order(property, Sort.Direction.DESC); } @Override public String toString() { return property + " " + direction.name(); } public Sort.Direction getDirection() { return direction; } public String getProperty() { return property; } } }