采用spring data jpa动态查询(封装类)

1.利用JPA的Specification接口和元模型就实现动态查询了。但是这样每一个需要动态查询的地方都需要写一个这样类似的findByConditions方法,小型项目还好,大型项目中其实会造成人力资源的浪费,进行了大量的重复工作,所以想着对动态查询进行封装,使其使用起来更加方便。

在开发中,用到动态查询的地方,所有的查询条件包括分页参数,都会被封装成一个查询类XxxQuery,我们封装的思路是创建一个BaseQuery类,在其中实现动态查询的封装,即提供几个模板方法,将查询类的所有属性按照连接规则,拼装成一个Specification型的对象返回,那么问题来了,如何去标识这些字段该用怎样的查询条件连接呢,还要考虑到每个查询类都可以通用,可以用字段注解,来标识字段的查询连接条件。

创建枚举类MatchType,列出所有的连接条件
  package powerx.io;

public enum MatchType {

equal,        // filed = value
//下面四个用于Number类型的比较
gt,   // filed > value
ge,   // field >= value
lt,              // field < value
le,      // field <= value

notEqual,            // field != value
like,   // field like value
notLike,    // field not like value
// 下面四个用于可比较类型(Comparable)的比较
greaterThan,        // field > value
greaterThanOrEqualTo,   // field >= value
lessThan,               // field < value
lessThanOrEqualTo   // field <= value

}

2.自定义注解,用来标识字段
package powerx.io;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
public @interface QueryCondition {

// 数据库中字段名,默认为空字符串,则Query类中的字段要与数据库中字段一致
String column() default "";

// equal, like, gt, lt...
MatchType func() default MatchType.equal;

// object是否可以为null
boolean nullable() default false;

// 字符串是否可为空
boolean emptyable() default false;

}

3.BaseQuery

import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import java.lang.reflect.Field;
import java.util.*;

public abstract class BaseQuery {
private int pageNum = 1;
private int pageSize = 10;

public Pageable toPageable() {
    return PageRequest.of(pageNum - 1, pageSize);
}

public Pageable toPageable(Sort sort) {
    return PageRequest.of(pageNum - 1, pageSize, sort);
}

public Query findPage() {
    return find().with(toPageable());
}

public Query findPage(Pageable pageable) {
    return find().with(pageable);
}

public Query findSort(Sort sort) {
    return find().with(sort);
}

public Query findPageSort(Sort sort) {
    return findPage(toPageable(sort));
}

public Query findPageSort(Pageable pageable, Sort sort) {
    return findPage(pageable).with(sort);
}

public Query find() {
    Class clazz = this.getClass();
    List fields = getAllFieldsWithRoot(clazz);
    Criteria criteria = new Criteria();

    Set setKey = new HashSet<>();
    for (Field field : fields) {
        QueryCondition qw = field.getAnnotation(QueryCondition.class);
        if (qw == null)
            continue;

        String column = qw.column();
        if (column.equals(""))
            column = field.getName();

        field.setAccessible(true);

        try {

            Object value = field.get(this);
            if (value == null && !qw.nullable())
                continue;

            if (value != null && String.class.isAssignableFrom(value.getClass())) {
                String s = (String) value;
                if ("".equals(s) && !qw.emptyable())
                    continue;
            }
            //判断是否重复
            if (!setKey.contains(column)) {
                criteria = criteria.and(column);
                setKey.add(column);
            }
            switch (qw.func()) {
                case eq:
                    criteria.is(value);
                    break;
                case gt:
                    criteria.gt(value);
                    break;
                case lt:
                    criteria.lt(value);
                    break;
                case ge:
                    criteria.gte(value);
                    break;
                case le:
                    criteria.lte(value);
                    break;
                case ne:
                    criteria.ne(value);
                    break;
                case like:
                    criteria.regex("^" + value + "^");
                    break;
                case regex:
                    criteria.regex(qw.regex(), String.valueOf(value));
                    break;
            }
        } catch (Exception e) {
            continue;
        }
    }
    return Query.query(criteria);
}

private List getAllFieldsWithRoot(Class clazz) {
    List fieldList = new ArrayList<>();
    Field[] dFields = clazz.getDeclaredFields();
    if (null != dFields && dFields.length > 0)
        fieldList.addAll(Arrays.asList(dFields));

    Class superClass = clazz.getSuperclass();
    if (superClass == Object.class) return Arrays.asList(dFields);

    List superFields = getAllFieldsWithRoot(superClass);

    if (null != superFields && !superFields.isEmpty()) {
        superFields.stream().
                filter(field -> !fieldList.contains(field)).forEach(field -> fieldList.add(field));
    }
    return fieldList;
}

public int getPageNum() {
    return pageNum;
}

public void setPageNum(int pageNum) {
    this.pageNum = pageNum;
}

public int getPageSize() {
    return pageSize;
}

public void setPageSize(int pageSize) {
    this.pageSize = pageSize;
}

}

4.实体类(使用@QueryCondition注解)
public class UserCoreQueryRequest extends BaseQuery{

@ApiModelProperty("用户id")
@QueryCondition
private Integer user_id;

你可能感兴趣的:(采用spring data jpa动态查询(封装类))