jpa二次封装:像使用mybatis-plus一样使用jpa查询

文章针对使用Hibernate查询数据库时存在的编写大量重复代码、部分API难记、不能链式构造条件等问题,提出对Hibernate进行二次封装的解决方案。介绍了封装的设计思路,包括常用API封装、使用cglib代理等,还设计了两种调用模式并给出使用示例,最后提供了相关依赖和工具源码。
  • 引言

    • 在使用hibernate查询数据库时需要面对的问题:
      1. 编写的非常多的重复代码[比如空值判断],代码是sql的3倍,
      2. 部分api记不住
      3. 不能链式构造条件
    • 解决方案:
      1. 对hibernate进行二次封装,解决以上需求
    • 源码在文章末尾,由于源码简单依赖少就没有单独推到git

  • Hibernate查询二次封装概述

    • 设计思路:
      1. 对常用的api进行封装,只需简单调用即可实现条件构造
      2. 使用cglib代理对对方法进行缓存与统一调用
      3. 大量使用lambda与泛型解决手动写字段名称与字段入参约束,实现入参预检
    • 设计了两种调用模式,
      1. 模式一:作为一个简单条件构造工具的封装
      2. 模式二:使用cglib代理实现方法的缓存与统一调用
  • 实现查询操作

    • 模式一
      • 使用示例
List<UserEntity> list = userService.list((root, qu, cb) -> MyJpaUtil.create(root, qu, cb)
.equal(UserEntity::getStatus, DataStatus.NORMAL.getStatus())
.like(query::getName)
//其他条件
.order(Order.DESC(UserEntity::getCreatedTime))
.builder());
  • 模式二
    • 使用示例1
List<UserEntity> list = userService.list(MyJpaUtil.create(UserEntity.class)
.equal(UserEntity::getStatus,DataStatus.NORMAL.getStatus())
.like(query::getName)
//其他条件
.order(Order.DESC(UserEntity::getCreatedTime)));
  • 使用示例2
MyJpaUtil<UserEntity> jpa = MyJpaUtil.create();  
jpa.equal(UserEntity::getStatus, DataStatus.NORMAL.getStatus());  
jpa.like(query::getName);
//其他条件
jpa.order(Order.DESC(UserEntity::getCreatedTime));  
List<UserEntity> list = userService.list(jpa);

更多使用示例直接参考源码注释即可,源码在文章末尾

  • 参考资料

    1. Hibernate框架使用手册【 Hibernate 教程_w3cschool
    2. cglib代理使用教程
    3. hutool参考文档【 入门和安装 (oschina.io)
  • 源码

    相关依赖:

        hutool,cglib[springboot自带],hibernate框架

        <!--hibernate依赖-->
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.1-api</artifactId>
            <version>1.0.2.Final</version>
        </dependency>
        <!--spring-jpa依赖-->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>2.7.15</version>
        </dependency>
        <!--hutool工具-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.23</version>
        </dependency>
工具源码:

最底层条件封装工具

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.func.LambdaUtil;
import cn.hutool.core.util.StrUtil;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Author: wanger
 * @Date: 2023/12/27 11:41
 * @Description: 具体构造jpa查询的工具,本工具类只对具体的操作进行封装处理<br/>
 * 扩展需遵循规范:<br/>
 * 1.方法前面的入参时必须这四个参数predicates,root,qu,cb必须在前,后面才是自己需要的参数,通常为两种模式【数据库字段,操作值】,【数据库字段】<br/>
 * 2.当前方法功能为【数据库字段 操作符 操作值】模式时,<br/>
 * 2.1.方法名将标识操作符,<br/>
 * 2.2.第一个入参为数据库字段,且为字符串类型<br/>
 * 2.3.第二个入参为操作值,并且该操作值需要加入必要的泛型约束其类型为操作值对应的类型,如equal看为任意类型,like为字符串类型,lessThanOrEqualTo为可比较的类型<br/>
 * 3.方法内部需合法地调用jpa的api<br/>
 * 4.方法内部需进行必要的空指针,空值判定<br/>
 * 5.<span style="color:red">禁止</span>在方法内写定制化代码,如:【<br/>
 * <pre>{@code
 *  //定制代码
 *  if ("userId".equals(field)) {
 *      //定制逻辑
 *  }
 * }</pre>
 * 】<br/>
 */
public class JpaConditionUtil {
    /**
     * 排序操作【order by 字段1 排序类型,字段2 排序类型,...】
     *
     * @param root   r
     * @param qu     q
     * @param cb     c
     * @param orders 排序字段列表
     * @param <T>    操作对象泛型类型
     */
    @SafeVarargs
    public static <T> void order(Root<T> root, CriteriaQuery<?> qu, CriteriaBuilder cb, Order<T>... orders) {
        for (Order<T> order : orders) {
            if (Order.ASC.equals(order.getSort())) {
                JpaConditionUtil.orderAsc(root, qu, cb, LambdaUtil.getFieldName(order.getFieldFun()));
            } else if (Order.DESC.equals(order.getSort())) {
                JpaConditionUtil.orderDesc(root, qu, cb, LambdaUtil.getFieldName(order.getFieldFun()));
            }
        }
    }

    /**
     * 顺序排序order by 字段 asc
     *
     * @param root  r
     * @param qu    q
     * @param cb    c
     * @param field 数据库字段名称
     * @param <T>   操作对象泛型类型
     */
    private static <T> void orderAsc(Root<T> root, CriteriaQuery<?> qu, CriteriaBuilder cb, String field) {
        qu.orderBy(cb.asc(root.get(field)));
    }

    /**
     * 逆序排序【order by 字段 desc】
     *
     * @param root  r
     * @param qu    q
     * @param cb    c
     * @param field 数据库字段名称
     * @param <T>   操作对象泛型类型
     */
    private static <T> void orderDesc(Root<T> root, CriteriaQuery<?> qu, CriteriaBuilder cb, String field) {
        qu.orderBy(cb.desc(root.get(field)));
    }

    /**
     * 不等于判定【字段 != 值】
     *
     * @param predicates p
     * @param root       r
     * @param cb         c
     * @param field      数据库字段名称
     * @param value      操作值
     * @param <T>        操作对象泛型类型
     */
    public static <T> void notEqual(List<Predicate> predicates, Root<T> root, CriteriaBuilder cb, String field, Object value) {
        if (value != null) {
            if (value instanceof String) {
                if (StrUtil.isNotBlank(value.toString())) {
                    predicates.add(cb.notEqual(root.get(field), value));
                }
            } else {
                predicates.add(cb.notEqual(root.get(field), value));
            }
        }
    }

