如何优雅的使用Jpa的JpaSpecificationExecutor提供的复杂查询,实现Specification对象的简单操作

首先看一个查询的列子,输入一个名称,模糊匹配username或者nickName

return adminJpa.findAll(
                adminJpa.support().like("username",name).or(support -> support.like("nickName",name)),
                PageRequest.of(pageNum - 1,pageSize)
        );

以上代码所打印的sql

Hibernate: select * from table table0_ where table0_.nick_name like ? or table0_.username like ? limit ?

相信你直接看都能看得懂以上代码所代表的是什么意思,那么这种操作是怎么实现的呢?

可以看到,我们只用了三四行的代码,就实现了原本需要十几行,并且可读性极差的代码所实现的功能

代码块

首先,我们先自定义一个BaseJpa,将原先继承JpaRepository的接口改成此接口,看以下代码,这里最主要的功能由JpaRepository提供,复杂查询由JpaSpecificationExecutor提供

 ps:修复了升级springboot 2.2.0错误

/**
 * @author hexm
 * @date 2019/8/20 10:54
 */
@NoRepositoryBean
public interface BaseJpa extends JpaRepository, JpaSpecificationExecutor {

    /**
     * 批量删除
     * @param ids
     * @return
     */
    int deleteByIdIn(Collection ids);

    /**
     * 提供默认复杂查询支持
     * @return
     */
    default SpecificationSupport support(){
        return SpecificationSupport.of();
    }
}

我们需要做的就是提供一个Specification的实现,这个实现是JpaSpecificationExecutor接口所要求的参数对象,对此我们做了一层简单的封装,以达到平常需要用到的条件查询,如果你找不到你要的方法,可以在原有的基础上进行添加,相信这一定很简单!下面提供Specification实现

ps:由于业务的升级,提供新的支持函数的查询方式

所以查询方式看起来有可能是这样子的?

如何优雅的使用Jpa的JpaSpecificationExecutor提供的复杂查询,实现Specification对象的简单操作_第1张图片

下面还是工具类:

import org.hibernate.query.criteria.internal.CriteriaBuilderImpl;
import org.hibernate.query.criteria.internal.expression.function.BasicFunctionExpression;
import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.*;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigInteger;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.IntFunction;

/**
 * Jpa复杂查询支持
 *
 * @author hexm
 * @date 2019/8/19 15:25
 */
public class SpecificationSupport implements Specification {

    /**
     * 额外添加的or或者and条件
     */
    private Map> AND_OR = new LinkedHashMap<>();

    /**
     * 里面都是and条件
     */
    private List condition = new ArrayList<>();

    /**
     * 被忽略的属性
     */
    private List ignoreColumn = new ArrayList<>();

    /**
     * 忽略大小写
     */
    private List ignoreCase = new ArrayList<>();

    /**构造时的对象*/
    private T t;

    /**
     * 忽略空字符串
     */
    private boolean ignoreNullString = true;

    private SpecificationSupport() {
    }

    /**
     * 得到一个查询构造器
     *
     * @param probe
     * @param 
     * @param 
     * @return
     */
    public static  SpecificationSupport of(K probe) {
        SpecificationSupport s = new SpecificationSupport<>();
        s.t = probe;
        return s;
    }

    /**
     * 得到一个查询构造器
     *
     * @param 
     * @return
     */
    public static  SpecificationSupport of(Class clazz) {
        return new SpecificationSupport<>();
    }

    /**
     * 得到一个查询构造器
     *
     * @param 
     * @return
     */
    public static  SpecificationSupport of() {
        return new SpecificationSupport<>();
    }

    /**
     * 前匹配 like %column
     *
     * @param column
     * @return
     */
    public SpecificationSupport startsLike(String column) {
        addCondition(column, OptionType.STARTS_LIKE);
        return this;
    }

    /**
     * 后匹配 like column%
     *
     * @param column
     * @return
     */
    public SpecificationSupport endLike(String column) {
        addCondition(column, OptionType.END_LIKE);
        return this;
    }

