封装Specification查询条件,在Spring Data JPA 2.0以前使用 Specifications 这个辅助类来操作where、not、and和or连接,在2.0版本以后这个类会被剔除,可以直接使用 Specification 自身对象来操作where多条件连接。(以下展示单表多条件查询)

import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.domain.Specifications; import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List; /**
* SQL拼接工具类
*
* @author yanhu
* @date 2018/8/9
*/
public class SpecificationFactory { private Specifications specs; private SpecificationFactory(Specification specs) {
this.specs = Specifications.where(specs);
} public static SpecificationFactory wheres(Specification spec) {
return new SpecificationFactory(spec);
} public SpecificationFactory and(Specification other) {
this.specs.and(other);
return this;
} public SpecificationFactory or(Specification other) {
this.specs.or(other);
return this;
} public Specifications build() {
return this.specs;
} /**
* 单where条件
*
* @param p
* @return
*/
public static Specification where(Predication p) {
List<Predication> ps = new ArrayList<>();
ps.add(p);
return where(ps);
} /**
* 多where条件and连接
*
* @param ps
* @param <T>
* @return
*/
public static <T> Specification<T> where(List<Predication> ps) {
return (Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) ->
builder.and(getPredicateList(root, builder, ps));
} /**
* 多where条件or连接
*
* @param ps
* @param <T>
* @return
*/
public static <T> Specification<T> or(List<Predication> ps) {
return (Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) ->
builder.or(getPredicateList(root, builder, ps));
} /**
* 获取查询条件数组
*
* @param root
* @param builder
* @param ps
* @return
*/
private static Predicate[] getPredicateList(Root<?> root, CriteriaBuilder builder, List<Predication> ps) {
List<Predicate> predicateList = new ArrayList<>();
ps.forEach(p -> {
Predicate predicate = buildPredicate(builder, root.get(p.getName()), p);
predicateList.add(predicate);
});
return predicateList.toArray(new Predicate[predicateList.size()]);
} /**
* 选取查询方式
*
* @param cb
* @param path
* @param p
* @return
*/
private static Predicate buildPredicate(CriteriaBuilder cb, Path path, Predication p) {
Predicate predicate;
switch (p.getOperator()) {
case LIKE:
predicate = cb.like(path, p.getValue().toString());
break;
case EQ:
predicate = cb.equal(path, p.getValue());
break;
case NOTEQ:
predicate = cb.notEqual(path, p.getValue());
break;
case GT:
predicate = cb.greaterThan(path, (Comparable) p.getValue());
break;
case GTEQ:
predicate = cb.greaterThanOrEqualTo(path, (Comparable) p.getValue());
break;
case LT:
predicate = cb.lessThan(path, (Comparable) p.getValue());
break;
case LTEQ:
predicate = cb.lessThanOrEqualTo(path, (Comparable) p.getValue());
break;
case NULL:
predicate = cb.isNull(path);
break;
case NOTNULL:
predicate = cb.isNotNull(path);
break;
case IN:
predicate = getIn(path, p.getValue());
break;
case NOTIN:
predicate = getIn(path, p.getValue()).not();
break;
default:
throw new IllegalArgumentException("非法的操作符");
}
return predicate;
} /**
* 创建in操作
*
* @param path
* @param value
* @param <T>
* @return
*/
private static <T> Predicate getIn(Path path, T value) {
if (value instanceof Object[]) {
return path.in((Object[]) value);
} else if (value instanceof Collection) {
return path.in((Collection) value);
} else {
throw new IllegalArgumentException("非法的IN操作");
}
} /***********************************************单where条件查询********************************************************/ // like
public static Specification like(String name, String value) {
return (root, query, cb) ->
cb.like(root.get(name), value);
} // =
public static Specification equal(String name, Object value) {
return (root, query, cb) ->
cb.equal(root.get(name), value);
} // !=
public static Specification notEqual(String name, Object value) {
return (root, query, cb) ->
cb.notEqual(root.get(name), value);
} // >
public static Specification gt(String name, Object value) {
return (root, query, cb) ->
cb.greaterThan(root.get(name), (Comparable) value);
} // >=
public static Specification gtEqual(String name, Object value) {
return (root, query, cb) ->
cb.greaterThanOrEqualTo(root.get(name), (Comparable) value);
} // <
public static Specification lt(String name, Object value) {
return (root, query, cb) ->
cb.lessThan(root.get(name), (Comparable) value);
} // <=
public static Specification ltEqual(String name, Object value) {
return (root, query, cb) ->
cb.lessThanOrEqualTo(root.get(name), (Comparable) value);
} // is null
public static Specification isNull(String name) {
return (root, query, cb) ->
cb.isNull(root.get(name));
} // is not null
public static Specification notNull(String name) {
return (root, query, cb) ->
cb.isNotNull(root.get(name));
} // in
public static Specification in(String name, Object value) {
return (root, query, cb) ->
root.get(name).in(value);
} // not in
public static Specification notIn(String name, Object value) {
return (root, query, cb) ->
root.get(name).in(value).not();
}
}
import lombok.Data;