    /**
     * 等于判定【字段 = 值】
     *
     * @param predicates p
     * @param root       r
     * @param cb         c
     * @param field      数据库字段名称
     * @param value      操作值
     * @param <T>        操作对象泛型类型
     */
    public static <T> void equal(List<Predicate> predicates, Root<T> root, CriteriaBuilder cb, String field, Object value) {
        if (value != null) {
            if (value instanceof String) {
                if (StrUtil.isNotBlank(value.toString())) {
                    predicates.add(cb.equal(root.get(field), value));
                }
            } else {
                predicates.add(cb.equal(root.get(field), value));
            }
        }
    }

    /**
     * 小于等于判定【字段 <= 值】
     *
     * @param predicates p
     * @param root       r
     * @param cb         c
     * @param field      数据库字段名称
     * @param value      操作值
     * @param <T>        操作对象泛型类型
     * @param <Y>        操作值类型泛型约束
     */
    public static <T, Y extends Comparable<? super Y>> void lessThanOrEqualTo(List<Predicate> predicates, Root<T> root, CriteriaBuilder cb, String field, Y value) {
        if (value != null) {
            predicates.add(cb.lessThanOrEqualTo(root.get(field), value));
        }
    }

    /**
     * 小于判定【字段 < 值】
     *
     * @param predicates p
     * @param root       r
     * @param cb         c
     * @param field      数据库字段名称
     * @param value      操作值
     * @param <T>        操作对象泛型类型
     * @param <Y>        操作值类型泛型约束
     */
    public static <T, Y extends Comparable<? super Y>> void lessThan(List<Predicate> predicates, Root<T> root, CriteriaBuilder cb, String field, Y value) {
        if (value != null) {
            predicates.add(cb.lessThan(root.get(field), value));
        }
    }

    /**
     * 大于等于判定【字段 >= 值】
     *
     * @param predicates p
     * @param root       r
     * @param cb         c
     * @param field      数据库字段名称
     * @param value      操作值
     * @param <T>        操作对象泛型类型
     * @param <Y>        操作值类型泛型约束
     */
    public static <T, Y extends Comparable<? super Y>> void greaterThanOrEqualTo(List<Predicate> predicates, Root<T> root, CriteriaBuilder cb, String field, Y value) {
        if (value != null) {
            predicates.add(cb.greaterThanOrEqualTo(root.get(field), value));
        }
    }

    /**
     * 大于判定【字段 > 值】
     *
     * @param predicates p
     * @param root       r
     * @param cb         c
     * @param field      数据库字段名称
     * @param value      操作值
     * @param <T>        操作对象泛型类型
     * @param <Y>        操作值类型泛型约束
     */
    public static <T, Y extends Comparable<? super Y>> void greaterThan(List<Predicate> predicates, Root<T> root, CriteriaBuilder cb, String field, Y value) {
        if (value != null) {
            predicates.add(cb.greaterThan(root.get(field), value));
        }
    }

    /**
     * 区间判定,不包含左右【字段 between startValue and endValue】
     *
     * @param predicates p
     * @param root       r
     * @param cb         c
     * @param field      数据库字段名称
     * @param startValue 起始值
     * @param endValue   结束值
     * @param <T>        操作对象泛型类型
     * @param <Y>        操作值类型泛型约束
     */
    public static <T, Y extends Comparable<? super Y>> void between(List<Predicate> predicates, Root<T> root, CriteriaBuilder cb, String field, Y startValue, Y endValue) {
        if (startValue != null && endValue != null) {
            predicates.add(cb.between(root.get(field), startValue, endValue));
        }
    }

    /**
     * 左右闭区间判定【字段 >= startValue and 字段 <= endValue】
     *
     * @param predicates p
     * @param root       r
     * @param cb         c
     * @param field      数据库字段名称
     * @param startValue 起始值
     * @param endValue   结束值
     * @param <T>        操作对象泛型类型
     * @param <Y>        操作值类型泛型约束
     */
    public static <T, Y extends Comparable<? super Y>> void closedInterval(List<Predicate> predicates, Root<T> root, CriteriaBuilder cb, String field, Y startValue, Y endValue) {
        if (startValue != null && endValue != null) {
            greaterThanOrEqualTo(predicates, root, cb, field, startValue);
            lessThanOrEqualTo(predicates, root, cb, field, endValue);
        }
    }

    /**
     * 左开右闭区间判定【字段 > startValue and 字段 <= endValue】
     *
     * @param predicates p
     * @param root       r
     * @param cb         c
     * @param field      数据库字段名称
     * @param startValue 起始值
     * @param endValue   结束值
     * @param <T>        操作对象泛型类型
     * @param <Y>        操作值类型泛型约束
     */
    public static <T, Y extends Comparable<? super Y>> void openLeftAndCloseRight(List<Predicate> predicates, Root<T> root, CriteriaBuilder cb, String field, Y startValue, Y endValue) {
        if (startValue != null && endValue != null) {
            greaterThan(predicates, root, cb, field, startValue);
            lessThanOrEqualTo(predicates, root, cb, field, endValue);
        }
    }

    /**
     * 左闭右开区间判定【字段 >= startValue and 字段 < endValue】
     *
     * @param predicates p
     * @param root       r
     * @param cb         c
     * @param field      数据库字段名称
     * @param startValue 起始值
     * @param endValue   结束值
     * @param <T>        操作对象泛型类型
     * @param <Y>        操作值类型泛型约束
     */
    public static <T, Y extends Comparable<? super Y>> void closeLeftAndOpenRight(List<Predicate> predicates, Root<T> root, CriteriaBuilder cb, String field, Y startValue, Y endValue) {
        if (startValue != null && endValue != null) {
            greaterThanOrEqualTo(predicates, root, cb, field, startValue);
            lessThan(predicates, root, cb, field, endValue);
        }
    }