    /**
     * 匹配 like %column%
     *
     * @param column
     * @return
     */
    public SpecificationSupport like(String column) {
        addCondition(column, OptionType.LIKE);
        return this;
    }

    /**
     * 匹配 = column
     *
     * @param column
     * @return
     */
    public SpecificationSupport eq(String column) {
        addCondition(column, OptionType.EQ);
        return this;
    }

    /**
     * 匹配 != column
     *
     * @param column
     * @return
     */
    public SpecificationSupport neq(String column) {
        addCondition(column, OptionType.NOT_EQ);
        return this;
    }

    /**
     * 匹配 not like %column
     *
     * @param column
     * @return
     */
    public SpecificationSupport notStartLike(String column) {
        addCondition(column, OptionType.NOT_STARTS_LIKE);
        return this;
    }

    /**
     * 匹配 not like column%
     *
     * @param column
     * @return
     */
    public SpecificationSupport notEndLike(String column) {
        addCondition(column, OptionType.NOT_END_LIKE);
        return this;
    }

    /**
     * 匹配 not like %column%
     *
     * @param column
     * @return
     */
    public SpecificationSupport notLike(String column) {
        addCondition(column, OptionType.NOT_LIKE);
        return this;
    }

    /**
     * 匹配 > column
     *
     * @param column 字段属性必须为数字类型,或字符串的数字
     * @return
     */
    public SpecificationSupport gt(String column) {
        addCondition(column, OptionType.GT);
        return this;
    }

    /**
     * 匹配 >= column
     *
     * @param column 字段属性必须为数字类型,或字符串的数字
     * @return
     */
    public SpecificationSupport ge(String column) {
        addCondition(column, OptionType.GE);
        return this;
    }

    /**
     * 匹配 < column
     *
     * @param column 字段属性必须为数字类型,或字符串的数字
     * @return
     */
    public SpecificationSupport lt(String column) {
        addCondition(column, OptionType.LT);
        return this;
    }

    /**
     * 匹配 <= column
     *
     * @param column 字段属性必须为数字类型,或字符串的数字
     * @return
     */
    public SpecificationSupport le(String column) {
        addCondition(column, OptionType.LE);
        return this;
    }


    /**
     * 前匹配 like %column
     *
     * @param column
     * @return
     */
    public SpecificationSupport startsLike(String column, String value) {
        addCondition(column, OptionType.STARTS_LIKE, value);
        return this;
    }

    /**
     * 后匹配 like column%
     *
     * @param column
     * @return
     */
    public SpecificationSupport endLike(String column, String value) {
        addCondition(column, OptionType.END_LIKE, value);
        return this;
    }

    /**
     * 匹配 like %column%
     *
     * @param column
     * @return
     */
    public SpecificationSupport like(String column, String value) {
        addCondition(column, OptionType.LIKE, value);
        return this;
    }

    /**
     * 匹配 = column
     *
     * @param column
     * @return
     */
    public SpecificationSupport eq(String column, Object value) {
        addCondition(column, OptionType.EQ, value);
        return this;
    }

    /**
     * 匹配 != column
     *
     * @param column
     * @return
     */
    public SpecificationSupport neq(String column, Object value) {
        addCondition(column, OptionType.NOT_EQ, value);
        return this;
    }

    /**
     * 匹配 not like %column
     *
     * @param column
     * @return
     */
    public SpecificationSupport notStartLike(String column, String value) {
        addCondition(column, OptionType.NOT_STARTS_LIKE, value);
        return this;
    }

    /**
     * 匹配 not like column%
     *
     * @param column
     * @return
     */
    public SpecificationSupport notEndLike(String column, String value) {
        addCondition(column, OptionType.NOT_END_LIKE, value);
        return this;
    }

    /**
     * 匹配 not like %column%
     *
     * @param column
     * @return
     */
    public SpecificationSupport notLike(String column, String value) {
        addCondition(column, OptionType.NOT_LIKE, value);
        return this;
    }

    /**
     * 匹配 > column
     *
     * @param column 字段属性必须为数字类型
     * @return
     */
    public SpecificationSupport gt(String column, Number value) {
        addCondition(column, OptionType.GT, value);
        return this;
    }

