jpa对于固定参数的条件查询比较简单,可以在Repository中直接用参数名来查询。但是对于不固定的参数查询就比较麻烦了,官方提供的是继承JpaSpecificationExecutor,然后自己拼接Specification。这一篇主要是对Specification进行封装,让写法更友好.
代码参考:http://lee1177.iteye.com/blog/1994295。感觉还不够完整,回头使用中再补上。

一:自定义Specification

创建条件表达式接口,模拟系统的条件查询

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;public interface Criterion {enum Operator {EQ, NE, LIKE, GT, LT, GTE, LTE, AND, OR, IS_MEMBER, IS_NOT_MEMBER}Predicate toPredicate(Root<?> root, CriteriaQuery<?> query,CriteriaBuilder builder);
}

创建一个自定义的Sepcification,添加add方法用来添加多个条件

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;/*** Created by 定义一个查询条件容器  on 17/6/6.*/
public class Criteria<T> implements Specification<T> {private List<Criterion> criterions = new ArrayList<>();@Overridepublic Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,CriteriaBuilder builder) {if (!criterions.isEmpty()) {List<Predicate> predicates = new ArrayList<>();for (Criterion c : criterions) {predicates.add(c.toPredicate(root, query, builder));}// 将所有条件用 and 联合起来if (predicates.size() > 0) {return builder.and(predicates.toArray(new Predicate[predicates.size()]));}}return builder.conjunction();}/*** 增加简单条件表达式** @Methods Name add* @Create In 2012-2-8 By lee*/public void add(Criterion criterion) {if (criterion != null) {criterions.add(criterion);}}
}

二:创建条件表达式接口的不同实现类


import org.springframework.util.StringUtils;import javax.persistence.criteria.*;
import java.util.List;
import java.util.Map;
import java.util.Set;/*** 简单条件表达式** @author lee*/
public class SimpleExpression implements Criterion {/***  属性名*/private String fieldName;/***  对应值*/private Object value;/*** 计算符*/private Operator operator;protected SimpleExpression(String fieldName, Object value, Operator operator) {this.fieldName = fieldName;this.value = value;this.operator = operator;}@Override@SuppressWarnings({"rawtypes", "unchecked"})public Predicate toPredicate(Root<?> root, CriteriaQuery<?> query,CriteriaBuilder builder) {Path expression;//此处是表关联数据,注意仅限一层关联,如user.address,//查询user的address集合中,address的name为某个值if (fieldName.contains(".")) {String[] names = StringUtils.split(fieldName, ".");//获取该属性的类型,Set?List?Map?expression = root.get(names[0]);Class clazz = expression.getJavaType();if (clazz.equals(Set.class)) {SetJoin setJoin = root.joinSet(names[0]);expression = setJoin.get(names[1]);} else if (clazz.equals(List.class)) {ListJoin listJoin = root.joinList(names[0]);expression = listJoin.get(names[1]);} else if (clazz.equals(Map.class)) {MapJoin mapJoin = root.joinMap(names[0]);expression = mapJoin.get(names[1]);} else {//是many to one时expression = expression.get(names[1]);}} else {//单表查询expression = root.get(fieldName);}switch (operator) {case EQ:return builder.equal(expression, value);case NE:return builder.notEqual(expression, value);case LIKE:return builder.like((Expression<String>) expression, "%" + value + "%");case LT:return builder.lessThan(expression, (Comparable) value);case GT:return builder.greaterThan(expression, (Comparable) value);case LTE:return builder.lessThanOrEqualTo(expression, (Comparable) value);case GTE:return builder.greaterThanOrEqualTo(expression, (Comparable) value);case IS_MEMBER:return builder.isMember(value, expression);case IS_NOT_MEMBER:return builder.isNotMember(value, expression);default:return null;}}}
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;/*** 逻辑条件表达式 用于复杂条件时使用,如单属性多对应值的OR查询等** @author lee*/
public class LogicalExpression implements Criterion {/*** 逻辑表达式中包含的表达式*/private Criterion[] criterion;/*** 计算符*/private Operator operator;public LogicalExpression(Criterion[] criterions, Operator operator) {this.criterion = criterions;this.operator = operator;}@Overridepublic Predicate toPredicate(Root<?> root, CriteriaQuery<?> query,CriteriaBuilder builder) {List<Predicate> predicates = new ArrayList<>();for (int i = 0; i < this.criterion.length; i++) {predicates.add(this.criterion[i].toPredicate(root, query, builder));}switch (operator) {case OR:return builder.or(predicates.toArray(new Predicate[predicates.size()]));default:return null;}}}

这两个类分别模拟不同的条件查询。

三:创建一个工厂类,根据条件创建不同的实现类


import org.springframework.util.StringUtils;import java.util.Collection;/*** 条件构造器* 用于创建条件表达式** @Class Name Restrictions* @Author lee*/
public class Restrictions {/*** 等于*/public static SimpleExpression eq(String fieldName, Object value, boolean ignoreNull) {if (ignoreNull && StringUtils.isEmpty(value)) {return null;}return new SimpleExpression(fieldName, value, Criterion.Operator.EQ);}/*** 集合包含某个元素*/public static SimpleExpression hasMember(String fieldName, Object value, boolean ignoreNull) {if (ignoreNull && StringUtils.isEmpty(value)) {return null;}return new SimpleExpression(fieldName, value, Criterion.Operator.IS_MEMBER);}/*** 不等于*/public static SimpleExpression ne(String fieldName, Object value, boolean ignoreNull) {if (ignoreNull && StringUtils.isEmpty(value)) {return null;}return new SimpleExpression(fieldName, value, Criterion.Operator.NE);}/*** 模糊匹配*/public static SimpleExpression like(String fieldName, String value, boolean ignoreNull) {if (ignoreNull && StringUtils.isEmpty(value)) {return null;}return new SimpleExpression(fieldName, value, Criterion.Operator.LIKE);}/***/
//    public static SimpleExpression like(String fieldName, String value,
//                                        MatchMode matchMode, boolean ignoreNull) {//        if (StringUtils.isEmpty(value)) return null;
//        return null;
//    }/*** 大于*/public static SimpleExpression gt(String fieldName, Object value, boolean ignoreNull) {if (ignoreNull && StringUtils.isEmpty(value)) {return null;}return new SimpleExpression(fieldName, value, Criterion.Operator.GT);}/*** 小于*/public static SimpleExpression lt(String fieldName, Object value, boolean ignoreNull) {if (ignoreNull && StringUtils.isEmpty(value)) {return null;}return new SimpleExpression(fieldName, value, Criterion.Operator.LT);}/*** 小于等于*/public static SimpleExpression lte(String fieldName, Object value, boolean ignoreNull) {if (ignoreNull && StringUtils.isEmpty(value)) {return null;}return new SimpleExpression(fieldName, value, Criterion.Operator.GTE);}/*** 大于等于*/public static SimpleExpression gte(String fieldName, Object value, boolean ignoreNull) {if (ignoreNull && StringUtils.isEmpty(value)) {return null;}return new SimpleExpression(fieldName, value, Criterion.Operator.LTE);}/*** 并且*/public static LogicalExpression and(Criterion... criterions) {return new LogicalExpression(criterions, Criterion.Operator.AND);}/*** 或者*/public static LogicalExpression or(Criterion... criterions) {return new LogicalExpression(criterions, Criterion.Operator.OR);}/*** 包含于*/@SuppressWarnings("rawtypes")public static LogicalExpression in(String fieldName, Collection value, boolean ignoreNull) {if (ignoreNull && (value == null || value.isEmpty())) {return null;}SimpleExpression[] ses = new SimpleExpression[value.size()];int i = 0;for (Object obj : value) {ses[i] = new SimpleExpression(fieldName, obj, Criterion.Operator.EQ);i++;}return new LogicalExpression(ses, Criterion.Operator.OR);}/*** 集合包含某几个元素,譬如可以查询User类中Set<String> set包含"ABC","bcd"的User集合,* 或者查询User中Set<Address>的Address的name为"北京"的所有User集合* 集合可以为基本类型或者JavaBean,可以是one to many或者是@ElementCollection* @param fieldName* 列名* @param value* 集合* @return* expresssion*/public static LogicalExpression hasMembers(String fieldName, Object... value) {SimpleExpression[] ses = new SimpleExpression[value.length];int i = 0;//集合中对象是基本类型,如Set<Long>,List<String>Criterion.Operator operator = Criterion.Operator.IS_MEMBER;//集合中对象是JavaBeanif (fieldName.contains(".")) {operator = Criterion.Operator.EQ;}for (Object obj : value) {ses[i] = new SimpleExpression(fieldName, obj, operator);i++;}return new LogicalExpression(ses, Criterion.Operator.OR);}
}

四:使用

假设有个Post的entity,有title,content,count,url等参数,再创建一个PostRepository extends JpaRepository

@Testpublic void contextLoads() {Criteria<Post> criteria = new Criteria<>();criteria.add(Restrictions.like("title", "1", true));criteria.add(Restrictions.eq("content", "content1", true));List<Post> postList = postRepository.findAll(criteria);for (Post post : postList) {System.out.println(post);}}

这里就可以比较优雅的创建不同的条件,然后拼接起来查询即可。相比之下要比原生的写法如

studentInfoDao.findAll(new Specification<StudentInfo> () {  public Predicate toPredicate(Root<StudentInfo> root,  CriteriaQuery<?> query, CriteriaBuilder cb) {  Path<String> namePath = root.get("name");  Path<String> nicknamePath = root.get("nickname");  /** * 连接查询条件, 不定参数,可以连接0..N个查询条件 */  query.where(cb.like(namePath, "%李%"), cb.like(nicknamePath, "%王%")); //这里可以设置任意条查询条件  return null;  }  }, page);  }  

比这种写法好看一点。

Springboot中对jpa动态查询条件的封装相关推荐

  1. jpa 动态查询条件 数组_Spring data jpa 复杂动态查询方式总结

    一.Spring data jpa 简介 首先JPA是Java持久层API,由Sun公司开发, 希望整合ORM技术,实现天下归一.  诞生的缘由是为了整合第三方ORM框架,建立一种标准的方式,目前也是 ...

  2. Spring data jpa 动态查询封装

    最近几天学习一下jpa,发现在动态查询方面支持不是很好,一个包含多种动态查询条件的列表需要写大量的代码,而我本身有强迫症,代码有洁癖,大量的重复的代码,自然不爽,于是就.......,废话少说,直接上 ...

  3. 浅析Entity Framework Core2.0的日志记录与动态查询条件

    前言 Entity Framework Core 2.0更新也已经有一段时间了,园子里也有不少的文章.. 本文主要是浅析一下Entity Framework Core2.0的日志记录与动态查询条件 去 ...

  4. linq之InnerJoin和LeftJoin以及封装动态查询条件版本

    Linq的出现,使数据集的处理显得愈来愈简便.很多时候对于本地数据集的处理,脑海中的第一反应,即尝试使用Linq来实现.诸如DataTable的innerJoin以及leftJoin等操作,很多时候我 ...

  5. ibatis动态查询条件

    ibatis的调试相对困难,出错的时候主要依据是log4生成的log文件和出错提示,这方面要能比较熟练的看懂. 下面这个配置基本上包含了最复杂的功能:分页\搜索\排序\缓存\传值Hash表\返回has ...

  6. Vue动态查询条件-Vue动态查询规则-Vue多条件分组组合查询-递归组件(一):前端

    先看最终的效果: 最近项目上有一个需求,VUE前端要实现动态查询条件组件,后端就能够动态组装SQL. 要模仿人家Azure Devops的查询功能,我丢,Azure Devops是人家微软开发的个东西 ...

  7. ibatis动态查询条件(转载待完善)

    ibatis动态查询条件(转载待完善) IBatis 动态查询条件 下面这个配置基本上包含了最复杂的功能:分页\搜索\排序\缓存\传值Hash表\返回hash表\动态sql <statement ...

  8. CGlib、Enhancer、ProxyFactory在springboot中的实现动态代理

    本人博客原地址:CGlib.Enhancer.ProxyFactory在springboot中的实现动态代理 创作时间:2019.06.27 11:38:35 基于springboot2.1.4 在s ...

  9. java中动态查询条件,Java实现动态添加查询条件

    今天遇到一个问题,就是需要根据前端页面发送的条件查询数据库记录,但是前端发送的条件是不确定的.如果使用mybatis的xml方法可以使用if标签灵活的添加判断条件,但是现在我使用的就是单纯的sql. ...

最新文章

  1. KMP算法的实现以及改进
  2. 算法导论之贪心算法(Huffman编码和拟阵)
  3. leetcode word break java,Word Break leetcode java
  4. 电脑已经连上网却显示没网图标小地球,导致国际游戏暴雪等软件无法运行(已解决)
  5. 后端:循环遍历的用法介绍
  6. 前端实现数字快速递增_天正CAD教程之递增文字应用实例
  7. 正则高级用法-分组group+替换
  8. 理解 C++ 的 Memory Order 以及 atomic 与并发程序的关系
  9. 统计测序数据reads数和碱基数的几种方法
  10. 中芯国际:公司客户需求强劲 订单饱满
  11. web渗透测试中WAF绕过讲解(二)基于HTTP协议绕过
  12. php地名转换成拼音,php汉字转拼音_php中怎么将中文转换拼音
  13. 计算机excel求体重指数,excel标准差-制程能力指数(CPK)的定义及计算公式
  14. Python图像灰度化处理
  15. 常用电压电流转换原理图
  16. 向云再出发:如数据般飞驰的内蒙古
  17. 11-用杂志拼接信件(蓝桥杯)
  18. Android 学习资料收集 1
  19. java求几何周长面积_java求几何图形面积
  20. 加强【圣域2】各个技能的打击感-华丽的击飞效果

热门文章

  1. DM368+聚林200W的并口机芯正常出图
  2. Linux:shell编程(shell基本语法)
  3. python列表查找值_查找列表中某个值的位置(python)
  4. 交换机:简述对交换机工作原理的认识
  5. 浅谈技术管理之团队管理
  6. SQLite数据库的下载及安装步骤
  7. 物理内存是什么是计算机的显卡内存吗,物理内存可用数_可用内存和物理内存是什么意思?_可用物理内存...
  8. Windows Server之浅谈SMB以及SMB小案例分享
  9. linux sqlserver有图形化吗,SQL Server for Linux 下一版本的公共预览
  10. Praat将连续录制的声音文件切成小单位文件