    /**
     * 包含判定【字段 in(值1,值2,...)】
     *
     * @param predicates p
     * @param root       r
     * @param field      数据库字段名称
     * @param value      操作值
     * @param <T>        操作对象泛型类型
     * @param <Y>        操作值类型泛型约束
     */
    public static <T, Y extends Collection<?>> void in(List<Predicate> predicates, Root<T> root, String field, Y value) {
        if (CollUtil.isNotEmpty(value)) {
            //创建一个新的list防止入参为不可修改内容对象
            List<Object> list = new ArrayList<>(value).stream().filter(Objects::nonNull).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(list)) {
                predicates.add(root.get(field).in(list));
            }
        }
    }

    /**
     * 包含判定【字段 not in(值1,值2,...)】
     *
     * @param predicates p
     * @param root       r
     * @param field      数据库字段名称
     * @param value      操作值
     * @param <T>        操作对象泛型类型
     * @param <Y>        操作值类型泛型约束
     */
    public static <T, Y extends Collection<?>> void notIn(List<Predicate> predicates, Root<T> root, CriteriaBuilder cb, String field, Y value) {
        if (CollUtil.isNotEmpty(value)) {
            //创建一个新的list防止入参为不可修改内容对象
            List<Object> list = new ArrayList<>(value).stream().filter(Objects::nonNull).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(list)) {
                predicates.add(cb.not(root.get(field).in(list)));
            }
        }
    }

    /**
     * 为空判定【字段 is null】
     *
     * @param predicates p
     * @param root       r
     * @param cb         c
     * @param field      数据库字段名称
     * @param <T>        操作对象泛型类型
     */
    public static <T> void isNull(List<Predicate> predicates, Root<T> root, CriteriaBuilder cb, String field) {
        if (StrUtil.isNotBlank(field)) {
            predicates.add(cb.isNull(root.get(field)));
        }
    }

    /**
     * 不为空判定【字段 is not null】
     *
     * @param predicates p
     * @param root       r
     * @param cb         c
     * @param field      数据库字段名称
     * @param <T>        操作对象泛型类型
     */
    public static <T> void isNotNull(List<Predicate> predicates, Root<T> root, CriteriaBuilder cb, String field) {
        if (StrUtil.isNotBlank(field)) {
            predicates.add(cb.isNotNull(root.get(field)));
        }
    }

    /**
     * 模糊匹配判定【字段 like ''】
     *
     * @param predicates p
     * @param root       r
     * @param cb         c
     * @param field      数据库字段名称
     * @param value      操作值
     * @param left       是否左匹配
     * @param right      是否右匹配
     * @param <T>        操作对象泛型类型
     */
    public static <T> void like(List<Predicate> predicates, Root<T> root, CriteriaBuilder cb, String field, String value, boolean left, boolean right) {
        if (StrUtil.isNotBlank(value)) {
            predicates.add(cb.like(root.get(field), (left ? "%" : "") + value + (right ? "%" : "")));
        }
    }

    /**
     * 反向模糊匹配判定【字段 not like ''】
     *
     * @param predicates p
     * @param root       r
     * @param cb         c
     * @param field      数据库字段名称
     * @param value      操作值
     * @param left       是否左匹配
     * @param right      是否右匹配
     * @param <T>        操作对象泛型类型
     */
    public static <T> void notLike(List<Predicate> predicates, Root<T> root, CriteriaBuilder cb, String field, String value, boolean left, boolean right) {
        if (StrUtil.isNotBlank(value)) {
            predicates.add(cb.notLike(root.get(field), (left ? "%" : "") + value + (right ? "%" : "")));
        }
    }

}

直接调用的工具

import cn.hutool.core.lang.func.Func0;
import cn.hutool.core.lang.func.Func1;
import cn.hutool.core.lang.func.LambdaUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @Author: wanger
 * @Date: 2023/12/27 15:08
 * @Description: 该工具为单表查询条件构造类,可类似MyBatis-plus的链式调用构造条件,并且不需要多余的判空操作<br/>
 * 两种使用模式:<br/>
 * <ol>
 *     <li>模式一:jpa全功能模式<br/>
 *     <ul>
 *         <li>jpa全功能模式使用相对复杂,但保留jpa原始功能比较全</li>
 *         <li>当前工具必须在Specification一个匿名实现类被使用,并且必须使用MyJpaUtil.create(root, qu, cb)创建,以builder()结束调用</li>
 *         <li>使用示例【<pre>{@code
 *         List<UserEntity> list = userService.list((root, qu, cb) -> MyJpaUtil.create(root, qu, cb)
 *                 .equal(UserEntity::getStatus, DataStatus.NORMAL.getStatus())
 *                 .like(query::getName)
 *                 //其他条件
 *                 .order(Order.DESC(UserEntity::getCreatedTime))
 *                 .builder());
 *         }</pre>】</li>
 *     </ul>
 *     </li>
 *     <li>模式二:使用更加方便,但禁止调用MyJpaUtil中没有的jpa功能</li>
 *     <ul>
 *         <li>更快捷的构造jpa查询条件</li>
 *         <li>功能设计思路:使用cglib动态代理记录所有被调用的方法而不调用,
 *         在Specification接口调用toPredicate方法时才把所有记录的方法都遍历出来一一实际调用,
 *         从而避免将当前工具作为Specification接口匿名实现类的List《Predicate》构造工具,而是实际作为Specification的实现类使用</li>
 *         <li>为此做出的牺牲:jpa原始的Root《T》,CriteriaQuery《?》,CriteriaBuilder,List《Predicate》四个对象将被禁止在模式二中调用</li>
 *         <li>模式二将依赖模式一</li>
 *         <li>使用示例1【<pre>{@code
 *         List<UserEntity> list = userService.list(MyJpaUtil.create(UserEntity.class)
 *                 .equal(UserEntity::getStatus, DataStatus.NORMAL.getStatus())
 *                 .like(query::getName)
 *                 //其他条件
 *                 .order(Order.DESC(UserEntity::getCreatedTime)));
 *         }</pre>】</li>
 *         <li>使用示例2【<pre>{@code
 *         MyJpaUtil<UserEntity> jpa = MyJpaUtil.create();
 *         jpa.equal(UserEntity::getStatus, DataStatus.NORMAL.getStatus());
 *         jpa.like(query::getName);
 *         //其他条件
 *         jpa.order(Order.DESC(UserEntity::getCreatedTime));
 *         List<UserEntity> list = userService.list(jpa);
 *         }</pre>】</li>
 *     </ul>
 * </ol><br/>
 * 扩展需遵循规范:<br/>
 * 1.当前方法功能为【数据库字段 操作符 操作值】模式时需提供两个方法,<br/>
 * 1.1.方法名将标识操作符,<br/>
 * 1.2.方法一为一个入参,参数为lambda函数参数入参,<br/>
 * 1.3.方法二为两个入参,参数1为lambda函数入参,参数2为操作值入参,<br/>
 * 2.当方法功能为【数据库字段 操作符】模式时只需提供一个方法
 * 2.1.方法名将标识操作符<br/>
 * 2.2.方法为一个入参,参数为lambda函数参数入参,<br/>
 * 3.方法内部需遵循规范调用JpaConditionUtil中的api<br/>
 * 4.方法结束需return this以保证链式调用不被中断<br/>
 * 5.方法必须添加必要的字段与返回值注释,并且需要说明方法的【功能,使用示例,效果】<br/>
 * 6.<span style="color:red">禁止</span>在方法内写定制化代码,如:【<br/>
 * <pre>{@code
 *  //定制代码
 *  if ("userId".equals(field)) {
 *      //定制逻辑
 *  }
 * }</pre>
 * 】<br/>
 */
