MyBatis-Plus 动态字段映射工具:一行代码实现字段名动态转换
痛点描述
在使用 MyBatis-Plus 开发时,我们经常遇到这样的场景:
// 前端传参:field=name, values=["张三","李四"]// 我们需要动态查询:WHERE name IN ('张三','李四')// 传统方式 - 硬编码queryWrapper.in("name",values);// 字段写死了,无法动态变化// Lambda方式 - 编译期固定queryWrapper.in(User::getName,values);// 同样无法动态变化如果需求是前端动态传递字段名,以上两种方式都无能为力。比如:
- 用户可选择按
姓名、工号、部门等不同字段批量查询 - 后台配置中心需要动态指定筛选字段
- 报表工具需要根据配置动态分组
此时,我们需要一个工具:传入字段名字符串,返回对应的数据库列名。
解决方案
DynamicFieldUtil工具类,通过 MyBatis-Plus 的TableInfoHelper,实现实体类字段名到数据库列名的动态映射。
核心代码
importcom.baomidou.mybatisplus.core.metadata.TableInfo;importcom.baomidou.mybatisplus.core.metadata.TableInfoHelper;importcom.baomidou.mybatisplus.core.metadata.TableFieldInfo;importjava.util.ArrayList;importjava.util.List;/** * MyBatis-Plus 动态字段映射工具 * 根据实体类字段名获取数据库列名,支持 @TableField 注解自动映射 * * @author Your Name * @since 2026-01-01 */publicclassDynamicFieldUtil{/** * 获取数据库列名 * * @param entityClass 实体类 Class(如 User.class) * @param propertyName 实体类字段名(如 "userName") * @return 数据库列名(如 "user_name"),找不到返回 null */publicstaticStringgetDbColumn(Class<?>entityClass,StringpropertyName){TableInfotableInfo=TableInfoHelper.getTableInfo(entityClass);if(tableInfo==null){returnnull;}// 1. 检查是否为主键if(tableInfo.getKeyProperty().equals(propertyName)){returntableInfo.getKeyColumn();}// 2. 遍历普通字段for(TableFieldInfofieldInfo:tableInfo.getFieldList()){if(fieldInfo.getProperty().equals(propertyName)){returnfieldInfo.getColumn();}}returnnull;}/** * 获取数据库列名(带异常提示) * * @param entityClass 实体类 * @param propertyName 字段名 * @return 数据库列名 * @throws IllegalArgumentException 字段不存在时抛出 */publicstaticStringgetDbColumnOrThrow(Class<?>entityClass,StringpropertyName){StringdbColumn=getDbColumn(entityClass,propertyName);if(dbColumn==null){List<String>availableFields=getAvailableFields(entityClass);thrownewIllegalArgumentException(String.format("实体类 %s 中找不到字段 '%s',可用字段: %s",entityClass.getSimpleName(),propertyName,String.join(", ",availableFields)));}returndbColumn;}/** * 获取实体类所有可用字段名 */publicstaticList<String>getAvailableFields(Class<?>entityClass){TableInfotableInfo=TableInfoHelper.getTableInfo(entityClass);if(tableInfo==null){returnnewArrayList<>();}List<String>fields=newArrayList<>();fields.add(tableInfo.getKeyProperty());// 主键tableInfo.getFieldList().forEach(f->fields.add(f.getProperty()));returnfields;}}使用示例
1. 基础用法
@RestControllerpublicclassUserController{@AutowiredprivateUserServiceuserService;@GetMapping("/search")publicResultsearch(@RequestParamStringfield,@RequestParamList<String>values){// 1. 获取数据库列名StringdbColumn=DynamicFieldUtil.getDbColumn(User.class,field);if(dbColumn==null){returnResult.error("不支持的字段: "+field);}// 2. 构建查询QueryWrapper<User>wrapper=newQueryWrapper<>();wrapper.in(dbColumn,values);returnResult.success(userService.list(wrapper));}}2. 带异常提示
@GetMapping("/search")publicResultsearch(@RequestParamStringfield,@RequestParamList<String>values){try{// 字段不存在会自动抛异常,并列出所有可用字段StringdbColumn=DynamicFieldUtil.getDbColumnOrThrow(User.class,field);QueryWrapper<User>wrapper=newQueryWrapper<>();wrapper.in(dbColumn,values);returnResult.success(userService.list(wrapper));}catch(IllegalArgumentExceptione){returnResult.error(e.getMessage());}}3. 支持 @TableField 注解
@Data@TableName("t_user")publicclassUser{@TableId("user_id")privateLongid;@TableField("user_name")privateStringname;// 前端传 "name",自动映射到数据库 "user_name"@TableField("user_age")privateIntegerage;}// 前端调用GET/search?field=name&values=张三,李四// 自动转换为 SQLSELECT*FROMt_userWHEREuser_nameIN('张三','李四')注意事项
1. 字段名安全性
- 工具只做字段名转换,不涉及 SQL 拼接,无 SQL 注入风险
- 建议对传入的字段名做白名单校验,或使用
getDbColumnOrThrow方法
2. 异常处理建议
推荐在全局异常处理器中统一处理:IllegalArgumentException.class)
参考文档
- MyBatis-Plus TableInfoHelper
- MyBatis-Plus @TableField
- MyBatis-Plus QueryWrapper
总结
DynamicFieldUtil工具类通过20 行代码解决了动态字段映射的核心问题:
一行代码:获取数据库列名
自动处理: @TableField 注解
友好提示:字段不存在时列出所有可用字段
零额外依赖:基于 MyBatis-Plus 官方 API
让你的查询条件真正实现动态化,代码更灵活、更简洁!