文档章节

springdata中Specification查询封装

SPPan
 SPPan
发布于 2017/05/31 15:24
字数 730
阅读 80
收藏 0

1、定义操作符类:

package net.sppan.base.service.specification;
 
/**
 * 操作符类,这个类中存储了键值对和操作符号,另外存储了连接下一个条件的类型是and还是or
 * <br>
 * 创建时通过 id>=7,其中id就是key,>=就是oper操作符,7就是value
 * <br>
 * 特殊的自定义几个操作符(:表示like %v%,b:表示v%,:b表示%v)
 */
public class SpecificationOperator {
    /**
     * 操作符的key,如查询时的name,id之类
     */
    private String key;
    /**
     * 操作符的value,具体要查询的值
     */
    private Object value;
    /**
     * 操作符,自己定义的一组操作符,用来方便查询
     */
    private String oper;
    /**
     * 连接的方式:and或者or
     */
    private String 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 String getOper() {
        return oper;
    }
 
    public void setOper(String oper) {
        this.oper = oper;
    }
 
    public String getJoin() {
        return join;
    }
 
    public void setJoin(String join) {
        this.join = join;
    }
    
	public static enum Operator {
		eq, ge, le, gt, lt, likeL, likeR, likeAll, isNull, isNotNull, notEqual;
		@Override
		public String toString() {
			return name();
		}
	}
	public static enum Join {
		and, or;
		@Override
		public String toString() {
			return name();
		}
	}
}

2、Specification实现类:

package net.sppan.base.service.specification;
 
import net.sppan.base.service.specification.SpecificationOperator.Join;
 
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.List;
 
public class SimpleSpecification<T> implements Specification<T> {
 
    /**
     * 查询的条件列表,是一组列表
     * */
    private List<SpecificationOperator> opers;
 
    public SimpleSpecification(List<SpecificationOperator> opers) {
        this.opers = opers;
    }
 
    @Override
    public Predicate toPredicate(Root<T> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
        int index = 0;
        //通过resultPre来组合多个条件
        Predicate resultPre = null;
        for(SpecificationOperator op:opers) {
            if(index++==0) {
                resultPre = generatePredicate(root,criteriaBuilder,op);
                continue;
            }
            Predicate pre = generatePredicate(root,criteriaBuilder,op);
            if(pre==null) continue;
            if(Join.and.name().equalsIgnoreCase(op.getJoin())) {
                resultPre = criteriaBuilder.and(resultPre,pre);
            } else if(Join.or.name().equalsIgnoreCase(op.getJoin())) {
                resultPre = criteriaBuilder.or(resultPre,pre);
            }
        }
        return resultPre;
    }
 
    private Predicate generatePredicate(Root<T> root,CriteriaBuilder criteriaBuilder, SpecificationOperator op) {
        /*
        * 根据不同的操作符返回特定的查询*/
        if(SpecificationOperator.Operator.eq.name().equalsIgnoreCase(op.getOper())) {
            return criteriaBuilder.equal(root.get(op.getKey()),op.getValue());
        } else if(SpecificationOperator.Operator.ge.name().equalsIgnoreCase(op.getOper())) {
            return criteriaBuilder.ge(root.get(op.getKey()).as(Number.class), (Number)op.getValue());
        } else if(SpecificationOperator.Operator.le.name().equalsIgnoreCase(op.getOper())) {
            return criteriaBuilder.le(root.get(op.getKey()).as(Number.class),(Number)op.getValue());
        } else if(SpecificationOperator.Operator.gt.name().equalsIgnoreCase(op.getOper())) {
            return criteriaBuilder.gt(root.get(op.getKey()).as(Number.class),(Number)op.getValue());
        } else if(SpecificationOperator.Operator.lt.name().equalsIgnoreCase(op.getOper())) {
            return criteriaBuilder.lt(root.get(op.getKey()).as(Number.class),(Number)op.getValue());
        } else if(SpecificationOperator.Operator.likeAll.name().equalsIgnoreCase(op.getOper())) {
            return criteriaBuilder.like(root.get(op.getKey()).as(String.class),"%"+op.getValue()+"%");
        } else if(SpecificationOperator.Operator.likeL.name().equalsIgnoreCase(op.getOper())) {
            return criteriaBuilder.like(root.get(op.getKey()).as(String.class),op.getValue()+"%");
        } else if(SpecificationOperator.Operator.likeR.name().equalsIgnoreCase(op.getOper())) {
            return criteriaBuilder.like(root.get(op.getKey()).as(String.class),"%"+op.getValue());
        } else if(SpecificationOperator.Operator.isNull.name().equalsIgnoreCase(op.getOper())) {
            return criteriaBuilder.isNull(root.get(op.getKey()));
        } else if(SpecificationOperator.Operator.isNotNull.name().equalsIgnoreCase(op.getOper())) {
            return criteriaBuilder.isNotNull(root.get(op.getKey()));
        } else if(SpecificationOperator.Operator.notEqual.name().equalsIgnoreCase(op.getOper())) {
            return criteriaBuilder.notEqual(root.get(op.getKey()),op.getValue());
        }
        return null;
    }
 
}

3、查询条件构造类:

package net.sppan.base.service.specification;
 
import java.util.ArrayList;
import java.util.List;
 
import net.sppan.base.service.specification.SpecificationOperator.Join;
 