@SuppressWarnings("unused")
public class MyJpaUtil<T> implements Specification<T> {
    private static final long serialVersionUID = -5346942786212881309L;
    /**
     * Specification接口的toPredicate方法中的Root《T》 root参数
     */
    private Root<T> root;
    /**
     * Specification接口的toPredicate方法中的CriteriaQuery《?》 query参数
     */
    private CriteriaQuery<?> query;
    /**
     * Specification接口的toPredicate方法中的CriteriaBuilder cb参数
     */
    private CriteriaBuilder cb;
    /**
     * 记录jpa条件的集合
     */
    private final List<Predicate> predicates = new ArrayList<>();
    /**
     * 方法调用代理处理类
     */
    private AgentSimplification agentSimplification;
    /**
     * 方法调用记录
     */
    private List<MethodRecord> methodRecords = new ArrayList<>();

    /**
     * 模糊匹配判定【字段 like ''】<br/>
     * 使用示例【.like(query::getName)】<br/>
     * 效果【name like '%张三%'】<br/>
     *
     * @param getFunc 字段与值的lambda函数
     * @return this
     */
    public MyJpaUtil<T> like(Func0<String> getFunc) {
        JpaConditionUtil.like(predicates, root, cb, LambdaUtil.getFieldName(getFunc), getFunc.callWithRuntimeException(), true, true);
        return this;
    }

    /**
     * 模糊匹配判定【字段 like ''】<br/>
     * 使用示例【.like(UserEntity::getName, "张三")】<br/>
     * 效果【name like '%张三%'】<br/>
     *
     * @param getFunc 字段的lambda函数
     * @param value   操作值
     * @return this
     */
    public MyJpaUtil<T> like(Func1<T, String> getFunc, String value) {
        JpaConditionUtil.like(predicates, root, cb, LambdaUtil.getFieldName(getFunc), value, true, true);
        return this;
    }

    /**
     * 模糊匹配判定【字段 like ''】<br/>
     * 使用示例【.likeLeft(query::getName)】<br/>
     * 效果【name like '%张三'】<br/>
     *
     * @param getFunc 字段与值的lambda函数
     * @return this
     */
    public MyJpaUtil<T> likeLeft(Func0<String> getFunc) {
        JpaConditionUtil.like(predicates, root, cb, LambdaUtil.getFieldName(getFunc), getFunc.callWithRuntimeException(), true, false);
        return this;
    }

    /**
     * 模糊匹配判定【字段 like ''】<br/>
     * 使用示例【.likeLeft(UserEntity::getName, "张三")】<br/>
     * 效果【name like '%张三'】<br/>
     *
     * @param getFunc 字段的lambda函数
     * @param value   操作值
     * @return this
     */
    public MyJpaUtil<T> likeLeft(Func1<T, String> getFunc, String value) {
        JpaConditionUtil.like(predicates, root, cb, LambdaUtil.getFieldName(getFunc), value, true, false);
        return this;
    }

    /**
     * 模糊匹配判定【字段 like ''】<br/>
     * 使用示例【.likeRight(query::getName)】<br/>
     * 效果【name like '张三%'】<br/>
     *
     * @param getFunc 字段与值的lambda函数
     * @return this
     */
    public MyJpaUtil<T> likeRight(Func0<String> getFunc) {
        JpaConditionUtil.like(predicates, root, cb, LambdaUtil.getFieldName(getFunc), getFunc.callWithRuntimeException(), false, true);
        return this;
    }

    /**
     * 模糊匹配判定【字段 like ''】<br/>
     * 使用示例【.likeRight(UserEntity::getName, "张三")】<br/>
     * 效果【name like '张三%'】<br/>
     *
     * @param getFunc 字段的lambda函数
     * @param value   操作值
     * @return this
     */
    public MyJpaUtil<T> likeRight(Func1<T, String> getFunc, String value) {
        JpaConditionUtil.like(predicates, root, cb, LambdaUtil.getFieldName(getFunc), value, false, true);
        return this;
    }

    /**
     * 模糊匹配判定【字段 not like ''】<br/>
     * 使用示例【.notLike(query::getName)】<br/>
     * 效果【name not like '%张三%'】<br/>
     *
     * @param getFunc 字段与值的lambda函数
     * @return this
     */
    public MyJpaUtil<T> notLike(Func0<String> getFunc) {
        JpaConditionUtil.notLike(predicates, root, cb, LambdaUtil.getFieldName(getFunc), getFunc.callWithRuntimeException(), true, true);
        return this;
    }

    /**
     * 模糊匹配判定【字段 not like ''】<br/>
     * 使用示例【.notLike(UserEntity::getName, "张三")】<br/>
     * 效果【name not like '%张三%'】<br/>
     *
     * @param getFunc 字段的lambda函数
     * @param value   操作值
     * @return this
     */
    public MyJpaUtil<T> notLike(Func1<T, String> getFunc, String value) {
        JpaConditionUtil.notLike(predicates, root, cb, LambdaUtil.getFieldName(getFunc), value, true, true);
        return this;
    }

    /**
     * 模糊匹配判定【字段 not like ''】<br/>
     * 使用示例【.notLikeLeft(query::getName)】<br/>
     * 效果【name not like '%张三'】<br/>
     *
     * @param getFunc 字段与值的lambda函数
     * @return this
     */
    public MyJpaUtil<T> notLikeLeft(Func0<String> getFunc) {
        JpaConditionUtil.notLike(predicates, root, cb, LambdaUtil.getFieldName(getFunc), getFunc.callWithRuntimeException(), true, false);
        return this;
    }

