spring-data-jpa 简单查询:封装及使用

简单查询条件封装

package com.lky.commons.specification;

import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.Collection;
import java.util.Date;
import java.util.List;

/**
 * 简单条件表达式
 *
 * @author luckyhua
 * @version 1.0
 * @since 2017/9/19
 */
public class SimpleSpecification<T> implements Specification<T> {

    /**
     * 查询的条件列表,是一组列表
     */
    private List<SpecificationOperator> operators;

    public SimpleSpecification(List<SpecificationOperator> operators) {
        this.operators = operators;
    }

    @Override
    public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        int index = 0;
        //通过resultPre来组合多个条件
        Predicate resultPre = null;
        for (SpecificationOperator op : operators) {
            if (index++ == 0) {
                resultPre = generatePredicate(root, cb, op);
                continue;
            }
            Predicate pre = generatePredicate(root, cb, op);
            if (pre == null) {
                continue;
            }
            switch (op.getJoin()) {
                case and:
                    resultPre = cb.and(resultPre, pre);
                    break;
                case or:
                    resultPre = cb.or(resultPre, pre);
                    break;
                default:
            }
        }
        return resultPre;
    }

    /**
     * 根据不同的操作符返回特定的查询
     *
     * @param root root
     * @param cb   条件构造器
     * @param op   操作对象
     * @return 逻辑表达式
     */
    private Predicate generatePredicate(Root<T> root, CriteriaBuilder cb, SpecificationOperator op) {
        Object value = op.getValue();
        switch (op.getOperator()) {
            case eq:
                return cb.equal(root.get(op.getKey()), value);
            case ne:
                return cb.notEqual(root.get(op.getKey()), value);
            case ge:
                return cb.ge(root.get(op.getKey()).as(Number.class), (Number) value);
            case le:
                return cb.le(root.get(op.getKey()).as(Number.class), (Number) value);
            case gt:
                return cb.gt(root.get(op.getKey()).as(Number.class), (Number) value);
            case lt:
                return cb.lt(root.get(op.getKey()).as(Number.class), (Number) value);
            case in:
                if (value instanceof Collection) {
                    return root.get(op.getKey()).in((Collection) value);
                }
                return root.get(op.getKey()).in(value);
            case notIn:
                if (value instanceof Collection) {
                    return cb.not(root.get(op.getKey()).in((Collection) value));
                }
                return cb.not(root.get(op.getKey()).in(value));
            case likeAll:
                return cb.like(root.get(op.getKey()).as(String.class), "%" + value + "%");
            case likeL:
                return cb.like(root.get(op.getKey()).as(String.class), value + "%");
            case likeR:
                return cb.like(root.get(op.getKey()).as(String.class), "%" + value);
            case isNull:
                return cb.isNull(root.get(op.getKey()));
            case isNotNull:
                return cb.isNotNull(root.get(op.getKey()));
            case lessThan:
                if (value instanceof Date) {
                    return cb.lessThan(root.get(op.getKey()), (Date) value);
                }
            case lessThanEqual:
                if (value instanceof Date) {
                    return cb.lessThanOrEqualTo(root.get(op.getKey()), (Date) value);
                }
            case greaterThan:
                if (value instanceof Date) {
                    return cb.greaterThan(root.get(op.getKey()), (Date) value);
                }
            case greaterThanEqual:
                if (value instanceof Date) {
                    return cb.greaterThanOrEqualTo(root.get(op.getKey()), (Date) value);
                }
            case between:
                if (value instanceof Date[]) {
                    Date[] dateArray = (Date[]) value;
                    return cb.between(root.get(op.getKey()), dateArray[0], dateArray[1]);
                }
            default:
                return null;
        }
    }
}

package com.lky.commons.specification;

import org.springframework.data.jpa.domain.Specification;

import java.util.ArrayList;
import java.util.List;

/**
 * 条件构造器
 * 用于创建条件表达式
 *
 * @author luckyhua
 * @version 1.0
 * @since 2017/9/19
 */
public class SimpleSpecificationBuilder<T> {

    /**
     * 条件列表
     */
    private List<SpecificationOperator> operators;

    public SimpleSpecificationBuilder() {
        operators = new ArrayList<>();
    }

    /**
     * 构造函数,初始化的条件是and
     *
     * @param key      条件的建
     * @param operator 条件
     * @param value    条件的值
     * @return 添加完的条件
     */
    public SimpleSpecificationBuilder(String key, SpecificationOperator.Operator operator, Object value) {
        SpecificationOperator so = new SpecificationOperator();
        so.setJoin(SpecificationOperator.Join.and);
        so.setKey(key);
        so.setOperator(operator);
        so.setValue(value);
        operators = new ArrayList<>();
        operators.add(so);
    }

    /**
     * 完成条件的添加
     *
     * @param join     连接符
     * @param key      条件的建
     * @param operator 条件
     * @param value    条件的值
     * @return this,方便后续的链式调用
     */
    public SimpleSpecificationBuilder<T> add(SpecificationOperator.Join join, String key, SpecificationOperator.Operator operator, Object value) {
        SpecificationOperator so = new SpecificationOperator();
        so.setJoin(join);
        so.setKey(key);
        so.setValue(value);
        so.setOperator(operator);
        operators.add(so);
        return this;
    }

    /**
     * 添加or条件
     *
     * @param key      条件的建
     * @param operator 条件
     * @param value    条件的值
     * @return this,方便后续的链式调用
     */
    public SimpleSpecificationBuilder<T> addOr(String key, SpecificationOperator.Operator operator, Object value) {
        return this.add(SpecificationOperator.Join.or, key, operator, value);
    }

