Backend Development 4 min read

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.

Java Captain
Java Captain
Java Captain
Automatic Construction of MyBatis-Plus QueryWrapper Using Reflection and Generics

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 范型 * @return 创建好的wrapper */ public static QueryWrapper createWrapper(Object param) { QueryWrapper 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.

JavaReflectiongenericsORMMyBatis-PlusQueryWrapper
Java Captain
Written by

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.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.