    /**
     * 模糊匹配判定【字段 not like ''】<br/>
     * 使用示例【.notLikeLeft(UserEntity::getName, "张三")】<br/>
     * 效果【name not like '%张三'】<br/>
     *
     * @param getFunc 字段的lambda函数
     * @param value   操作值
     * @return this
     */
    public MyJpaUtil<T> notLikeLeft(Func1<T, String> getFunc, String value) {
        JpaConditionUtil.notLike(predicates, root, cb, LambdaUtil.getFieldName(getFunc), value, true, false);
        return this;
    }

    /**
     * 模糊匹配判定【字段 not like ''】<br/>
     * 使用示例【.notLikeRight(query::getName)】<br/>
     * 效果【name not like '张三%'】<br/>
     *
     * @param getFunc 字段与值的lambda函数
     * @return this
     */
    public MyJpaUtil<T> notLikeRight(Func0<String> getFunc) {
        JpaConditionUtil.notLike(predicates, root, cb, LambdaUtil.getFieldName(getFunc), getFunc.callWithRuntimeException(), false, true);
        return this;
    }

    /**
     * 模糊匹配判定【字段 not like ''】<br/>
     * 使用示例【.notLikeRight(UserEntity::getName, "张三")】<br/>
     * 效果【name not like '张三%'】<br/>
     *
     * @param getFunc 字段的lambda函数
     * @param value   操作值
     * @return this
     */
    public MyJpaUtil<T> notLikeRight(Func1<T, String> getFunc, String value) {
        JpaConditionUtil.notLike(predicates, root, cb, LambdaUtil.getFieldName(getFunc), value, false, true);
        return this;
    }

    /**
     * 顺序排序操作【order by 字段 desc】<br/>
     * 使用示例【.orderDesc(UserEntity::getAge))】<br/>
     * 效果【order by age desc】<br/>
     *
     * @param getFunc 字段的lambda函数
     * @return this
     */
    public MyJpaUtil<T> orderDesc(Func1<T, ?> getFunc) {
        return this.order(Order.DESC(getFunc));
    }

    /**
     * 顺序排序操作【order by 字段 asc】<br/>
     * 使用示例【.orderAsc(UserEntity::getAge)】<br/>
     * 效果【order by age asc】<br/>
     *
     * @param getFunc 字段的lambda函数
     * @return this
     */
    public MyJpaUtil<T> orderAsc(Func1<T, ?> getFunc) {
        return this.order(Order.ASC(getFunc));
    }

    /**
     * 多值排序操作【order by 字段1 排序类型,字段2 排序类型,...】<br/>
     * 使用示例【.order(Order.DESC(UserEntity::getCreatedTime), Order.ASC(UserEntity::getPhone))】<br/>
     * 效果【order by created_time desc,phone asc】<br/>
     *
     * @param orders 排序条件数组
     * @return this
     */
    public MyJpaUtil<T> order(Order<T>... orders) {
        JpaConditionUtil.order(root, query, cb, orders);
        return this;
    }

    /**
     * 为空判定【字段 is null】<br/>
     * 使用示例【.isNull(query::getName)】<br/>
     * 效果【name is null】<br/>
     *
     * @param getFunc 字段的lambda函数
     * @return this
     */
    public MyJpaUtil<T> isNull(Func1<T, ?> getFunc) {
        JpaConditionUtil.isNull(predicates, root, cb, LambdaUtil.getFieldName(getFunc));
        return this;
    }

    /**
     * 为空判定【字段 is not null】<br/>
     * 使用示例【.isNotNull(query::getName)】<br/>
     * 效果【name is not null】<br/>
     *
     * @param getFunc 字段的lambda函数
     * @return this
     */
    public MyJpaUtil<T> isNotNull(Func1<T, ?> getFunc) {
        JpaConditionUtil.isNotNull(predicates, root, cb, LambdaUtil.getFieldName(getFunc));
        return this;
    }

    /**
     * 小于等于判定【字段 <= 值】<br/>
     * 使用示例【.lessThanOrEqualTo(query::getAge)】<br/>
     * 效果【age <= 20】<br/>
     *
     * @param getFunc 字段与值的lambda函数,函数的返回值必须实现Comparable是可比较的
     * @param <V>     操作值的类型
     * @return this
     */
    public <V extends Comparable<? super V>> MyJpaUtil<T> lessThanOrEqualTo(Func0<V> getFunc) {
        JpaConditionUtil.lessThanOrEqualTo(predicates, root, cb, LambdaUtil.getFieldName(getFunc), getFunc.callWithRuntimeException());
        return this;
    }

    /**
     * 小于等于判定【字段 <= 值】<br/>
     * 使用示例【.lessThanOrEqualTo(UserEntity::getAge, 20)】<br/>
     * 效果【age <= 20】<br/>
     *
     * @param getFunc 字段的lambda函数
     * @param value   操作值,必须实现Comparable是可比较的
     * @param <V>     操作值的类型
     * @return this
     */
    public <V extends Comparable<? super V>> MyJpaUtil<T> lessThanOrEqualTo(Func1<T, V> getFunc, V value) {
        JpaConditionUtil.lessThanOrEqualTo(predicates, root, cb, LambdaUtil.getFieldName(getFunc), value);
        return this;
    }

    /**
     * 小于等于判定【字段 < 值】<br/>
     * 使用示例【.lessThan(query::getAge)】<br/>
     * 效果【age < 20】<br/>
     *
     * @param getFunc 字段与值的lambda函数,函数的返回值必须实现Comparable是可比较的
     * @param <V>     操作值的类型
     * @return this
     */
    public <V extends Comparable<? super V>> MyJpaUtil<T> lessThan(Func0<V> getFunc) {
        JpaConditionUtil.lessThan(predicates, root, cb, LambdaUtil.getFieldName(getFunc), getFunc.callWithRuntimeException());
        return this;
    }

    /**
     * 小于等于判定【字段 < 值】<br/>
     * 使用示例【.lessThan(UserEntity::getAge, 20)】<br/>
     * 效果【age < 20】<br/>
     *
     * @param getFunc 字段的lambda函数
     * @param value   操作值,必须实现Comparable是可比较的
     * @param <V>     操作值的类型
     * @return this
     */
    public <V extends Comparable<? super V>> MyJpaUtil<T> lessThan(Func1<T, V> getFunc, V value) {
        JpaConditionUtil.lessThan(predicates, root, cb, LambdaUtil.getFieldName(getFunc), value);
        return this;
    }

