前几天写一个有几十个字段的查询wrapper,写得我心烦意乱。然后就琢磨了一下能不能只传一个条件类对像就能创建对应的wrapper。去看了下mybatis-plus的文档没看到合适的api,有一个创建wrapper时传入实体类的,但那个的查询条件都是eq不太使用。所以我就自己用反射和泛型写了一个创建wrapper的方法,可以根据传入的dto对象和泛型来返回对应的wrapper。
大概思路就是根据泛型创建一个对应类型的QueryWrapper,使用反射来读取遍历dto的属性来作为查询条件。
public static <T> QueryWrapper<T> createWrapper(Object dto){
QueryWrapper<T> wrapper = new QueryWrapper<>();
Class<?> dataClass = data.getClass();
try {
for (Field field : dataClass.getDeclaredFields()) {
//如果属性没有用private修饰的话这行可以不用
field.setAccessible(true);
//获取字段类型和字段值
Class<?> type = field.getType();
Object value = field.get(data);
if (value == null){
continue;
}
//将字段名转为数据库中的字段名
String fieldName;
//获取一下属性上的@TableField注解,优先使用注解的value作为字段名
TableField tableFieldAnnotation = field.getAnnotation(TableField.class);
if (tableFieldAnnotation != null) {
fieldName = tableFieldAnnotation.value();
}else{
//若没有TableField注解则将获取到的字段名转换一下,从驼峰命名改为下划线的形式
fieldName = convertToSnakeCase(field.getName());
}
//下面这部分定义字段的查询方式就看各自的习惯了,下面是我经常用的
//根据字段的类型来选择不同的查询方式
if (type == String.class) {
wrapper.like(fieldName, value);
}else if (type == Long.class){
wrapper.eq(fieldName, value);
}else if (type == List.class){
wrapper.in(fieldName, (ArrayList<?>)value);
}else if (type == TimeParam.class){
TimeUtils val= (TimeParam)value;
wrapper.between(fieldName, val.getStart(), val.getEnd());
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return wrapper;
}
/**
* 将驼峰命名法的字段名转为下划线隔开的形式
* @param input
* @return
*/
public static String convertToSnakeCase(String input) {
StringBuilder output = new StringBuilder();
for (int i = 0; i < input.length(); i++) {
char ch = input.charAt(i);
if (Character.isUpperCase(ch)) {
if (i > 0) {
output.append(StrPool.C_UNDERLINE);
}
output.append(Character.toLowerCase(ch));
} else {
output.append(ch);
}
}
return output.toString();
}
欧了,希望这个方法能帮到各位