    /**
     * 匹配 >= column
     *
     * @param column 字段属性必须为数字类型
     * @return
     */
    public SpecificationSupport ge(String column, Number value) {
        addCondition(column, OptionType.GE, value);
        return this;
    }

    /**
     * 匹配 < column
     *
     * @param column 字段属性必须为数字类型
     * @return
     */
    public SpecificationSupport lt(String column, Number value) {
        addCondition(column, OptionType.LT, value);
        return this;
    }

    /**
     * 匹配 <= column
     *
     * @param column 字段属性必须为数字类型
     * @return
     */
    public SpecificationSupport le(String column, Number value) {
        addCondition(column, OptionType.LE, value);
        return this;
    }

    /**
     * 匹配 between column1 and column2
     *
     * @param column 字段
     * @param value1 继承了比较接口的对象
     * @param value2 继承了比较接口的对象
     * @return
     */
    public SpecificationSupport between(String column, Comparable value1, Comparable value2) {
        addCondition(column, OptionType.BETWEEN, value1, value2);
        return this;
    }

    /**
     * 匹配 in (column)
     *
     * @param column 字段
     * @param value  多个比较值
     * @return
     */
    public SpecificationSupport in(String column, Object... value) {
        addCondition(column, OptionType.IN, value);
        return this;
    }

    /**
     * 匹配 column is null
     *
     * @param column 字段
     * @return
     */
    public SpecificationSupport isNull(String column) {
        addConditionEmptyValue(column, OptionType.IS_NULL);
        return this;
    }

    /**
     * 匹配 column is not null
     *
     * @param column 字段
     * @return
     */
    public SpecificationSupport isNotNull(String column) {
        addConditionEmptyValue(column, OptionType.IS_NOT_NULL);
        return this;
    }

    /**
     * 匹配 column == true
     *
     * @param column 字段
     * @return
     */
    public SpecificationSupport isTrue(String column) {
        addConditionEmptyValue(column, OptionType.TRUE);
        return this;
    }

    /**
     * 匹配 column == false
     *
     * @param column 字段
     * @return
     */
    public SpecificationSupport isFalse(String column) {
        addConditionEmptyValue(column, OptionType.FALSE);
        return this;
    }

    /**
     * 匹配 date_format(column,'format') ?= value
     * 注:由于指定方法名为:date_format只适用于mysql,如果使用oracle需要改为to_char
     * @param column 匹配字段
     * @param value  匹配值
     * @param format 匹配格式
     * @return
     */
    public SpecificationSupport dateFormat(String column, Object value, String format, OptionType optionType) {
        Map argTypeMap = new HashMap<>();
        argTypeMap.put(column, ArgType.ROOT);   //第一个参数读取字段
        argTypeMap.put(format, ArgType.STRING); //第二个参数字符串类型
        function("date_format", new String[]{column, format}, argTypeMap, optionType, false, value);
        return this;
    }

    /**
     * 匹配 date_format(column,'format') = value
     *
     * @param column 匹配字段
     * @param value  匹配值
     * @param format 匹配格式
     * @return
     */
    public SpecificationSupport dateEq(String column, Object value, String format) {
        dateFormat(column, value, format, OptionType.EQ);
        return this;
    }

    /**
     * 匹配 date_format(column,'format') >= value
     *
     * @param column 匹配字段
     * @param value  匹配值
     * @param format 匹配格式
     * @return
     */
    public SpecificationSupport dateGe(String column, Object value, String format) {
        dateFormat(column, value, format, OptionType.GE);
        return this;
    }

    /**
     * 匹配 date_format(column,'format') <= value
     *
     * @param column 匹配字段
     * @param value  匹配值
     * @param format 匹配格式
     * @return
     */
    public SpecificationSupport dateLe(String column, Object value, String format) {
        dateFormat(column, value, format, OptionType.LE);
        return this;
    }