    /**
     * 小于等于判定【字段 >= 值】<br/>
     * 使用示例【.greaterThanOrEqualTo(query::getAge)】<br/>
     * 效果【age >= 20】<br/>
     *
     * @param getFunc 字段与值的lambda函数,函数的返回值必须实现Comparable是可比较的
     * @param <V>     操作值的类型
     * @return this
     */
    public <V extends Comparable<? super V>> MyJpaUtil<T> greaterThanOrEqualTo(Func0<V> getFunc) {
        JpaConditionUtil.greaterThanOrEqualTo(predicates, root, cb, LambdaUtil.getFieldName(getFunc), getFunc.callWithRuntimeException());
        return this;
    }

    /**
     * 小于等于判定【字段 >= 值】<br/>
     * 使用示例【.greaterThanOrEqualTo(UserEntity::getAge, 20)】<br/>
     * 效果【age >= 20】<br/>
     *
     * @param getFunc 字段的lambda函数
     * @param value   操作值,必须实现Comparable是可比较的
     * @param <V>     操作值的类型
     * @return this
     */
    public <V extends Comparable<? super V>> MyJpaUtil<T> greaterThanOrEqualTo(Func1<T, V> getFunc, V value) {
        JpaConditionUtil.greaterThanOrEqualTo(predicates, root, cb, LambdaUtil.getFieldName(getFunc), value);
        return this;
    }

    /**
     * 小于等于判定【字段 > 值】<br/>
     * 使用示例【.greaterThan(query::getAge)】<br/>
     * 效果【age > 20】<br/>
     *
     * @param getFunc 字段与值的lambda函数,函数的返回值必须实现Comparable是可比较的
     * @param <V>     操作值的类型
     * @return this
     */
    public <V extends Comparable<? super V>> MyJpaUtil<T> greaterThan(Func0<V> getFunc) {
        JpaConditionUtil.greaterThan(predicates, root, cb, LambdaUtil.getFieldName(getFunc), getFunc.callWithRuntimeException());
        return this;
    }

    /**
     * 小于等于判定【字段 > 值】<br/>
     * 使用示例【.greaterThan(UserEntity::getAge, 20)】<br/>
     * 效果【age > 20】<br/>
     *
     * @param getFunc 字段的lambda函数
     * @param value   操作值,必须实现Comparable是可比较的
     * @param <V>     操作值的类型
     * @return this
     */
    public <V extends Comparable<? super V>> MyJpaUtil<T> greaterThan(Func1<T, V> getFunc, V value) {
        JpaConditionUtil.greaterThan(predicates, root, cb, LambdaUtil.getFieldName(getFunc), value);
        return this;
    }

    /**
     * 小于等于判定【字段 in(值)】<br/>
     * 使用示例【.in(query::getId)】<br/>
     * 效果【id in(1,2,3)】<br/>
     *
     * @param getFunc 字段与值的lambda函数,函数的返回值必须实现Collection是一个集合
     * @return this
     */
    public <V extends Collection<?>> MyJpaUtil<T> in(Func0<V> getFunc) {
        JpaConditionUtil.in(predicates, root, LambdaUtil.getFieldName(getFunc), getFunc.callWithRuntimeException());
        return this;
    }

    /**
     * 小于等于判定【字段 in(值)】<br/>
     * 使用示例【.in(query::getId, userIds)】<br/>
     * 效果【id in(1,2,3)】<br/>
     *
     * @param getFunc 字段的lambda函数,
     * @param value   操作值,必须实现Collection是一个集合
     * @param <V>     操作值的类型
     * @param <E>     操作值的元素类型
     * @return this
     */
    public <E, V extends Collection<E>> MyJpaUtil<T> in(Func1<T, E> getFunc, V value) {
        JpaConditionUtil.in(predicates, root, LambdaUtil.getFieldName(getFunc), value);
        return this;
    }

    /**
     * 小于等于判定【字段 not in(值)】<br/>
     * 使用示例【.notIn(query::getId)】<br/>
     * 效果【id in(1,2,3)】<br/>
     *
     * @param getFunc 字段与值的lambda函数,函数的返回值必须实现Collection是一个集合
     * @param <V>     操作值的类型
     * @param <E>     操作值的元素类型
     * @return this
     */
    public <E, V extends Collection<E>> MyJpaUtil<T> notIn(Func0<V> getFunc) {
        JpaConditionUtil.notIn(predicates, root, cb, LambdaUtil.getFieldName(getFunc), getFunc.callWithRuntimeException());
        return this;
    }

    /**
     * 小于等于判定【字段 in(值)】<br/>
     * 使用示例【.notIn(query::getId, userIds)】<br/>
     * 效果【id not in(1,2,3)】<br/>
     *
     * @param getFunc 字段的lambda函数
     * @param value   操作值,必须实现Collection是一个集合
     * @param <V>     操作值的类型
     * @param <E>     操作值的元素类型
     * @return this
     */
    public <E, V extends Collection<E>> MyJpaUtil<T> notIn(Func1<T, E> getFunc, V value) {
        JpaConditionUtil.notIn(predicates, root, cb, LambdaUtil.getFieldName(getFunc), value);
        return this;
    }

    /**
     * 区间判定,不包含左右【字段 between startValue and endValue】<br/>
     * 使用示例【.between(query::getAge, 1, 20)】<br/>
     * 效果【age between 1 and 20】<br/>
     *
     * @param getFunc    字段的lambda函数
     * @param startValue 起始值
     * @param endValue   结束值
     * @param <V>        操作值必须为Comparable实现类,是可比较的
     * @return this
     */
    public <V extends Comparable<? super V>> MyJpaUtil<T> between(Func1<T, V> getFunc, V startValue, V endValue) {
        JpaConditionUtil.between(predicates, root, cb, LambdaUtil.getFieldName(getFunc), startValue, endValue);
        return this;
    }

    /**
     * 左右闭区间判定【字段 >= startValue and 字段 <= endValue】<br/>
     * 使用示例【.closedInterval(query::getAge, 1, 20)】<br/>
     * 效果【age >= 1 and age <= 20】<br/>
     *
     * @param getFunc    字段的lambda函数
     * @param startValue 起始值
     * @param endValue   结束值
     * @param <V>        操作值必须为Comparable实现类,是可比较的
     * @return this
     */
    public <V extends Comparable<? super V>> MyJpaUtil<T> closedInterval(Func1<T, V> getFunc, V startValue, V endValue) {
        JpaConditionUtil.closedInterval(predicates, root, cb, LambdaUtil.getFieldName(getFunc), startValue, endValue);
        return this;
    }

