JPA使用Specification构建动态查询
封装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构建动态查询的更多相关文章
- 使用Spring Data JPA的Specification构建数据库查询
Spring Data JPA最为优秀的特性就是可以通过自定义方法名称生成查询来轻松创建查询SQL.Spring Data JPA提供了一个Repository编程模型,最简单的方式就是通过扩展Jpa ...
- 基于jpa的specification实现动态查询
spring data jpa为我们实现简单的crud操作提供了极大的方便.但大部分情况下,系统中都存在大量的动态查询操作,这个时候就可以借助spring data jpa的 Specificatio ...
- SpringBoot中使用Spring Data Jpa 实现简单的动态查询的两种方法
软件152 尹以操 首先谢谢大佬的简书文章:http://www.jianshu.com/p/45ad65690e33# 这篇文章中讲的是spring中使用spring data jpa,使用了xml ...
- linq 使用or构建动态查询
You can certainly do it within a Where clause (extension method). If you need to build a complex que ...
- Spring data jpa 实现简单动态查询的通用Specification方法
本篇前提: SpringBoot中使用Spring Data Jpa 实现简单的动态查询的两种方法 这篇文章中的第二种方法 实现Specification 这块的方法 只适用于一个对象针对某一个固定字 ...
- springboot整合spring data jpa 动态查询
Spring Data JPA虽然大大的简化了持久层的开发,但是在实际开发中,很多地方都需要高级动态查询,在实现动态查询时我们需要用到Criteria API,主要是以下三个: 1.Criteria ...
- spring data jpa封装specification实现简单风格的动态查询
github:https://github.com/peterowang/spring-data-jpa-demo 单一实体的动态查询: @Servicepublic class AdvancedUs ...
- spring data jpa Specification动态查询
package com.ytkj.entity; import javax.persistence.*; import java.io.Serializable; /** * @Entity * 作用 ...
- spring data jpa 动态查询(工具类封装)
利用JPA的Specification<T>接口和元模型就实现动态查询了.但是这样每一个需要动态查询的地方都需要写一个这样类似的findByConditions方法,小型项目还好,大型项目 ...
随机推荐
- 干货:Wireshark使用技巧-显示规则
- 显示规则使用 在Wireshark界面对已经抓取的报文在界面的显示进行控制的规则,称为显示规则,显示规则只是让一部分不符合规则的报文不被显示,但未被丢弃,这些报文仍然存在在Wireshark的系统 ...
- 【微信小程序】template模板使用详解
WXML提供模板(template),可以在模板中定义代码片段,然后在不同的地方调用. 模板的作用域: 模板拥有自己的作用域,只能使用 data 传入的数据以及模板定义文件中定义的 <wxs / ...
- STM32 掉电检测程序
当VDD下降到PVD阀值以下或当VDD上升到PVD阀值之上时,根据外部中断第16线的上升/下降边沿触发设置,就会产生PVD中断 void PVD_IRQHandler(void) { led_ctrl ...
- elasticsearch的window的安装和启动
1.下载elasticserch的window和kibana的安装包 2.解压 进入elasticseach的bin目录下elasticsearch.bat 启动页面localhost:9200 3 ...
- [20191011]bash任意进制编码表.txt
[20191011]bash任意进制编码表.txt --//bash可以使用任意进制编码转化为十进制.我想了解内部编码:--//实际上受字符集的限制,"任意"进制有限制的.测试看看 ...
- python pip 升级 或者换源
1. 临时换源python -m pip install --upgrade pip -i https://pypi.douban.com/simple pip国内的一些镜像 阿里云 https ...
- JAVA基础复习(重点)
一. 初识Java编程 1. Java开发环境 JDK Java开发工具 JVM Java虚拟机 JRE Java运行环境 2.实现第一个hello world public cl ...
- git--配置文件、.gitignore
配置文件 git给我们提供了三种配置文件的方法,一种是项目配置文件,一种是全局配置文件,还有一种是系统配置文件. 在我们第一次使用git commit提交代码的时候,git让我们配置用户名和邮箱 全局 ...
- ASP.NET开发实战——(六)ASP.NET MVC & 分层 代码篇
上一篇文章对如何规范使用ASP.NET进行了介绍,本章内容将根据上一篇得出的结论来修改博客应用的代码. 代码分层 综合考虑将博客应用代码分为以下几个层次: ○ 模型:代表应用程序中的数据模型,与数据库 ...
- 爬虫——控制台抓包和requests.post()发送请求
控制台抓包 打开方式及常用选项 1.打开浏览器,F12打开控制台,找到Network选项卡 2.控制台常用选项 1.Network: 抓取网络数据包 1.ALL: 抓取所有的网络数据包 2.XHR:抓 ...