import org.springframework.data.jpa.domain.Specification;
 
public class SimpleSpecificationBuilder<T> {
 
    /**
     * 条件列表
     */
    private List<SpecificationOperator> opers;
 
    /**
     * 构造函数,初始化的条件是and
     */
    public SimpleSpecificationBuilder(String key,String oper,Object value) {
        SpecificationOperator so = new SpecificationOperator();
        so.setJoin(Join.and.name());
        so.setKey(key);
        so.setOper(oper);
        so.setValue(value);
        opers = new ArrayList<SpecificationOperator>();
        opers.add(so);
    }
 
    public SimpleSpecificationBuilder() {
        opers = new ArrayList<SpecificationOperator>();
    }
 
    /**
     * 完成条件的添加
     * @return
     */
    public SimpleSpecificationBuilder<T> add(String key,String oper,Object value,String join) {
        SpecificationOperator so = new SpecificationOperator();
        so.setKey(key);
        so.setValue(value);
        so.setOper(oper);
        so.setJoin(join);
        opers.add(so);
        return this;
    }
 
 
    /**
     * 添加or条件的重载
     * @return this,方便后续的链式调用
     */
    public SimpleSpecificationBuilder<T> addOr(String key,String oper,Object value) {
        return this.add(key,oper,value,Join.or.name());
    }
 
    /**
     * 添加and的条件
     * @return
     */
    public SimpleSpecificationBuilder<T> add(String key,String oper,Object value) {
        return this.add(key,oper,value,Join.and.name());
    }
 
 
    public Specification<T> generateSpecification() {
        Specification<T> specification = new SimpleSpecification<T>(opers);
        return specification;
    }
}

4、使用示例

SimpleSpecificationBuilder<Resource> builder = new SimpleSpecificationBuilder<Resource>();//Resource 持久层实体
builder.add("name", Operator.likeAll.name(), "keyword");
Specification specification = builder.generateSpecification()

© 著作权归作者所有

SPPan
粉丝 11
博文 29
码字总数 15103
作品 0
成都
程序员
私信 提问
技术专题讨论:如何对 JPA 或者 MyBatis 进行技术选型

在我们平时的项目中,大家都知道可以使用 JPA 或者 Mybatis 作为 ORM 层。对 JPA 和 Mybatis 如何进行技术选型? 下面看看大精华总结如下: 最佳回答 首先表达个人观点,JPA必然是首选的。 ...

后海
2018/06/27
0
0
Elasticsearch

本地搭建了ELK中的EL环境,通过logstash采集日志到es中,然后springboot工程与elasticsearch集成,采用springdata-elasticsearch, 三种查询方式: 1. 使用springdata-elasticsearch提供的...

aybaylyn
2016/12/22
159
0
Spring Data Redis与Jedis的选择(转)

说明:内容可能有点旧,需要在业务上做权衡。 Redis的客户端有两种实现方式,一是可以直接调用Jedis来实现,二是可以使用Spring Data Redis,通过Spring的封装来调用。应该使用哪一个呢?基于...

easonjim
2017/11/08
0
0
使用Spring访问Mongodb的方法大全——Spring Data MongoDB查询指南

1.概述 Spring Data MongoDB 是Spring框架访问mongodb的神器,借助它可以非常方便的读写mongo库。本文介绍使用Spring Data MongoDB来访问mongodb数据库的几种方法: 使用Query和Criteria类 ...

xiaomin0322
2018/06/28
0
0
是大三的我对大二的学弟要求高了吗?

目前我大三,学校四年制,在学校的一个校企合作公司实习。 先说一下我这三年都干了什么,然后再说我遇到的问题吧。 写着写着发现写得太长了,就单独提取出来放到另外一篇文章了:https://www...

侯坤林
2018/04/25
5.6K
46

没有更多内容

加载失败,请刷新页面

加载更多

Java的战争

本文来自微信公众号: 金捷幡(ID:jin-jiefan) ,作者:金捷幡,封面:拉里·埃里森(东方IC) 2019年5月,彻底撕破脸的特朗普掀起对华为的战争,谷歌被迫吊销了华为的Android授权。开源软...

Java领航员
今天
7
0
超详细的LM3414MRX/NOPB规格参数介绍就在这里

超详细的LM3414MRX/NOPB规格参数介绍就在这里 描述 LM3414和LM3414MRX/NOPB是具有1-A 60 W(1)共阳极功能的恒流降压LED驱动器。它们适用于驱动单串3-W HBLED,效率高达96%。它们可接受4.5...

不能吃肉的仙女
今天
3
0
Eclipse国内镜像源配置方法

Table of Contents 我们在国内从官网下载Eclipse以及插件非常慢,那么,有没有方法变快呢? 有,那就是使用国内的公开镜像源替换官方源。 1 下载Eclipse 首先,我们看一个链接地址: http:/...

求神
今天
8
0
java 请求服务

一.第一种基于java web http 请求服务,必须用tomcat 容器启动才能对外提供服务 在maven 工程中pox 文件导入jar <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>h......

zaolonglei
今天
6
0
HDFS工作机制——自开发分布式数据采集系统

需求描述: 在业务系统的服务器上,业务程序会不断生成业务日志(比如网站的页面访问日志) 业务日志是用log4j生成的,会不断地切出日志文件,需要定期(比如每小时)从业务服务器上的日志目...

须臾之余
今天
21
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部