Automatic Construction of MyBatis-Plus QueryWrapper Using Reflection and Generics
This article describes a utility method that leverages Java reflection and generics to automatically generate a MyBatis-Plus QueryWrapper from a DTO, handling field‑name mapping, type‑specific query conditions, and camel‑to‑snake case conversion for seamless database queries.
Background : When building complex query conditions with MyBatis-Plus Wrapper, developers often spend excessive time manually writing each condition and may introduce errors.
Idea : Provide a generic method that inspects a parameter object's fields via reflection, determines the appropriate query operation based on the field type, and returns a correctly typed QueryWrapper instance.
Implementation : The method iterates over all declared fields of the supplied object, skips null values, resolves the database column name by checking for a @TableField annotation or converting camelCase to snake_case, and applies the appropriate condition ( like, eq, in, between) based on the field’s Java type. Helper code for camel‑to‑snake conversion is also included.
/**
* 创建对应的wrapper
* @param param 参数对象
* @param <T> 范型
* @return 创建好的wrapper
*/
public static <T> QueryWrapper<T> createWrapper(Object param) {
QueryWrapper<T> wrapper = new QueryWrapper<>();
Class<?> dataClass = param.getClass();
try {
for (Field field : dataClass.getDeclaredFields()) {
field.setAccessible(true);
//获取字段类型和字段值
Class<?> type = field.getType();
Object value = field.get(param);
if (value == null) {
continue;
}
//将字段名转为数据库中的字段名
String fieldName;
TableField tableFieldAnnotation = field.getAnnotation(TableField.class);
if (tableFieldAnnotation != null) {
fieldName = tableFieldAnnotation.value();
} else {
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, (List<?>)value);
} else if (type == Between.class) {
Between val = (Between) value;
wrapper.between(fieldName, val.getStart(), val.getEnd());
} else {
wrapper.eq(fieldName, value);
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return wrapper;
}
/**
* 将驼峰命名法的字段名转为下划线隔开的形式
* @param input 驼峰命名法的字段名
* @return 下划线隔开的数据库字段名
*/
private 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();
}Test : After invoking createWrapper with a DTO instance, the generated QueryWrapper contains all non‑null fields mapped to the correct database columns and query operators, as demonstrated by the accompanying screenshots.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Captain
Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