@Data
public class Predication<T> { private OP operator;
private String name;
private T value; private Predication() {
} public static <T> Predication<T> get(OP operator, String name, T value) {
return new Builder().operator(operator)
.name(name).value(value).build();
} public static class Builder<T> {
private Predication p; public Builder() {
this.p = new Predication();
} public Builder operator(OP op) {
this.p.operator = op;
return this;
} public Builder name(String name) {
this.p.name = name;
return this;
} public Builder value(T value) {
this.p.value = value;
return this;
} public <T> Predication<T> build() {
return this.p;
} }
}
public enum OP {
// like
LIKE,
// =
EQ,
// !=
NOTEQ,
// >
GT,
// >=
GTEQ,
// <
LT,
// <=
LTEQ,
// is null
NULL,
// is not null
NOTNULL,
// in
IN,
// not in
NOTIN, AND, OR, NOT
}

具体使用

        Sort sort = new Sort(Sort.Direction.DESC, "id");
Pageable pageable = new PageRequest(number, size, sort); Specification spec;
/***********************单条件查询*************************/
// 方式1
Predication p = Predication.get(OP.EQ, "name", name);
spec = SpecificationFactory.where(p);
// 方式2
spec = SpecificationFactory.equal("name", name);
/***********************多条件查询*************************/
List<Predication> ps = new ArrayList<>();
ps.add(Predication.get(OP.LIKE, "name", name));
ps.add(Predication.get(OP.EQ, "age", age));
// 全and连接
spec = SpecificationFactory.where(ps);
// 全or连接
spec = SpecificationFactory.or(ps);
// and和or混合连接 // where name like ?1 and age = ?2
// and name like ?3 and age = ?4
// or name like ?5 or age = ?6
// 工具类实现
spec = SpecificationFactory.wheres(SpecificationFactory.where(ps))
.and(SpecificationFactory.where(ps))
.or(SpecificationFactory.or(ps))
.build();
// JPA API辅助类实现
spec = Specifications.where(SpecificationFactory.where(ps))
.and(SpecificationFactory.where(ps))
.or(SpecificationFactory.where(ps)); // where name like ?1 and age = ?2
// and ( name like ?3 or age = ?4 )
// 工具类实现
spec = SpecificationFactory.wheres(SpecificationFactory.where(ps))
.and(SpecificationFactory.or(ps))
.build();
// JPA API辅助类实现
spec = Specifications.where(SpecificationFactory.where(ps))
.and(SpecificationFactory.or(ps)); Page<ConsultChat> chatPage = consultChatDao.findAll(spec, pageable);

