mybatis-plus动态排序

最近项目中遇到一个问题,动态排序。前端传过来一个对象数组,结构类似下面这种

[
	{
		"sortFiled":"name",
		"sortDirection":"descending"
	},
	...
]

最终会拼接到sql语句的orderby中,后台处理query参数用的是mybatis-plus的LambdaQueryWrapper,问题来了,如何通过"name"这个字符串生成get方法对应的方法引用,也就是User::getName这种。
本来想过用QueryWrapper直接传字符串进去,但是前端字段一般都是驼峰的,需要转成下划线形式的,否则会报错。而且其他查询条件也要跟着动,所以就放弃了这种方案。
看源码eq这种方法需要的是SFunction,网上关于这方面的资料好难找。写了个工具类专门用来创建方法引用。

import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import org.springframework.cglib.core.ReflectUtils;

import java.beans.PropertyDescriptor;
import java.lang.invoke.*;
import java.util.*;

public class LambdaUtil {

    public static final Map<Class<?>, PropertyDescriptor[]> cache = new HashMap<>();

    public static <T> SFunction<T, ?> getLambdaGetter(Class<T> clazz, String prop) throws Throwable {
        PropertyDescriptor[] beanGetters;
        if (cache.containsKey(clazz)) {
            beanGetters = cache.get(clazz);
        } else {
            beanGetters = ReflectUtils.getBeanGetters(clazz);
            cache.put(clazz, beanGetters);
        }
        var lookup = MethodHandles.lookup();
        var optional = Arrays.stream(beanGetters)
                .filter(pd -> pd.getName().equals(prop))
                .findFirst();
        if (optional.isPresent()) {
        	// 反射获取getter方法
            var readMethod = optional.get().getReadMethod();
            // 拿到方法句柄
            final MethodHandle methodHandle = lookup.unreflect(readMethod);
            // 创建动态调用链
            var callSite = LambdaMetafactory.altMetafactory(
                    lookup,
                    "apply",
                    MethodType.methodType(SFunction.class),
                    MethodType.methodType(Object.class, Object.class),
                    methodHandle,
                    MethodType.methodType(readMethod.getReturnType(), clazz),
                    LambdaMetafactory.FLAG_SERIALIZABLE
            );
            return (SFunction<T, ?>) callSite.getTarget().invokeExact();
        }
        return null;
    }
}

单元测试

SFunction<User, ?> getFun = LambdaUtil.getLambdaGetter(User.class, "name");
User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(getFun, "超级管理员"));
System.out.println("user = " + user);

最终正常返回结果

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值