    /**
     * 添加and条件
     *
     * @param key      条件的建
     * @param operator 条件
     * @param value    条件的值
     * @return this,方便后续的链式调用
     */
    public SimpleSpecificationBuilder<T> add(String key, SpecificationOperator.Operator operator, Object value) {
        return this.add(SpecificationOperator.Join.and, key, operator, value);
    }

    /**
     * 构建条件表达式
     *
     * @return 表达式
     */
    public Specification<T> generateSpecification() {
        return new SimpleSpecification<>(operators);
    }
}

package com.lky.commons.specification;

/**
 * 操作符类,这个类中存储了键值对和操作符号,另外存储了连接下一个条件的类型是and还是or
 * <br>
 * 创建时通过 id>=7,其中id就是key,>=就是operator操作符,7就是value
 * <br>
 * 特殊的自定义几个操作符(:表示like %v%,b:表示v%,:b表示%v)
 *
 * @author luckyhua
 * @version 1.0
 * @since 2017/9/19
 */
public class SpecificationOperator {

    /**
     * 操作符的key,如查询时的name,id之类
     */
    private String key;

    /**
     * 操作符的value,具体要查询的值
     */
    private Object value;

    /**
     * 操作符,自己定义的一组操作符,用来方便查询
     */
    private Operator operator;

    /**
     * 连接的方式:and或者or
     */
    private Join join;

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public Object getValue() {
        return value;
    }

    public void setValue(Object value) {
        this.value = value;
    }

    public Operator getOperator() {
        return operator;
    }

    public void setOperator(Operator operator) {
        this.operator = operator;
    }

    public Join getJoin() {
        return join;
    }

    public void setJoin(Join join) {
        this.join = join;
    }

    public enum Operator {
        eq, ne, ge, le, gt, lt, likeL, likeR, likeAll, isNull, isNotNull, in, notIn,
        lessThan, lessThanEqual, greaterThan, greaterThanEqual, between;

        @Override
        public String toString() {
            return name();
        }
    }

    public enum Join {
        and, or;

        @Override
        public String toString() {
            return name();
        }
    }
}

简单查询条件使用

//测试between
Date date = new Date();
Date beginDate = DateUtils.getBeginDate(date, DAY_OF_YEAR);
SimpleSpecificationBuilder<User> builder = new SimpleSpecificationBuilder<>();
builder.add("createTime", SpecificationOperator.Operator.between, new Date[]{beginDate, date});
List<User> userList = userService.findAll(builder.generateSpecification());
System.out.println("0------------------" + userList.size());

//测试in
Set<Integer> idSet = new HashSet<>();
idSet.add(1);
idSet.add(2);
idSet.add(1999);
SimpleSpecificationBuilder<User> builder1 = new SimpleSpecificationBuilder<>();
builder1.add("id", SpecificationOperator.Operator.in, idSet);
List<User> userList1 = userService.findAll(builder1.generateSpecification());
System.out.println("1------------------" + userList1.size());

//测试not in
SimpleSpecificationBuilder<User> builder2 = new SimpleSpecificationBuilder<>();
builder2.add("id", SpecificationOperator.Operator.notIn, 1);
List<User> userList2 = userService.findAll(builder2.generateSpecification());
System.out.println("2------------------" + userList2.size());

//测试lessThanEqual
SimpleSpecificationBuilder<User> builder3 = new SimpleSpecificationBuilder<>();
builder3.add("createTime", SpecificationOperator.Operator.lessThanEqual, beginDate);
List<User> userList3 = userService.findAll(builder3.generateSpecification());
System.out.println("3------------------" + userList3.size());

//测试like
SimpleSpecificationBuilder<SUser> builder4 = new SimpleSpecificationBuilder<>();
builder4.add("username", SpecificationOperator.Operator.likeAll, "l");
List<SUser> sUserList = sUserDao.findAll(builder4.generateSpecification());
sUserList.forEach(sUser -> System.out.println(sUser.getUsername()));

//实例代码使用一
SimpleSpecificationBuilder<Category> builder = new SimpleSpecificationBuilder<>();
if (StringUtils.isNotEmpty(name)) {
    builder.add("name", SpecificationOperator.Operator.likeAll, name.trim());
}
if (parentId != null) {
    builder.add("parentId", SpecificationOperator.Operator.eq, parentId);
} else {
    builder.add("parentId", SpecificationOperator.Operator.isNull, null);
}
List<Category> categoryList = categoryService.findAll(builder.generateSpecification());

//实例代码使用二
SimpleSpecificationBuilder<UserMessage> builder = new SimpleSpecificationBuilder<>();
        builder.add("userId", SpecificationOperator.Operator.eq, user.getId());
if (StringUtils.isNotEmpty(type)) {
    builder.add("targetType", SpecificationOperator.Operator.eq, type);
}
if (StringUtils.isNotEmpty(title)) {
    builder.add("title", SpecificationOperator.Operator.likeAll, title);
}
Sort sort = new Sort(
        new Sort.Order(Sort.Direction.DESC, "unread"),
        new Sort.Order(Sort.Direction.DESC, "id"));
Pageable pageable = new PageRequest(pageNumber, pageSize, sort);
Page<UserMessage> userMessageList = userMessageService.findAll(builder.generateSpecification(), pageable);         
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341

推荐阅读更多精彩内容