    /**
     * 匹配 function(column) ? value
     *
     * @param functionName 方法名称
     * @param args         参数名
     * @param typeMap      参数类型
     * @param optionType   比较类型
     * @param emptyValue   是否没有参数
     * @param value        参数
     * @return
     */
    public SpecificationSupport function(String functionName, Object[] args, Map typeMap, OptionType optionType, boolean emptyValue, Object... value) {
        Class clazz;
        //不是空参数,根据比较的参数类型,指定函数的返回类型
        if (!emptyValue && value != null && value[0] != null) {
            clazz = value[0].getClass();
        } else {
            clazz = Boolean.class;
        }
        SupportFunction supportFunction = new SupportFunction(functionName, args, typeMap, optionType, clazz);
        addConditions(null, OptionType.FUNCTION, emptyValue, supportFunction, value);
        return this;
    }

    /**
     * 忽略某个字段属性
     *
     * @param columns
     * @return
     */
    public SpecificationSupport ignoreProperty(String... columns) {
        ignoreColumn.addAll(Arrays.asList(columns));
        return this;
    }

    /**
     * 忽略大小写匹配 = lower(column)
     *
     * @param columns
     * @return
     */
    public SpecificationSupport ignoreCase(String... columns) {
        ignoreCase.addAll(Arrays.asList(columns));
        return this;
    }

