最近开始使用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即可