JPA使用Specification构建动态查询的更多相关文章

  1. 使用Spring Data JPA的Specification构建数据库查询

    Spring Data JPA最为优秀的特性就是可以通过自定义方法名称生成查询来轻松创建查询SQL.Spring Data JPA提供了一个Repository编程模型,最简单的方式就是通过扩展Jpa ...

  2. 基于jpa的specification实现动态查询

    spring data jpa为我们实现简单的crud操作提供了极大的方便.但大部分情况下,系统中都存在大量的动态查询操作,这个时候就可以借助spring data jpa的 Specificatio ...

  3. SpringBoot中使用Spring Data Jpa 实现简单的动态查询的两种方法

    软件152 尹以操 首先谢谢大佬的简书文章:http://www.jianshu.com/p/45ad65690e33# 这篇文章中讲的是spring中使用spring data jpa,使用了xml ...

  4. linq 使用or构建动态查询

    You can certainly do it within a Where clause (extension method). If you need to build a complex que ...

  5. Spring data jpa 实现简单动态查询的通用Specification方法

    本篇前提: SpringBoot中使用Spring Data Jpa 实现简单的动态查询的两种方法 这篇文章中的第二种方法 实现Specification 这块的方法 只适用于一个对象针对某一个固定字 ...

  6. springboot整合spring data jpa 动态查询

    Spring Data JPA虽然大大的简化了持久层的开发,但是在实际开发中,很多地方都需要高级动态查询,在实现动态查询时我们需要用到Criteria API,主要是以下三个: 1.Criteria ...

  7. spring data jpa封装specification实现简单风格的动态查询

    github:https://github.com/peterowang/spring-data-jpa-demo 单一实体的动态查询: @Servicepublic class AdvancedUs ...

  8. spring data jpa Specification动态查询

    package com.ytkj.entity; import javax.persistence.*; import java.io.Serializable; /** * @Entity * 作用 ...

  9. spring data jpa 动态查询(工具类封装)

    利用JPA的Specification<T>接口和元模型就实现动态查询了.但是这样每一个需要动态查询的地方都需要写一个这样类似的findByConditions方法,小型项目还好,大型项目 ...

随机推荐

  1. 企业账号发布APP

    做了一个公司内部人使用的项目,公司申请了企业开发者账号.现将企业开发者账号发布app的过成总结如下: 1.生成Certificate Signing Request (CSR)文件 2.2 请求Cer ...

  2. Python 字符串用法总结

    一.将某个对象转换为字符串,有str()和repr()两种方法 区别:repr() 转化为供解释器读取的形式str() 转化为适于人阅读的形式 a = 123456 print('repr输出:', ...

  3. [日常] Redis中set集合的使用思考

    公司部门同事有个需求,就是需要把当前另一个部门a中存储的数据全部导出来,自己当前业务b的数据全部导出来,两个要取一下差集,把a中存在,b中不存在的记下来,要去调用某接口把对应的文件删除.这个我感觉可以 ...

  4. 爬虫---lxml简单操作

    前几篇写了一些Beautiful Soup的一些简单操作,也拿出来了一些实例进行实践,今天引入一个新的python库lxmt,lxmt也可以完成数据的爬取哦 什么是lxml lxml是python的一 ...

  5. RAID10(5块硬盘)的简介和创建

    一.        RAID10简介 (1)兼具速度和安全性,但成本很高. (2)继承了RAID0的快速与RAID1的安全,RAID1在这里提供了冗余备份的阵列,而RAID0则负责数据的读写阵列.因这 ...

  6. centos7下安装配置prometheus

    prometheus官网:https://prometheus.io/download/ 搭建环境参考:https://blog.csdn.net/baidu_36943075/article/det ...

  7. C++ int 和string互相转化

    1.int转换成string );//"-12" );//"12" +);//"1" 2.string转换成int );//"-1 ...

  8. C++ class内的 ++ 重载,左++,右++,重载示例。

    #include <iostream> // overloading "operator ++ " inside class // ++ 是一元操作符 //////// ...

  9. python将xml文件数据增强(labelimg)

    在处理faster-rcnn和yolo时笔者使用labelimg标注图片 但是我们只截取了大概800张左右的图,这个量级在训练时肯定是不够的,所以我们需要使用数据增强(无非是旋转加噪调量度)来增加我们 ...

  10. Mybatis的Java API(八)

    使用mybatis的主要Java接口就是SqlSession.可以通过这个接口来执行命令,获取映射器和事务管理. SqlSession是由SqlSessionFactory实例创建,SqlSessio ...