    /**
     * 添加条件
     *
     * @param column
     * @param optionType
     */
    private void addCondition(String column, OptionType optionType) {
        try {
            addCondition(column, optionType, ObjectUtils.getField(t, column).get(t));
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 添加条件
     *
     * @param column
     * @param optionType
     */
    private void addConditionEmptyValue(String column, OptionType optionType) {
        addConditions(column, optionType, true, null);
    }

    /**
     * 添加条件
     *
     * @param column
     * @param optionType
     */
    @SafeVarargs
    private final  void addCondition(String column, OptionType optionType, K... value) {
        addConditions(column, optionType, false, null, value);
    }

    /**
     * 添加条件
     *
     * @param column
     * @param optionType
     */
    @SafeVarargs
    private final  void addConditions(String column, OptionType optionType, boolean emptyValue, SupportFunction function, K... value) {
        if (emptyValue) {
            condition.add(new FieldOption<>(column, optionType, value, function));
        } else {
            boolean flag = true;
            for (K k : value) {
                if (k == null) {
                    flag = false;
                    break;
                }
                if ("".equals(k) && ignoreNullString) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                condition.add(new FieldOption<>(column, optionType, value, function));
            }
        }
    }

    /**
     * and操作,创建一个消费者,依靠lambed表达式,消费一个创建好的对象,以添加到定义的队列中
     *
     * @param and
     * @return
     */
    public SpecificationSupport and(Consumer> and) {
        if (and != null) {
            SpecificationSupport s = SpecificationSupport.of();
            and.accept(s);
            if (!s.isEmpty()) {
                AND_OR.put(OptionType.AND, s);
            }
        }
        return this;
    }

    /**
     * or操作,创建一个消费者,依靠lambed表达式,消费一个创建好的对象,以添加到定义的队列中
     *
     * @param or
     * @return
     */
    public SpecificationSupport or(Consumer> or) {
        if (or != null) {
            SpecificationSupport s = SpecificationSupport.of();
            or.accept(s);
            if (!s.isEmpty()) {
                AND_OR.put(OptionType.OR, s);
            }
        }
        return this;
    }

    /**
     * @param root
     * @param query
     * @param cb
     * @return
     */
    @Override
    public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
        if (t != null) {
            Map fieldMap = ObjectUtils.getFieldMap(t.getClass());
            fieldMap.forEach((s1, field) -> {
                try {
                    if (!Modifier.isFinal(field.getModifiers())) {
                        if (!condition.contains(new FieldOption<>(field.getName(), null, null))) {
                            addCondition(field.getName(), OptionType.EQ, field.get(t));
                        }
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            });
        }
        Predicate p = null;
        List predicates = new ArrayList<>();
        for (FieldOption option : condition) {
            //不在忽略字段中
            if (!ignoreColumn.contains(option.name)) {
                Predicate predicate = getPredicate(root, cb, option);
                if (predicate != null) {
                    predicates.add(predicate);
                }
            }
        }
        if (!predicates.isEmpty()) {
            p = cb.and(predicates.toArray(new Predicate[0]));
        }
        for (Map.Entry> entry : AND_OR.entrySet()) {
            OptionType optionType = entry.getKey();
            SpecificationSupport specificationSupport = entry.getValue();
            if (optionType == OptionType.AND) {
                if (p == null) {
                    p = cb.and(specificationSupport.toPredicate(root, query, cb));
                } else {
                    p = cb.and(specificationSupport.toPredicate(root, query, cb), p);
                }
            } else {
                if (p == null) {
                    p = cb.or(specificationSupport.toPredicate(root, query, cb));
                } else {
                    p = cb.or(specificationSupport.toPredicate(root, query, cb), p);
                }
            }
        }
        return p;
    }

    /**
     * 设置是否忽略空串
     *
     * @param ignoreNullString
     */
    public void setIgnoreNullString(boolean ignoreNullString) {
        this.ignoreNullString = ignoreNullString;
    }

    /**
     * 判断构造器条件是否为空
     *
     * @return
     */
    protected boolean isEmpty() {
        return condition.isEmpty() && AND_OR.isEmpty();
    }

    /**
     * 判断条件类型,添加到组合中
     *
     * @param root
     * @param cb
     * @param option
     * @return
     */
    @SuppressWarnings("unchecked")
    private Predicate getPredicate(Root root, CriteriaBuilder cb, FieldOption option) {
        switch (option.getOptionType()) {
            case EQ:
                if (ignoreCase.contains(option.getName())) {
                    return cb.equal(cb.lower(root.get(option.getName())), option.getValue()[0].toString().toLowerCase());
                }
                return cb.equal(root.get(option.getName()), option.getValue()[0]);
            case GE:
                return cb.ge(root.get(option.getName()), (Number) option.getValue()[0]);
            case GT:
                return cb.gt(root.get(option.getName()), (Number) option.getValue()[0]);
            case IN:
                if (ignoreCase.contains(option.getName())) {
                    CriteriaBuilder.In in = cb.in(cb.lower(root.get(option.getName())));
                    for (Object o : option.getValue()) {
                        in.value(o.toString().toLowerCase());
                    }
                    return cb.and(in);
                }
                return root.get(option.getName()).in(option.getValue());
            case LE:
                return cb.le(root.get(option.getName()), (Number) option.getValue()[0]);
            case LT:
                Number o = null;
                if (option.getValue()[0] instanceof String) {
                    o = new BigInteger((String) option.getValue()[0]);
                }
                if (o == null) {
                    o = (Number) option.getValue()[0];
                }
                return cb.lt(root.get(option.getName()), o);
            case LIKE:
                if (ignoreCase.contains(option.getName())) {
                    return cb.like(cb.lower(root.get(option.getName())), "%" + option.getValue()[0].toString().toLowerCase() + "%");
                }
                return cb.like(root.get(option.getName()), "%" + option.getValue()[0] + "%");
            case STARTS_LIKE:
                if (ignoreCase.contains(option.getName())) {
                    return cb.like(cb.lower(root.get(option.getName())), "%" + option.getValue()[0].toString().toLowerCase());
                }
                return cb.like(root.get(option.getName()), "%" + option.getValue()[0]);
            case END_LIKE:
                if (ignoreCase.contains(option.getName())) {
                    return cb.like(cb.lower(root.get(option.getName())), option.getValue()[0].toString().toLowerCase() + "%");
                }
                return cb.like(root.get(option.getName()), option.getValue()[0] + "%");
            case IS_NULL:
                return root.get(option.getName()).isNull();
            case IS_NOT_NULL:
                return root.get(option.getName()).isNotNull();
            case NOT_LIKE:
                if (ignoreCase.contains(option.getName())) {
                    return cb.notLike(cb.lower(root.get(option.getName())), "%" + option.getValue()[0].toString().toLowerCase() + "%");
                }
                return cb.notLike(root.get(option.getName()), "%" + option.getValue()[0] + "%");
            case NOT_STARTS_LIKE:
                if (ignoreCase.contains(option.getName())) {
                    return cb.notLike(cb.lower(root.get(option.getName())), "%" + option.getValue()[0].toString().toLowerCase());
                }
                return cb.notLike(root.get(option.getName()), "%" + option.getValue()[0]);
            case NOT_END_LIKE:
                if (ignoreCase.contains(option.getName())) {
                    return cb.notLike(cb.lower(root.get(option.getName())), option.getValue()[0].toString().toLowerCase() + "%");
                }
                return cb.notLike(root.get(option.getName()), option.getValue()[0] + "%");
            case NOT_EQ:
                if (ignoreCase.contains(option.getName())) {
                    return cb.notEqual(cb.lower(root.get(option.getName())), option.getValue()[0].toString().toLowerCase());
                }
                return cb.notEqual(root.get(option.getName()), option.getValue()[0]);
            case BETWEEN:
                return cb.between(root.get(option.getName()), (Comparable) option.getValue()[0], (Comparable) option.getValue()[1]);
            case TRUE:
                return cb.isTrue(root.get(option.getName()));
            case FALSE:
                return cb.isFalse(root.get(option.getName()));
            case FUNCTION:
                SupportFunction function = option.getFunction();
                Expression[] args = Arrays.stream(function.args).map(o1 -> {
                    ArgType o2 = function.getArgType().get(o1);
                    if (o2 != null) {
                        if (o2 == ArgType.ROOT) {
                            return root.get(o1.toString());
                        } else if (o2 == ArgType.STRING) {
                            return cb.literal(o1);
                        } else if (o2 == ArgType.FUNCTION) {
                            return new BasicFunctionExpression((CriteriaBuilderImpl) cb, String.class, o1.toString());
                        }
                    }
                    return cb.literal(o1);
                }).toArray((IntFunction[]>) Expression[]::new);
                Expression expression = cb.function(function.function, function.resultType, args);
                return getExpression(cb, expression, option);
        }
        return null;
    }

    /**
     * 获取方法表达式
     *
     * @param cb
     * @param expression
     * @param option
     * @return
     */
    @SuppressWarnings("unchecked")
    private Predicate getExpression(CriteriaBuilder cb, Expression expression, FieldOption option) {
        switch (option.function.optionType) {
            case EQ:
                return cb.equal(expression, option.getValue()[0]);
            case GE:
                return cb.ge((Expression) expression, (Number) option.getValue()[0]);
            case GT:
                return cb.gt((Expression) expression, (Number) option.getValue()[0]);
            case IN:
                CriteriaBuilder.In in = cb.in(expression);
                for (Object o : option.getValue()) {
                    in.value(o);
                }
                return cb.and(in);
            case LE:
                return cb.le((Expression) expression, (Number) option.getValue()[0]);
            case LT:
                return cb.lt((Expression) expression, (Number) option.getValue()[0]);
            case LIKE:
                return cb.like((Expression) expression, "%" + option.getValue()[0] + "%");
            case STARTS_LIKE:
                return cb.like((Expression) expression, "%" + option.getValue()[0]);
            case END_LIKE:
                return cb.like((Expression) expression, option.getValue()[0] + "%");
            case IS_NULL:
                return cb.isNull(expression);
            case IS_NOT_NULL:
                return cb.isNotNull(expression);
            case NOT_LIKE:
                return cb.notLike((Expression) expression, "%" + option.getValue()[0] + "%");
            case NOT_STARTS_LIKE:
                return cb.notLike((Expression) expression, "%" + option.getValue()[0]);
            case NOT_END_LIKE:
                return cb.notLike((Expression) expression, option.getValue()[0] + "%");
            case NOT_EQ:
                return cb.notEqual(expression, option.getValue()[0]);
            case BETWEEN:
                return cb.between((Expression) expression, (Comparable) option.getValue()[0], (Comparable) option.getValue()[1]);
            case TRUE:
                return cb.isTrue((Expression) expression);
            case FALSE:
                return cb.isFalse((Expression) expression);
        }
        return null;
    }

    public enum OptionType {
        FUNCTION,   //执行函数
        AND,        //添加and
        OR,         //添加or
        BETWEEN,    //between x1 and x2
        STARTS_LIKE,//like %s
        END_LIKE,   //like s%
        LIKE,       //like %s%
        EQ,         //=
        GT,         //>
        LT,         //<
        GE,         //>=
        LE,         //<=
        IN,         //in
        TRUE,
        FALSE,
        REGEXP,     //regexp(column,regex)
        IS_NULL,    // is null
        IS_NOT_NULL,//is not null
        NOT_EQ,     //!=
        NOT_LIKE,   //not like %s%
        NOT_STARTS_LIKE,//not like %s
        NOT_END_LIKE,   //not like s%
        IGNORE_CASE //忽略大小写
    }

    private static class FieldOption {
        private String name;
        private OptionType optionType;
        private T[] value;
        private SupportFunction function;

        FieldOption(String name, OptionType optionType, T[] value) {
            this.name = name;
            this.optionType = optionType;
            this.value = value;
        }

        FieldOption(String name, OptionType optionType, T[] value, SupportFunction function) {
            this.name = name;
            this.optionType = optionType;
            this.value = value;
            this.function = function;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        OptionType getOptionType() {
            return optionType;
        }

        public void setOptionType(OptionType optionType) {
            this.optionType = optionType;
        }

        public T[] getValue() {
            return value;
        }

        public void setValue(T[] value) {
            this.value = value;
        }

        public SupportFunction getFunction() {
            return function;
        }

        public void setFunction(SupportFunction function) {
            this.function = function;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            FieldOption option = (FieldOption) o;
            return Objects.equals(name, option.name);
        }

        @Override
        public int hashCode() {
            return Objects.hash(name);
        }
    }

    /**
     * 方法对象
     */
    private static class SupportFunction {
        private String function;
        private Class resultType;
        private Object[] args;
        private Map argType;   //key:argName value:argType
        private OptionType optionType;

        SupportFunction(String function, Object[] args, Map argType, OptionType optionType, Class resultType) {
            this.function = function;
            this.args = args;
            this.argType = argType;
            this.optionType = optionType;
            this.resultType = resultType;
        }

        public String getFunction() {
            return function;
        }

        public void setFunction(String function) {
            this.function = function;
        }

        public Class getResultType() {
            return resultType;
        }

        public void setResultType(Class resultType) {
            this.resultType = resultType;
        }

        public Object[] getArgs() {
            return args;
        }

        public void setArgs(Object[] args) {
            this.args = args;
        }

        public Map getArgType() {
            return argType;
        }

        public void setArgType(Map argType) {
            this.argType = argType;
        }

        public OptionType getOptionType() {
            return optionType;
        }

        public void setOptionType(OptionType optionType) {
            this.optionType = optionType;
        }
    }

    //参数类型,是读取字段,还是字符串参数
    enum ArgType {
        ROOT,
        STRING,
        FUNCTION
    }
}
 
  

关于以上代码中用到的其他工具代码:

/**
 * 获取对象Field属性对象集合ap
 *
 * @param clazz
 * @return
 */
public static Map getFieldMap(Class clazz) {
    Map result = new LinkedHashMap(16);
    for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            result.put(field.getName(), field);
        }
    }
    return result;
}
//ps:之前漏了一些方法的说明,补充一下,关于ObjectUtils中涉及到的方法
//另外补充一下,其实将Field保存为Map,使用key的方式搜索会更好一点
/**
 * 获取对象Field属性对象
 *
 * @param clazz
 * @param name  属性名称
 * @return
 */
public static Field getField(Class clazz, String name) {
    for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (name.equals(field.getName())) {
                field.setAccessible(true);
                return field;
            }
        }
    }
    return null;
}

/**
 * 获取对象Field属性对象
 *
 * @param obj
 * @param name
 * @param 
 * @return
 */
public static  Field getField(T obj, String name) {
    return getField(obj.getClass(), name);
}

这些你都可以复制后直接使用!

具体代码实现原理这里不再累赘,网上很多这方面的资料。

由于时间问题只看了两天的资料,所以有一些疏漏的地方轻喷,请指正。

你可能感兴趣的:(Jpa)