一、问题场景:
在使用MyBatisPlus操作MySql数据库时,对于查找的字段名可以以类似下面的写法:
queryWrapper.eq(Dict::getId, 1);
这样写的好处就在于一来不会写错,而用字符串形式的属性名容易写错,二来如果修改属性名或者删除属性后,也能在编译阶段就发现问题而不是把问题留到运行阶段。
但是在用MongoDBTemplate操作Mongo数据时,却不支持这种写法,经过研究,找到两种类似的写法。一种是引入lombok依赖包,通过FieldNameConstants注解的方式,另一种则是通过java反射的方式;
二、lombok方法:
1、首先引入依赖:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
</dependency>
2、实体类上添加注解:
@FieldNameConstants
public class User {
private Long userId;
private String userName;
private String userAddr;
private Integer userAge;
//............
}
3、mongo查找时使用:
Criteria criteria = Criteria.where(User.Fields.userAge).gt(30);
return mongoTemplate.find(new Query(criteria), User.class);
三、反射的方式:
1、通过反射实现获取属性名的方法:
// 拿到getter方法对应的属性名称
public static <T> String getFieldName(PropertyFunc<T, ?> field) {
Class<?> clazz = field.getClass();
try {
Method method = clazz.getDeclaredMethod("writeReplace");
method.setAccessible(true);
SerializedLambda lambda = (SerializedLambda) method.invoke(field);
return uncapitalize(lambda.getImplMethodName());
} catch (Exception e) {
if (!Object.class.isAssignableFrom(clazz.getSuperclass())) {
return getFieldName(field);
}
throw new RuntimeException("属性不存在");
}
}
// 去掉方法的“get/is”前缀,首字母小写
private static String uncapitalize(String str) {
if (StringUtils.isBlank(str) || str.length() < 4) {
return str;
}
String fieldName = str.startsWith("get") ?
str.substring(3) : str.startsWith("is") ? str.substring(2) : str;
return CharSequenceUtil.lowerFirst(fieldName);
}
2、使用:
Criteria criteria = Criteria.where(getFieldName(User::getUserAge)).gt(30);
return mongoTemplate.find(new Query(criteria), User.class);