    /**
     * 左开右闭区间判定【字段 > startValue and 字段 <= endValue】<br/>
     * 使用示例【.openLeftAndCloseRight(query::getAge, 1, 20)】<br/>
     * 效果【age > 1 and age <= 20】<br/>
     *
     * @param getFunc    字段的lambda函数
     * @param startValue 起始值
     * @param endValue   结束值
     * @param <V>        操作值必须为Comparable实现类,是可比较的
     * @return this
     */
    public <V extends Comparable<? super V>> MyJpaUtil<T> openLeftAndCloseRight(Func1<T, V> getFunc, V startValue, V endValue) {
        JpaConditionUtil.openLeftAndCloseRight(predicates, root, cb, LambdaUtil.getFieldName(getFunc), startValue, endValue);
        return this;
    }

    /**
     * 左闭右开区间判定【字段 >= startValue and 字段 < endValue】<br/>
     * 使用示例【.closeLeftAndOpenRight(query::getAge, 1, 20)】<br/>
     * 效果【age >= 1 and age < 20】<br/>
     *
     * @param getFunc    字段的lambda函数
     * @param startValue 起始值
     * @param endValue   结束值
     * @param <V>        操作值必须为Comparable实现类,是可比较的
     * @return this
     */
    public <V extends Comparable<? super V>> MyJpaUtil<T> closeLeftAndOpenRight(Func1<T, V> getFunc, V startValue, V endValue) {
        JpaConditionUtil.closeLeftAndOpenRight(predicates, root, cb, LambdaUtil.getFieldName(getFunc), startValue, endValue);
        return this;
    }

    /**
     * 等于判定【字段 = 值】<br/>
     * 使用示例【.equal(user::getId)】<br/>
     * 效果【id = 1】<br/>
     *
     * @param getFunc 字段与值的lambda函数
     * @param <V>     操作值类型约束
     * @return this
     */
    public <V> MyJpaUtil<T> equal(Func0<V> getFunc) {
        JpaConditionUtil.equal(predicates, root, cb, LambdaUtil.getFieldName(getFunc), getFunc.callWithRuntimeException());
        return this;
    }

    /**
     * 等于判定【字段 = 值】<br/>
     * 使用示例【.equal(query::getId, 1)】<br/>
     * 效果【id = 1】<br/>
     *
     * @param getFunc 字段的lambda函数
     * @param value   操作值
     * @param <V>     操作值类型约束
     * @return this
     */
    public <V> MyJpaUtil<T> equal(Func1<T, V> getFunc, V value) {
        JpaConditionUtil.equal(predicates, root, cb, LambdaUtil.getFieldName(getFunc), value);
        return this;
    }

    /**
     * 等于判定【字段 != 值】<br/>
     * 使用示例【.notEqual(user::getId)】<br/>
     * 效果【id != 1】<br/>
     *
     * @param getFunc 字段与值的lambda函数
     * @param <V>     操作值类型约束
     * @return this
     */
    public <V> MyJpaUtil<T> notEqual(Func0<V> getFunc) {
        JpaConditionUtil.notEqual(predicates, root, cb, LambdaUtil.getFieldName(getFunc), getFunc.callWithRuntimeException());
        return this;
    }

    /**
     * 等于判定【字段 != 值】<br/>
     * 使用示例【.notEqual(query::getId, 1)】<br/>
     * 效果【id != 1】<br/>
     *
     * @param getFunc 字段的lambda函数
     * @param value   操作值
     * @param <V>     操作值类型约束
     * @return this
     */
    public <V> MyJpaUtil<T> notEqual(Func1<T, V> getFunc, V value) {
        JpaConditionUtil.notEqual(predicates, root, cb, LambdaUtil.getFieldName(getFunc), value);
        return this;
    }

    /**
     * 模式一中结束当前工具调用的方法并返回Predicate,该方法被@ProxyTab(useAgent = false)标记为在代理中直接调用
     *
     * @return p
     */
    @ProxyTab(useAgent = false)
    public Predicate builder() {
        return query.where(predicates.toArray(new Predicate[0])).getRestriction();
    }

    /**
     * Specification接口的toPredicate方法,在模式二中将通过Specification调用到次方法,该方法被@ProxyTab(useAgent = false)标记为在代理中直接调用
     *
     * @param root  r
     * @param query q
     * @param cb    c
     * @return p
     */
    @Override
    @ProxyTab(useAgent = false)
    public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        try {
            MyJpaUtil<T> jpa = MyJpaUtil.create(root, query, cb);
            for (MethodRecord record : methodRecords) {
                record.method.invoke(jpa, record.args);
            }
            return jpa.builder();
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 方法记录类,记录方法方法本身,方法参数
     */
    @Data
    @AllArgsConstructor
    private static class MethodRecord {
        private Method method;
        private Object[] args;
    }

    /**
     * 代理标记注解,将标记代理中如何处理方法
     */
    @Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    private @interface ProxyTab {
        /**
         * 不使用代理标记
         *
         * @return true:使用代理处理;false:代理中不做其他处理,直接调用
         */
        boolean useAgent() default true;

        /**
         * 禁止在代理中调用该方法
         *
         * @return true:禁止代理调用,在代理中调用会抛异常;false:允许代理调用
         */
        boolean disableProxyCall() default false;
    }

    /**
     * 代理处理器,在该处理器中将根据方法使用的ProxyTab标记情况对类进行相应的处理
     */
    private class AgentSimplification implements MethodInterceptor {
        /**
         * 代理处理实现方法
         *
         * @param obj    调用被代理方法的对象
         * @param method 当前方法
         * @param args   方法参数
         * @param proxy  代理方法
         * @return 返回方法的返回值
         * @throws Throwable 可能的可抛出异常
         */
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            ProxyTab tab = method.getAnnotation(ProxyTab.class);
            if (tab != null) {//加了代理标记,按代理标记的处理
                if (tab.useAgent()) {//标记说允许使用代理
                    methodRecords.add(new MethodRecord(method, args));
                } else {//正常调用方法
                    if (obj instanceof MyJpaUtil<?>) {//传递记录的方法
                        ((MyJpaUtil<?>) obj).setMethodRecords(methodRecords);
                    }
                    return proxy.invokeSuper(obj, args);
                }
                if (tab.disableProxyCall()) {//标记说禁止调用就抛异常
                    throw new RuntimeException("当前方法为禁止代理调用方法,请使用MyJpaUtil.create(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb)创建方式调用该方法");
                }
            } else {//没有加标记就先缓存,后续调用toPredicate时才曾用缓存
                methodRecords.add(new MethodRecord(method, args));
            }
            return obj;
        }
    }

