spring-data-jpa实现vo类的动态添加查询

最近开始使用spring-data-jpa,它对于实体类的基本查询非常方便,vo查询还是需要写sql,动态条件的查询则需要继承JpaSpecificationExecutor来实现,网上例子非常多。这里找到一个封装不错的例子,配置查询条件的注解就可以使用动态条件的查询,原文地址:https://blog.csdn.net/a184838158/article/details/82658757

借鉴了这个例子,可以实现对实体类的动态条件查询,但是实际更多需要查询vo的分页对象,在这个基础上进行了改造。

理解还不深,实现的比较简陋,希望能提出改进意见。

开始

在原文基础上

BaseRepository中添加findAllPage(DataQueryObjectPage param, Class voclass, Class entityClass)方法

@NoRepositoryBean
@Transactional(readOnly=true,rollbackFor = Exception.class)
public interface BaseRepository extends JpaRepository, JpaSpecificationExecutor {
	
//	普通查询
	List findAll(DataQueryObject query);
	
//	分页查询
	Page findAll(DataQueryObject query, Pageable page);

//	分页查询
	Page findAll(DataQueryObjectPage dataQueryObjectpage);

//	排序查询
	List findAll(DataQueryObject dataQueryObject, Sort sort);

//	排序查询
	List findAll(DataQueryObjectSort dataQueryObjectSort);

//      查询分页vo
        Page findAllPage(DataQueryObjectPage param, Class voclass, Class entityClass);
}
public class BaseRepositoryImpl extends SimpleJpaRepository
		implements BaseRepository, JpaSpecificationExecutor {

        //省略原文代码
        ...

        @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 predicates = new ArrayList();
        
        // 获取查询对象的所有属性
 		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 equal = getRootByQueryFiledInvoke(queryFiled, root);
				predicate = cb.equal(equal, value);
				predicates.add(predicate);
				break;
			case BEWTEEN:
				Path 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 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 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 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 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 notEqual = getRootByQueryFiledInvoke(queryFiled, root);
				predicate = cb.notEqual(notEqual, value);
				predicates.add(predicate);
				break;
			case IS_NULL:
				Path isNull = getRootByQueryFiledInvoke(queryFiled, root);
				predicate = cb.isNull(isNull);
				predicates.add(predicate);
				break;
			case IS_NOT_NULL:
				Path isNotNull = getRootByQueryFiledInvoke(queryFiled, root);
				predicate = cb.isNotNull(isNotNull);
				predicates.add(predicate);
				break;
			case LEFT_LIKE:
				Path leftLike = getRootByQueryFiledStringInvoke(queryFiled, root);
				predicate = cb.like(leftLike, "%" + value.toString());
				predicates.add(predicate);
				break;
			case RIGHT_LIKE:
				Path rightLike = getRootByQueryFiledStringInvoke(queryFiled, root);
				predicate = cb.like(rightLike, value.toString() + "%");
				predicates.add(predicate);
				break;
			case FULL_LIKE:
				Path fullLike = getRootByQueryFiledStringInvoke(queryFiled, root);
				predicate = cb.like(fullLike, "%" + value.toString() + "%");
				predicates.add(predicate);
				break;
			case DEFAULT_LIKE:
				Path like = getRootByQueryFiledStringInvoke(queryFiled, root);
				predicate = cb.like(like, value.toString());
				predicates.add(predicate);
				break;
			case NOT_LIKE:
				Path notLike = getRootByQueryFiledStringInvoke(queryFiled, root);
				predicate = cb.like(notLike, value.toString());
				predicates.add(predicate);
				break;
			case IN:
				Path 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 getCountQeury() {
				CriteriaBuilder builder = entityManager.getCriteriaBuilder();
				CriteriaQuery 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. emptyList());

				return entityManager.createQuery(queryCount);
			}
			
			private Long executeCountQuery(TypedQuery query) {

				Assert.notNull(query, "TypedQuery must not be null!");

				List totals = query.getResultList();
				Long total = 0L;

				for (Long element : totals) {
					total += element == null ? 0 : element;
				}

				return total;
			}
		});
	}
	
	private String[] getVOField(Class voclass) {
		List list = new ArrayList();
		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> list = new ArrayList>();
		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 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("."))));
		}
	}

} 
  

改动主要为将传入的实体类型换为不确定的泛型占位,传入vo和po的类型实例化Root对象等,反射获取属性值生成查询对象query.multiselect(getRootSelection(root, getVOField(voclass)));

由于不知道如何构建TotalSupplier对象,只能重写了分页中获取数据总条数的方法。

最后调用,和原方法相同,数据层实现BaseRepository接口,定义好查询对象和vo对象直接调用findAllPage即可

你可能感兴趣的:(学习)