jpa对于固定参数的条件查询比较简单,可以在Repository中直接用参数名来查询。但是对于不固定的参数查询就比较麻烦了,官方提供的是继承JpaSpecificationExecutor,然后自己拼接Specification。这一篇主要是对Specification进行封装,让写法更友好.
代码参考:http://lee1177.iteye.com/blog/1994295。感觉还不够完整,回头使用中再补上。
一:自定义Specification
创建条件表达式接口,模拟系统的条件查询
import javax.persistence.criteria.CriteriaBuilder;import javax.persistence.criteria.CriteriaQuery;import javax.persistence.criteria.Predicate;import javax.persistence.criteria.Root;public interface Criterion { enum Operator { EQ, NE, LIKE, GT, LT, GTE, LTE, AND, OR, IS_MEMBER, IS_NOT_MEMBER } Predicate toPredicate(Root<?> root, CriteriaQuery<?> query, CriteriaBuilder builder);}12345678910111213
创建一个自定义的Sepcification,添加add方法用来添加多个条件
import javax.persistence.criteria.CriteriaBuilder;import javax.persistence.criteria.CriteriaQuery;import javax.persistence.criteria.Predicate;import javax.persistence.criteria.Root;import java.util.ArrayList;import java.util.List;/** * Created by 定义一个查询条件容器 on 17/6/6. */public class Criteria<T> implements Specification<T> { private List<Criterion> criterions = new ArrayList<>(); @Override public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) { if (!criterions.isEmpty()) { List<Predicate> predicates = new ArrayList<>(); for (Criterion c : criterions) { predicates.add(c.toPredicate(root, query, builder)); } // 将所有条件用 and 联合起来 if (predicates.size() > 0) { return builder.and(predicates.toArray(new Predicate[predicates.size()])); } } return builder.conjunction(); } /** * 增加简单条件表达式 * * @Methods Name add * @Create In 2012-2-8 By lee */ public void add(Criterion criterion) { if (criterion != null) { criterions.add(criterion); } } }1234567891011121314151617181920212223242526272829303132333435363738394041
二:创建条件表达式接口的不同实现类
import org.springframework.util.StringUtils;import javax.persistence.criteria.*;import java.util.List;import java.util.Map;import java.util.Set;/** * 简单条件表达式 * * @author lee */public class SimpleExpression implements Criterion { /** * 属性名 */ private String fieldName; /** * 对应值 */ private Object value; /** * 计算符 */ private Operator operator; protected SimpleExpression(String fieldName, Object value, Operator operator) { this.fieldName = fieldName; this.value = value; this.operator = operator; } @Override @SuppressWarnings({"rawtypes", "unchecked"}) public Predicate toPredicate(Root<?> root, CriteriaQuery<?> query, CriteriaBuilder builder) { Path expression; //此处是表关联数据,注意仅限一层关联,如user.address, //查询user的address集合中,address的name为某个值 if (fieldName.contains(".")) { String[] names = StringUtils.split(fieldName, "."); //获取该属性的类型,Set?List?Map? expression = root.get(names[0]); Class clazz = expression.getJavaType(); if (clazz.equals(Set.class)) { SetJoin setJoin = root.joinSet(names[0]); expression = setJoin.get(names[1]); } else if (clazz.equals(List.class)) { ListJoin listJoin = root.joinList(names[0]); expression = listJoin.get(names[1]); } else if (clazz.equals(Map.class)) { MapJoin mapJoin = root.joinMap(names[0]); expression = mapJoin.get(names[1]); } else { //是many to one时 expression = expression.get(names[1]); } } else { //单表查询 expression = root.get(fieldName); } switch (operator) { case EQ: return builder.equal(expression, value); case NE: return builder.notEqual(expression, value); case LIKE: return builder.like((Expression<String>) expression, "%" + value + "%"); case LT: return builder.lessThan(expression, (Comparable) value); case GT: return builder.greaterThan(expression, (Comparable) value); case LTE: return builder.lessThanOrEqualTo(expression, (Comparable) value); case GTE: return builder.greaterThanOrEqualTo(expression, (Comparable) value); case IS_MEMBER: return builder.isMember(value, expression); case IS_NOT_MEMBER: return builder.isNotMember(value, expression); default: return null; } } }123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
import javax.persistence.criteria.CriteriaBuilder;import javax.persistence.criteria.CriteriaQuery;import javax.persistence.criteria.Predicate;import javax.persistence.criteria.Root;import java.util.ArrayList;import java.util.List;/** * 逻辑条件表达式 用于复杂条件时使用,如单属性多对应值的OR查询等 * * @author lee */public class LogicalExpression implements Criterion { /** * 逻辑表达式中包含的表达式 */ private Criterion[] criterion; /** * 计算符 */ private Operator operator; public LogicalExpression(Criterion[] criterions, Operator operator) { this.criterion = criterions; this.operator = operator; } @Override public Predicate toPredicate(Root<?> root, CriteriaQuery<?> query, CriteriaBuilder builder) { List<Predicate> predicates = new ArrayList<>(); for (int i = 0; i < this.criterion.length; i++) { predicates.add(this.criterion[i].toPredicate(root, query, builder)); } switch (operator) { case OR: return builder.or(predicates.toArray(new Predicate[predicates.size()])); default: return null; } } }12345678910111213141516171819202122232425262728293031323334353637383940414243
这两个类分别模拟不同的条件查询。
三:创建一个工厂类,根据条件创建不同的实现类
import org.springframework.util.StringUtils;import java.util.Collection;/** * 条件构造器 * 用于创建条件表达式 * * @Class Name Restrictions * @Author lee */public class Restrictions { /** * 等于 */ public static SimpleExpression eq(String fieldName, Object value, boolean ignoreNull) { if (ignoreNull && StringUtils.isEmpty(value)) { return null; } return new SimpleExpression(fieldName, value, Criterion.Operator.EQ); } /** * 集合包含某个元素 */ public static SimpleExpression hasMember(String fieldName, Object value, boolean ignoreNull) { if (ignoreNull && StringUtils.isEmpty(value)) { return null; } return new SimpleExpression(fieldName, value, Criterion.Operator.IS_MEMBER); } /** * 不等于 */ public static SimpleExpression ne(String fieldName, Object value, boolean ignoreNull) { if (ignoreNull && StringUtils.isEmpty(value)) { return null; } return new SimpleExpression(fieldName, value, Criterion.Operator.NE); } /** * 模糊匹配 */ public static SimpleExpression like(String fieldName, String value, boolean ignoreNull) { if (ignoreNull && StringUtils.isEmpty(value)) { return null; } return new SimpleExpression(fieldName, value, Criterion.Operator.LIKE); } /** */// public static SimpleExpression like(String fieldName, String value,// MatchMode matchMode, boolean ignoreNull) {// if (StringUtils.isEmpty(value)) return null;// return null;// } /** * 大于 */ public static SimpleExpression gt(String fieldName, Object value, boolean ignoreNull) { if (ignoreNull && StringUtils.isEmpty(value)) { return null; } return new SimpleExpression(fieldName, value, Criterion.Operator.GT); } /** * 小于 */ public static SimpleExpression lt(String fieldName, Object value, boolean ignoreNull) { if (ignoreNull && StringUtils.isEmpty(value)) { return null; } return new SimpleExpression(fieldName, value, Criterion.Operator.LT); } /** * 小于等于 */ public static SimpleExpression lte(String fieldName, Object value, boolean ignoreNull) { if (ignoreNull && StringUtils.isEmpty(value)) { return null; } return new SimpleExpression(fieldName, value, Criterion.Operator.GTE); } /** * 大于等于 */ public static SimpleExpression gte(String fieldName, Object value, boolean ignoreNull) { if (ignoreNull && StringUtils.isEmpty(value)) { return null; } return new SimpleExpression(fieldName, value, Criterion.Operator.LTE); } /** * 并且 */ public static LogicalExpression and(Criterion... criterions) { return new LogicalExpression(criterions, Criterion.Operator.AND); } /** * 或者 */ public static LogicalExpression or(Criterion... criterions) { return new LogicalExpression(criterions, Criterion.Operator.OR); } /** * 包含于 */ @SuppressWarnings("rawtypes") public static LogicalExpression in(String fieldName, Collection value, boolean ignoreNull) { if (ignoreNull && (value == null || value.isEmpty())) { return null; } SimpleExpression[] ses = new SimpleExpression[value.size()]; int i = 0; for (Object obj : value) { ses[i] = new SimpleExpression(fieldName, obj, Criterion.Operator.EQ); i++; } return new LogicalExpression(ses, Criterion.Operator.OR); } /** * 集合包含某几个元素,譬如可以查询User类中Set<String> set包含"ABC","bcd"的User集合, * 或者查询User中Set<Address>的Address的name为"北京"的所有User集合 * 集合可以为基本类型或者JavaBean,可以是one to many或者是@ElementCollection * @param fieldName * 列名 * @param value * 集合 * @return * expresssion */ public static LogicalExpression hasMembers(String fieldName, Object... value) { SimpleExpression[] ses = new SimpleExpression[value.length]; int i = 0; //集合中对象是基本类型,如Set<Long>,List<String> Criterion.Operator operator = Criterion.Operator.IS_MEMBER; //集合中对象是JavaBean if (fieldName.contains(".")) { operator = Criterion.Operator.EQ; } for (Object obj : value) { ses[i] = new SimpleExpression(fieldName, obj, operator); i++; } return new LogicalExpression(ses, Criterion.Operator.OR); } }123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
四:使用
假设有个Post的entity,有title,content,count,url等参数,再创建一个PostRepository extends JpaRepository
@Test public void contextLoads() { Criteria<Post> criteria = new Criteria<>(); criteria.add(Restrictions.like("title", "1", true)); criteria.add(Restrictions.eq("content", "content1", true)); List<Post> postList = postRepository.findAll(criteria); for (Post post : postList) { System.out.println(post); } }123456789101112
这里就可以比较优雅的创建不同的条件,然后拼接起来查询即可。相比之下要比原生的写法如
studentInfoDao.findAll(new Specification<StudentInfo> () { public Predicate toPredicate(Root<StudentInfo> root, CriteriaQuery<?> query, CriteriaBuilder cb) { Path<String> namePath = root.get("name"); Path<String> nicknamePath = root.get("nickname"); /** * 连接查询条件, 不定参数,可以连接0..N个查询条件 */ query.where(cb.like(namePath, "%李%"), cb.like(nicknamePath, "%王%")); //这里可以设置任意条查询条件 return null; } }, page); } 123456789101112131415161718
比这种写法好看一点。
版权声明:本文为博主武伟峰原创文章,转载请注明地址http://blog.csdn.net/tianyaleixiaowu。