    /**
     * 该构造器仅供动态代理调用
     */
    protected MyJpaUtil() {
        this.agentSimplification = new AgentSimplification();
    }

    /**
     * 内部构造器,当前工具实际的唯一创建方式
     *
     * @param root  r
     * @param query q
     * @param cb    c
     */
    private MyJpaUtil(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        this.root = root;
        this.query = query;
        this.cb = cb;
    }

    /**
     * 模式一中创建MyJpaUtil的静态方法
     *
     * @param root r
     * @param qu   q
     * @param cb   c
     * @param <T>  root中定义的实体类类型
     * @return this
     */
    public static <T> MyJpaUtil<T> create(Root<T> root, CriteriaQuery<?> qu, CriteriaBuilder cb) {
        return new MyJpaUtil<>(root, qu, cb);
    }

    /**
     * 模式二指定通过返回值指定泛型类型的创建方式
     *
     * @param <T> root中定义的实体类类型
     * @return this
     */
    @SuppressWarnings("unchecked")
    public static <T> MyJpaUtil<T> create() {
        MyJpaUtil<T> jpa = new MyJpaUtil<>();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(MyJpaUtil.class);
        enhancer.setCallback(jpa.agentSimplification);
        return (MyJpaUtil<T>) enhancer.create();
    }

    /**
     * 模式二通过class指定通过返回值指定泛型类型的创建方式
     *
     * @param <T> root中定义的实体类类型
     * @return this
     */
    @SuppressWarnings("unchecked")
    public static <T> MyJpaUtil<T> create(Class<T> ignore) {
        MyJpaUtil<T> jpa = new MyJpaUtil<>();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(MyJpaUtil.class);
        enhancer.setCallback(jpa.agentSimplification);
        return (MyJpaUtil<T>) enhancer.create();
    }

    /**
     * 重写toString方法简介debug时当前工具显示异常问题
     *
     * @return s
     */
    @Override
    @ProxyTab(useAgent = false)
    public String toString() {
        return "MyJpaUtil{" +
                "root=" + root +
                ", qu=" + query +
                ", cb=" + cb +
                ", predicates=" + predicates +
                ", methodRecords=" + methodRecords +
                '}';
    }

    /**
     * 获取Root,使用@ProxyTab(disableProxyCall = true)标记当前方法为禁止模式二调用
     *
     * @return Root
     */
    @ProxyTab(disableProxyCall = true)
    public Root<T> getRoot() {
        return root;
    }

    /**
     * 获取CriteriaQuery,使用@ProxyTab(disableProxyCall = true)标记当前方法为禁止模式二调用
     *
     * @return CriteriaQuery
     */
    @ProxyTab(disableProxyCall = true)
    public CriteriaQuery<?> getQuery() {
        return query;
    }

    /**
     * 获取CriteriaBuilder,使用@ProxyTab(disableProxyCall = true)标记当前方法为禁止模式二调用
     *
     * @return CriteriaBuilder
     */
    @ProxyTab(disableProxyCall = true)
    public CriteriaBuilder getCb() {
        return cb;
    }

    /**
     * 获取条件记录,使用@ProxyTab(disableProxyCall = true)标记当前方法为禁止模式二调用
     *
     * @return List<Predicate>
     */
    @ProxyTab(disableProxyCall = true)
    public List<Predicate> getPredicates() {
        return predicates;
    }

    /**
     * 放置方法记录,使用@ProxyTab(useAgent = false)标记当前方法为正常调用
     *
     * @param methodRecords 方法记录
     */
    @ProxyTab(useAgent = false)
    private void setMethodRecords(List<MethodRecord> methodRecords) {
        this.methodRecords = methodRecords;
    }
}

排序工具

import cn.hutool.core.lang.func.Func1;
import lombok.Getter;

/**
 * @Author: wanger
 * @Date: 2024/1/2 9:35
 * @Description: 自定义排序类调用参考示例【<pre>{@code
 *         List<UserEntity> list = userService.list(MyJpaUtil.create(UserEntity.class)
 *                 .equal(UserEntity::getStatus, DataStatus.NORMAL.getStatus())
 *                 //其他条件...
 *                 .order(Order.DESC(UserEntity::getCreatedTime), Order.ASC(UserEntity::getPhone),其他排序字段)
 *                 );
 *         }</pre>】
 */
@Getter
public class Order<T> {
    /**
     * 顺序排序标识
     */
    public static final String ASC = "ASC";
    /**
     * 倒序排序标识
     */
    public static final String DESC = "DESC";
    /**
     * 当前的排序标识
     */
    private final String sort;
    /**
     * 排序字段lambda方法,如【UserEntity::getAge】
     */
    private final Func1<T, ?> fieldFun;

    /**
     * 私有构造器,仅供内部ASC与DESC两个方法使用
     *
     * @param fieldFun 排序字段lambda方法,如【UserEntity::getAge】
     * @param sort     排序状态,ASC/DESC
     */
    private Order(Func1<T, ?> fieldFun, String sort) {
        this.fieldFun = fieldFun;
        this.sort = sort;
    }

    /**
     * 顺序排序方式,如【Order.ASC(UserEntity::getAge)】
     *
     * @param fieldFun 排序字段lambda方法,如【UserEntity::getAge】
     * @param <T>      调用者的泛型类型
     * @return 返回排序对象
     */
    public static <T> Order<T> ASC(Func1<T, ?> fieldFun) {
        return new Order<>(fieldFun, ASC);
    }

    /**
     * 顺序排序方式,如【Order.DESC(UserEntity::getAge)】
     *
     * @param fieldFun 排序字段lambda方法,如【UserEntity::getAge】
     * @param <T>      调用者的泛型类型
     * @return 返回排序对象
     */
    public static <T> Order<T> DESC(Func1<T, ?> fieldFun) {
        return new Order<>(fieldFun, DESC);
    }

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值