spring-data-jpa实现vo类的动态添加查询
2019-03-14 16:08
1546 查看
最近开始使用spring-data-jpa,它对于实体类的基本查询非常方便,vo查询还是需要写sql,动态条件的查询则需要继承JpaSpecificationExecutor<T>来实现,网上例子非常多。这里找到一个封装不错的例子,配置查询条件的注解就可以使用动态条件的查询,原文地址:https://blog.csdn.net/a184838158/article/details/82658757
借鉴了这个例子,可以实现对实体类的动态条件查询,但是实际更多需要查询vo的分页对象,在这个基础上进行了改造。
理解还不深,实现的比较简陋,希望能提出改进意见。
开始
在原文基础上
BaseRepository中添加findAllPage(DataQueryObjectPage param, Class<?> voclass, Class<?> entityClass)方法
[code]@NoRepositoryBean @Transactional(readOnly=true,rollbackFor = Exception.class) public interface BaseRepository<T,ID extends Serializable> extends JpaRepository<T,ID>, JpaSpecificationExecutor<T> { // 普通查询 List<T> findAll(DataQueryObject query); // 分页查询 Page<T> findAll(DataQueryObject query, Pageable page); // 分页查询 Page<T> findAll(DataQueryObjectPage dataQueryObjectpage); // 排序查询 List<T> findAll(DataQueryObject dataQueryObject, Sort sort); // 排序查询 List<T> findAll(DataQueryObjectSort dataQueryObjectSort); // 查询分页vo Page<?> findAllPage(DataQueryObjectPage param, Class<?> voclass, Class<?> entityClass); }
[code]public class BaseRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements BaseRepository<T, ID>, JpaSpecificationExecutor<T> { //省略原文代码 ... @Override public Page<?> findAllPage(DataQueryObjectPage param, Class<?> voclass, Class<?> entityClass){ CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<?> query = cb.createQuery(voclass); final Root<?> root = query.from(entityClass); //拼接where条件 List<Predicate> predicates = new ArrayList<Predicate>(); // 获取查询对象的所有属性 Field[] fields = param.getClass().getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); String queryFiled = null; QueryType queryType = null; Object value = null; Predicate predicate = null; // 获取属性的 自定义注解类型 QueryField annotaion = field.getAnnotation(QueryField.class); // 如果没有注解 则跳过 if (annotaion == null) { continue; } // 如果注解中 name为空 则用字段名称作为属性名 if (!StringUtils.isEmpty(annotaion.name())) { queryFiled = annotaion.name(); } else { queryFiled = field.getName(); } queryType = annotaion.type(); try { value = field.get(param); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } // 判断字段类型是否为空 if (value == null && queryType.isNotCanBeNull()) { //TODO // logger.debug("查询类型:" + queryType + "不允许为空。"); continue; } // 判断注解中 的条件类型 switch (queryType) { case EQUAL: Path<Object> equal = getRootByQueryFiledInvoke(queryFiled, root); predicate = cb.equal(equal, value); predicates.add(predicate); break; case BEWTEEN: Path<Comparable> between = getRootByQueryFiledComparableInvoke(queryFiled, root); QueryBetween queryBetween = null; if (value instanceof QueryBetween) queryBetween = (QueryBetween) value; else continue; predicate = cb.between(between, queryBetween.after, queryBetween.before); predicates.add(predicate); break; case LESS_THAN: Path<Comparable> lessThan = getRootByQueryFiledComparableInvoke(queryFiled, root); if (value instanceof QueryBetween) queryBetween = (QueryBetween) value; else continue; predicate = cb.lessThan(lessThan, queryBetween.after); predicates.add(predicate); break; case LESS_THAN_EQUAL: Path<Comparable> lessThanOrEqualTo = getRootByQueryFiledComparableInvoke(queryFiled, root); if (value instanceof QueryBetween) queryBetween = (QueryBetween) value; else continue; predicate = cb.lessThanOrEqualTo(lessThanOrEqualTo, queryBetween.after); predicates.add(predicate); break; case GREATEROR_THAN: Path<Comparable> greaterThan = getRootByQueryFiledComparableInvoke(queryFiled, root); if (value instanceof QueryBetween) queryBetween = (QueryBetween) value; else continue; predicate = cb.greaterThan(greaterThan, queryBetween.after); predicates.add(predicate); break; case GREATEROR_THAN_EQUAL: Path<Comparable> greaterThanOrEqualTo = getRootByQueryFiledComparableInvoke(queryFiled, root); if (value instanceof QueryBetween) queryBetween = (QueryBetween) value; else continue; predicate = cb.lessThanOrEqualTo(greaterThanOrEqualTo, queryBetween.after); predicates.add(predicate); break; case NOT_EQUAL: Path<Object> notEqual = getRootByQueryFiledInvoke(queryFiled, root); predicate = cb.notEqual(notEqual, value); predicates.add(predicate); break; case IS_NULL: Path<Object> isNull = getRootByQueryFiledInvoke(queryFiled, root); predicate = cb.isNull(isNull); predicates.add(predicate); break; case IS_NOT_NULL: Path<Object> isNotNull = getRootByQueryFiledInvoke(queryFiled, root); predicate = cb.isNotNull(isNotNull); predicates.add(predicate); break; case LEFT_LIKE: Path<String> leftLike = getRootByQueryFiledStringInvoke(queryFiled, root); predicate = cb.like(leftLike, "%" + value.toString()); predicates.add(predicate); break; case RIGHT_LIKE: Path<String> rightLike = getRootByQueryFiledStringInvoke(queryFiled, root); predicate = cb.like(rightLike, value.toString() + "%"); predicates.add(predicate); break; case FULL_LIKE: Path<String> fullLike = getRootByQueryFiledStringInvoke(queryFiled, root); predicate = cb.like(fullLike, "%" + value.toString() + "%"); predicates.add(predicate); break; case DEFAULT_LIKE: Path<String> like = getRootByQueryFiledStringInvoke(queryFiled, root); predicate = cb.like(like, value.toString()); predicates.add(predicate); break; case NOT_LIKE: Path<String> notLike = getRootByQueryFiledStringInvoke(queryFiled, root); predicate = cb.like(notLike, value.toString()); predicates.add(predicate); break; case IN: Path<Object> in = getRootByQueryFiledInvoke(queryFiled, root); In ins = cb.in(in); List inList = null; if (value instanceof List) { inList = (List) value; } for (Object object : inList) { ins.value(object); } predicates.add(ins); break; default: break; } } Predicate[] predicate = new Predicate[predicates.size()]; predicate = predicates.toArray(predicate); final Predicate[] pCount = predicate; //加上where条件 query.where(predicate); query.multiselect(getRootSelection(root, getVOField(voclass))); Pageable pageable = new PageRequest(param.getPage(), param.getSize()); TypedQuery<?> q = entityManager.createQuery(query); q.setFirstResult(pageable.getOffset()); q.setMaxResults(pageable.getPageSize()); return PageableExecutionUtils.getPage(q.getResultList(), pageable, new TotalSupplier() { @Override public long get() { return executeCountQuery(getCountQeury()); } private TypedQuery<Long> getCountQeury() { CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<Long> queryCount = builder.createQuery(Long.class); queryCount.where(pCount); if (queryCount.isDistinct()) { queryCount.select(builder.countDistinct(root)); } else { queryCount.select(builder.count(root)); } // Remove all Orders the Specifications might have applied queryCount.orderBy(Collections.<javax.persistence.criteria.Order> emptyList()); return entityManager.createQuery(queryCount); } private Long executeCountQuery(TypedQuery<Long> query) { Assert.notNull(query, "TypedQuery must not be null!"); List<Long> totals = query.getResultList(); Long total = 0L; for (Long element : totals) { total += element == null ? 0 : element; } return total; } }); } private String[] getVOField(Class<?> voclass) { List<String> list = new ArrayList<String>(); Field[] field = voclass.getDeclaredFields(); for (int i = 0; i < field.length; i++) { QueryField annotaion = field[i].getAnnotation(QueryField.class); //注解或者注解name为空则取属性名,存在则取注解name中字段名 list.add(annotaion==null||StringUtils.isEmpty(annotaion.name())?field[i].getName():annotaion.name()); } return list.toArray(new String[list.size()]); } private Selection<?>[] getRootSelection(Root<?> root,String[] path){ List<Selection<?>> list = new ArrayList<Selection<?>>(); for (int i = 0; i < path.length; i++) { if(StringUtils.isNotEmpty(path[i])) { list.add(root.get(path[i])); } } return list.toArray(new Selection<?>[list.size()]); } private Path<Object> getRootByQueryFiledInvoke(String queryFiled, Root<?> root) { if (queryFiled.indexOf(".") < 0) { return root.get(queryFiled); } else { return getRootByQueryFiled(queryFiled.substring(queryFiled.indexOf(".") + 1, queryFiled.length()), root.get(queryFiled.substring(0, queryFiled.indexOf(".")))); } } }
改动主要为将传入的<T>实体类型换为不确定的泛型占位,传入vo和po的类型实例化Root对象等,反射获取属性值生成查询对象query.multiselect(getRootSelection(root, getVOField(voclass)));
由于不知道如何构建TotalSupplier对象,只能重写了分页中获取数据总条数的方法。
最后调用,和原方法相同,数据层实现BaseRepository接口,定义好查询对象和vo对象直接调用findAllPage即可
相关文章推荐
- Spring Data JPA实现动态条件与范围查询实例代码
- SpringData JPA 实现动态条件查询
- SpringBoot中使用Spring Data Jpa 实现简单的动态查询的两种方法
- SpringBoot中使用Spring Data Jpa 实现简单的动态查询的两种方法
- Spring data JPA使用Specification实现动态查询例子
- JAVA编程132——springdata JPA使用Example快速实现动态查询
- Spring data jpa 实现简单动态查询的通用Specification方法
- springdata jpa使用Example快速实现动态查询
- springdata jpa使用Example快速实现动态查询
- 【spring data jpa】带有条件的查询后分页和不带条件查询后分页实现
- (spring boot)spring data JPA 高级动态查询, 排序加分页加多参数查询 返回二元组
- Spring Data JPA可以通过Specification进行动态查询
- Spring Data Jpa 查询操作的基本实现(Spring Data Jpa 2)
- Spring Data JPA中的动态查询
- Spring Data JPA 动态查询
- Spring data JPA中使用Specifications动态构建查询
- Spring Data JPA中的动态查询
- Spring Data Jpa 配合MongoDB实现持久层对象属性动态增加
- 在Spring Boot中使用Spring-data-jpa实现分页查询(转)
- 【spring data jpa】带有条件的查询后分页和不带条件查询后分页实现