封装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. 网络流(2)——用Ford-Fullkerson算法寻找最大流

    寻找最大流 在大规模战争中,后勤补给是重中之重,为了尽最大可能满足前线的物资消耗,后勤部队必然要充分利用每条运输网,这正好可以用最大流模型解决.如何寻找一个复杂网络上的最大流呢? 直觉上的方案 一种直 ...

  2. easyui三

    陈旧的开发模式 美工(ui工程师:出一个项目模型) java工程师:将原有的html转成jsp,动态展示数据 缺点: 客户需要调节前端的展示效果 解决:由美工去重新排版,重新选色.Vs前后端分离 美工 ...

  3. Tomcat 学习总结(1) --Servlet技术

    在Web应用中,Servlet是一门重要的技术,Servlet是利用Java类编写的服务端程序,与平台架构,协议无关. JSP的实质就是Servlet,因为所有的JSP页面传回服务端时要转为Servl ...

  4. socket 与 websocket的区别

    区别: socket并不是一个协议,而是抽象出来的一层,应用于应用层和传输控制层之间的一组接口, socket是传输控制层协议,websocket是应用层协议 websocket是什么样的协议,具有什 ...

  5. else if 使用注意

    写出一个程序,接受一个有字母和数字以及空格组成的字符串,和一个字符,然后输出输入字符串中含有该字符的个数.不区分大小写. 例如:输入:ABCDE A 输出:1 错误代码如下: #include < ...

  6. Pwn-level1

    题目地址 https://dn.jarvisoj.com/challengefiles/level1.80eacdcd51aca92af7749d96efad7fb5 先看一下文件的类型和保护机制   ...

  7. python 2.7 操作mysql数据库 实例

    create table msg(id int primary key auto_increment,title varchar(20),name varchar(60),content varcha ...

  8. 用背包问题思路解决 322. Coin Change(完全背包)

    首先需要明白 0-1 背包问题中的放置表格,见 “玩转算法面试 从真题到思维全面提升算法思维” 9-5 节,本题思路类似表格纵向为:只考虑第 [0 …,… index] 种硬币(物品)表格横向为:需要 ...

  9. ora-01489 字符串连接的结果过长 解决方案

    如下代码,使用listagg进行分组拼接时,常常会报 ora-01489 错误,造成该报错的主要原因是:oracle对字符变量的长度限制,正常情况下,oracle定义的varchar2类型变量的长度不 ...

  10. 【声明式事务】Spring事务介绍(一)

    事务管理对于企业应用来说是至关重要的,当出现异常情况时,它也可以保证数据的一致性. Spring事务有两种管理方式:编程式事务和声明式事务 编程式事务使用TransactionTemplate或者直接 ...