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。

网友评论

更多精彩分享

游戏论坛模拟-Java培训机构,青岛Java培训,青岛计算机培训,软件编程培训,seo优化培训,网络推广培训,网络营销培训,SEM培训,网络优化,在线营销培训,Java培训游戏论坛模拟