您的位置:首页 > 编程语言 > Java开发

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即可

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: