Springboot中对jpa动态查询条件的封装
来源:互联网 发布:淘宝商品网页无法显示 编辑:程序博客网 时间:2024/06/05 22:36
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<>(); @Override public 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; } @Override public 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; //集合中对象是JavaBean if (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
@Test public 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); }
比这种写法好看一点。
阅读全文
0 0
- Springboot中对jpa动态查询条件的封装
- Springboot整合JPA以及动态条件查询的实现
- spring data jpa的动态查询封装
- springBoot JPA 查询中出现的问题
- SpringBoot中使用Spring Data Jpa 实现简单的动态查询的两种方法
- JPA动态查询代码封装
- Srping Data Jpa条件查询封装
- 基于SpringBoot的Jpa查询
- Spring data jpa 多表查询(三:多对多关系动态条件查询)
- SpringData JPA 实现动态条件查询
- spring jpa动态条件查询并分页
- spring data jpa动态条件查询
- SpringBoot JPA 条件分页
- 【mysql】nodejs 下对 mysql 查询条件的一个封装
- Mybatis中查询条件和返回的结果Map封装
- spring JPA中对自定义实体的查询经验
- hibernate(jpa)根据实体动态生成查询条件,并实现分页问题的解决方案
- springboot+jpa+jqueryeasyui重新封装
- 下载Spring源文件方法
- mysql group by作用
- LinkedHashMap和HashMap的比较使用
- 微信公众号三方平台开发【component_verify_ticket篇】
- fiddler抓包时出现了tunnel to ......443
- Springboot中对jpa动态查询条件的封装
- 同样是webkit内核为什么chrome和safari兼容性会不一样?
- 进程和线程的区别
- nrf51822-添加DFU服务
- Java中List去重处理
- SVN安装与使用教程总结
- Java三种移位运算符
- HTML页面 button 标签 刷新页面问题
- CSDN不再维护