使用JPA支持多参数列表查询(参数可能为空)
作者:waani
这篇文章主要介绍了使用JPA支持多参数列表查询(参数可能为空),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
JPA支持多参数列表查询(参数可能为空)
1.JPA 支持写SQL语句查询
@Query(value = "select * from xxx ",nativeQuery = true)
2.JPA @Query的SQL语句
可以通过?1、?2
这样获取查询方法里第一个参数、第二个参数,以此类推;或者是使用@Param("name")
标识参数,然后使用 :name
获取。
3.mysql 的if函数,类似三目运算
if(sex=1, '男' , '女')
结合起来可以使用MySQL的if函数,来判断参数是否为空,为空时设置1=1,也就是查所有。
- 第一种方式:
?1
获取参数
@Query(value = "select * from test_demo where if(?1 !='',name=?1,1=1) and if(?2 !='',info=?2,1=1) ",nativeQuery = true) List<TestDemo> find(String name, String info) ;
- 第二种方式:
:name
获取参数
@Query(value = "select * from test_demo where if(:name !='',name= :name,1=1) and if(:info !='',info= :info,1=1) ",nativeQuery = true) List<TestDemo> find2(@Param("name") String name, @Param("info") String info) ;
- 第三种方式:实体类获取参数
@Query(value = "select * from test_demo where if(:#{#testDemo.name} !='',name=:#{#testDemo.name},1=1) and if(:#{#testDemo.info} !='',info=:#{#testDemo.info},1=1) ",nativeQuery = true) List<TestDemo> find3(@Param("testDemo")TestDemo testDemo) ;
这三种写法结果是一样的,主要逻辑就是使用MySQL的if函数,判断某个字段是否不为空,是的话就根据这个字段查询,否则就1=1(为了保证sql语句可以执行)。
同理可以拓展很多,包括模糊查询等,只要MySQL 支持的SQL语句就可以使用JPA来实现,同时JPA特有的分页也可以实现只需要传递Pageable对象并使用Page 接收数据即可。
@Query(value = "select * from test_demo where if(?1 !='',name=?1,1=1) and if(?2 !='',info=?2,1=1) ",nativeQuery = true) Page<TestDemo> find(String name, String info, Pageable pageable) ;
JPA动态查询 支持多字段模糊查询 排序
1、定义条件容器
import org.springframework.data.jpa.domain.Specification; import org.springframework.util.CollectionUtils; import javax.persistence.criteria.*; import java.util.ArrayList; import java.util.List; /** * 定义一个查询条件容器 * Created by gzs */ public class Criteria<T> implements Specification<T> { private List<Criterion> criterions = new ArrayList<>(); private List<Criterion> orderCriterions = new ArrayList<>(); private List<Criterion> groupCriterions = 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) { Predicate predicate = c.toPredicate(root, query, builder); predicates.add(predicate); } // 将所有条件用 and 联合起来 if (predicates.size() > 0) { query.where(predicates.toArray(new Predicate[predicates.size()])); } // 将所有条件用 and 联合起来 /*if (predicates.size() > 0) { return builder.and(predicates.toArray(new Predicate[predicates.size()])); }*/ } //处理排序 if (!orderCriterions.isEmpty()) { List<Order> orders = new ArrayList<>(); for (Criterion c : orderCriterions) { Order order = c.toOrder(root, query, builder); orders.add(order); } if (!CollectionUtils.isEmpty(orders)) { query.orderBy(orders); } } //处理分组 if (!groupCriterions.isEmpty()) { List<Expression> groups = new ArrayList<>(); for (Criterion c : groupCriterions) { Expression group = c.toGroupBy(root, query, builder); groups.add(group); } if (!CollectionUtils.isEmpty(groups)) { Expression[] groupExpressions = (Expression[]) groups.toArray(); query.groupBy(groupExpressions); } } return query.getRestriction(); //return builder.conjunction(); } /** * 增加简单条件表达式 * * @Methods Name add * @Create In 2018-10-15 By gzs */ public void add(Criterion criterion) { if (criterion != null) { criterions.add(criterion); } } /** * 增加排序表达式 * * @Methods Name add * @Create In 2018-11-15 By gzs */ public void addOrder(Criterion order) { if (order != null) { orderCriterions.add(order); } } /** * 增加排序表达式 * * @Methods Name add * @Create In 2018-11-15 By gzs */ public void addGroupBy(Criterion group) { if (group != null) { groupCriterions.add(group); } } }
2、条件表达式
import javax.persistence.criteria.*; /** * 创建条件表达式接口,模拟系统的条件查询 * Created by gzs */ public interface Criterion { enum Operator { EQ, NE, LIKE, GT, LT, GTE, LTE, IS_NULL, IS_NOT_NULL, AND, OR, IS_MEMBER, IS_NOT_MEMBER, DESC, ASC } Predicate toPredicate(Root<?> root, CriteriaQuery<?> query, CriteriaBuilder builder); Order toOrder(Root<?> root, CriteriaQuery<?> query, CriteriaBuilder builder); Expression toGroupBy(Root<?> root, CriteriaQuery<?> query, CriteriaBuilder builder); }
3、实现逻辑条件表达式
import javax.persistence.criteria.*; import java.util.ArrayList; import java.util.List; /** * 逻辑条件表达式 用于复杂条件时使用,如单属性多对应值的OR查询等 * * Created by gzs */ 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++) { Predicate predicate = this.criterion[i].toPredicate(root, query, builder); predicates.add(predicate); } switch (operator) { case OR: return builder.or(predicates.toArray(new Predicate[predicates.size()])); case AND: return builder.and(predicates.toArray(new Predicate[predicates.size()])); default: return null; } } @Override public Order toOrder(Root<?> root, CriteriaQuery<?> query, CriteriaBuilder builder) { return null; } @Override public Expression toGroupBy(Root<?> root, CriteriaQuery<?> query, CriteriaBuilder builder) { return null; } }
4、实现简单条件表达式
import org.springframework.util.StringUtils; import javax.persistence.criteria.*; import java.util.List; import java.util.Map; import java.util.Set; /** * 简单条件表达式 * * Created by gzs */ public class SimpleExpression implements Criterion { /** * 属性名 */ private String fieldName; /** * 对应值 */ private Object value; /** * 计算符 */ private Operator operator; protected SimpleExpression(String fieldName, Operator operator) { this.fieldName = fieldName; this.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_NULL: return builder.isNull(expression); case IS_NOT_NULL: return builder.isNotNull(expression); case IS_MEMBER: return builder.isMember(value, expression); case IS_NOT_MEMBER: return builder.isNotMember(value, expression); default: return null; } } @Override public Order toOrder(Root<?> root, CriteriaQuery<?> query, CriteriaBuilder builder) { return null; } @Override public Expression toGroupBy(Root<?> root, CriteriaQuery<?> query, CriteriaBuilder builder) { return null; } }
5、实现排序表达式
import org.springframework.util.StringUtils; import javax.persistence.criteria.*; import java.util.List; import java.util.Map; import java.util.Set; /** * 逻辑条件表达式 用于复杂条件时使用,如单属性多对应值的OR查询等 * * Created by gzs */ public class OrderExpression implements Criterion { /** * 计算符 */ private Operator operator; /** * 属性名 */ private String fieldName; public OrderExpression(String fieldName, Operator operator) { this.fieldName = fieldName; this.operator = operator; } @Override public Predicate toPredicate(Root<?> root, CriteriaQuery<?> query, CriteriaBuilder builder) { return null; } @Override public Order toOrder(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 DESC: return builder.desc(expression); default: return builder.asc(expression); } } @Override public Expression toGroupBy(Root<?> root, CriteriaQuery<?> query, CriteriaBuilder builder) { return null; } }
6、实现分组表达式 GroupByExpression
import org.springframework.util.StringUtils; import javax.persistence.criteria.*; import java.util.List; import java.util.Map; import java.util.Set; /** * 分组条件表达式 用于复杂条件时使用等 * * Created by gzs */ public class GroupByExpression implements Criterion { /** * 属性名 */ private String fieldName; public GroupByExpression(String fieldName) { this.fieldName = fieldName; } @Override public Predicate toPredicate(Root<?> root, CriteriaQuery<?> query, CriteriaBuilder builder) { return null; } @Override public Order toOrder(Root<?> root, CriteriaQuery<?> query, CriteriaBuilder builder) { return null; } @Override public Expression toGroupBy(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); } return expression; } }
import org.springframework.util.StringUtils; import java.util.Collection; /** * 条件构造器 * 用于创建条件表达式 * * Created by gzs */ 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); } /** * 为null */ public static SimpleExpression isNull(String fieldName) { return new SimpleExpression(fieldName, Criterion.Operator.IS_NULL); } /** * 不为null */ public static SimpleExpression isNotNull(String fieldName) { return new SimpleExpression(fieldName, Criterion.Operator.IS_NOT_NULL); } /** * 集合包含某个元素 */ 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.LTE); } /** * 大于等于 */ public static SimpleExpression gte(String fieldName, Object value, boolean ignoreNull) { if (ignoreNull && StringUtils.isEmpty(value)) { return null; } return new SimpleExpression(fieldName, value, Criterion.Operator.GTE); } /** * 降序 */ public static OrderExpression desc(String fieldName) { /*if (StringUtils.isEmpty(fieldName)) { return null; }*/ return new OrderExpression(fieldName, Criterion.Operator.DESC); } /** * 升序 */ public static OrderExpression asc(String fieldName) { /*if (StringUtils.isEmpty(fieldName)) { return null; }*/ return new OrderExpression(fieldName, Criterion.Operator.ASC); } /** * 并且 */ 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); } /** * 分组 */ public static GroupByExpression groupBy(String fieldName) { if (StringUtils.isEmpty(fieldName)) { return null; } return new GroupByExpression(fieldName); } }
7、见证奇迹的时刻来了demo
if (StringUtils.isNotBlank(teacher.getContactName())) { //动态查询 Criteria<Teacher> criteria = new Criteria<>(); final LogicalExpression or = Restrictions.or( Restrictions.like("code", teacher.getContactName(), true), Restrictions.like("contactName", teacher.getContactName(), true), Restrictions.like("mobile", teacher.getContactName(), true)); criteria.add(or); criteria.add(Restrictions.eq("groupMerchantId", teacher.getGroupMerchantId(), true)); criteria.add(Restrictions.eq("merchantId", teacher.getMerchantId(), true)); criteria.add(Restrictions.eq("campusId", teacher.getCampusId(), true)); criteria.addOrder(Restrictions.desc("gmtModified")); Pageable pageable = new PageRequest(pageNo - 1, pageSize); //页码:前端从1开始,jpa从0开始,做个转换 org.springframework.data.domain.Page<Teacher> cmsUsers = teacherRepository.findAll(criteria, pageable);
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。