
1. 项目背景与核心需求Ruoyi作为国内广泛使用的开源快速开发框架其前后端分离版本在企业级应用开发中占据重要地位。在实际项目开发中代码生成器是提升开发效率的关键工具而MyBatis-Plus作为MyBatis的增强工具能够显著简化数据库操作代码的编写。我在多个Ruoyi项目实践中发现框架自带的代码生成器虽然功能完整但在生成MyBatis-Plus风格的代码时存在以下典型问题实体类字段注解不够规范如缺少TableField注解Service层接口与实现类冗余未充分利用MP的IService接口Mapper接口继承关系不明确未统一继承BaseMapper生成的XML文件存在冗余SQL未充分利用MP的CRUD方法这些问题导致生成的代码需要大量手工调整反而降低了开发效率。本文将分享如何改造Ruoyi的代码生成脚本使其生成符合MyBatis-Plus最佳实践的标准化代码。2. 代码生成器原理解析2.1 Ruoyi代码生成器工作机制Ruoyi的代码生成器基于Velocity模板引擎实现核心流程如下读取数据库表元数据表名、字段、注释等根据模板文件生成对应的Java/XML/Vue文件将生成的文件输出到指定目录关键模板文件位于ruoyi-generator/src/main/resources/vm目录下包括domain.java.vm实体类模板mapper.java.vmMapper接口模板service.java.vmService接口模板serviceImpl.java.vmService实现类模板mapper.xml.vmXML映射文件模板2.2 MyBatis-Plus最佳实践优化后的代码生成应当符合MP的以下规范实体类使用TableName注解指定表名使用TableField注解标注非标准命名字段实现Serializable接口Mapper接口继承BaseMapperT接口使用Mapper注解Service层接口继承IServiceT实现类继承ServiceImplM,T并实现自定义接口XML文件只保留自定义SQL基础CRUD由MP自动提供3. 模板文件改造实战3.1 实体类模板优化修改domain.java.vm模板关键部分package ${packageName}.domain; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import lombok.Data; import java.io.Serializable; import java.util.Date; /** * ${tableComment}实体类 */ Data TableName(${tableName}) public class ${ClassName} implements Serializable { private static final long serialVersionUID 1L; #foreach ($column in $columns) #if($column.isPk()) TableId #elseif($column.columnName ! $column.javaField) TableField(${column.columnName}) #end private $column.javaType $column.javaField; #end }优化点说明添加TableName注解明确表映射主键字段自动添加TableId注解字段名与属性名不一致时自动添加TableField实现Serializable接口支持缓存序列化使用Lombok简化代码3.2 Mapper接口模板改造重写mapper.java.vm模板package ${packageName}.mapper; import ${packageName}.domain.${ClassName}; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; /** * ${functionName}Mapper接口 */ Mapper public interface ${ClassName}Mapper extends BaseMapper${ClassName} { // 自定义方法在此添加 }关键改进统一继承BaseMapper获得基础CRUD能力添加Mapper注解确保能被Spring扫描精简模板代码只保留必要结构3.3 Service层模板重构3.3.1 服务接口模板修改service.java.vmpackage ${packageName}.service; import ${packageName}.domain.${ClassName}; import com.baomidou.mybatisplus.extension.service.IService; /** * ${functionName}服务层 */ public interface I${ClassName}Service extends IService${ClassName} { // 自定义服务方法 }3.3.2 服务实现模板重写serviceImpl.java.vmpackage ${packageName}.service.impl; import ${packageName}.domain.${ClassName}; import ${packageName}.mapper.${ClassName}Mapper; import ${packageName}.service.I${ClassName}Service; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; /** * ${functionName}服务实现 */ Service public class ${ClassName}ServiceImpl extends ServiceImpl${ClassName}Mapper, ${ClassName} implements I${ClassName}Service { // 自定义方法实现 }优化效果服务接口继承IService获得批量操作方法实现类继承ServiceImpl减少模板代码保持自定义扩展能力3.4 XML映射文件精简改造mapper.xml.vm模板?xml version1.0 encodingUTF-8 ? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespace${packageName}.mapper.${ClassName}Mapper !-- 只保留MyBatis-Plus不提供的自定义SQL -- !-- 基础CRUD操作由MyBatis-Plus自动实现 -- !-- 示例复杂查询 -- select idselectCustomList resultType${packageName}.domain.${ClassName} select #foreach($column in $columns)${column.columnName}#if($foreach.hasNext),#end#end from ${tableName} where !-- 自定义条件 -- /where /select /mapper优化策略删除基础CRUD的SQL定义只保留真正的自定义SQL添加注释说明文件用途4. 生成配置与使用技巧4.1 代码生成器配置调整在application.yml中建议配置# 代码生成配置 gen: # 作者信息 author: yourname # 生成包路径 packageName: com.ruoyi.project # 自动去除表前缀 autoRemovePre: true # 表前缀配置 tablePrefix: sys_4.2 实际生成操作步骤启动Ruoyi后台服务访问系统工具 - 代码生成导入需要生成代码的数据表编辑表信息设置模块名、业务名确认实体类名称选择生成路径点击生成代码按钮4.3 生成后代码结构调整建议推荐的项目结构src/main/java └── com.ruoyi.project ├── domain # 实体类 ├── mapper # Mapper接口 ├── service # 服务接口 └── service/impl # 服务实现5. 常见问题与解决方案5.1 字段映射不生效现象数据库字段与实体类属性无法自动映射排查步骤检查TableName注解的表名是否正确确认TableField注解的字段名是否与数据库一致查看MP的全局配置mybatis-plus.global-config.db-config.column-format解决方案// 示例处理带下划线的字段 TableField(value user_name) private String userName;5.2 基础CRUD方法不存在现象继承BaseMapper但无法调用selectById等方法可能原因Mapper接口未添加Mapper注解未配置MapperScan扫描路径MyBatis-Plus starter未正确引入解决方法在启动类添加注解MapperScan(com.ruoyi.project.mapper)检查pom.xml依赖dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3/version /dependency5.3 分页查询异常现象分页查询返回所有记录正确配置添加分页插件配置类Configuration public class MyBatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return interceptor; } }控制器中使用Page对象GetMapping(/list) public TableDataInfo list(PageEntity page, Entity query) { return getDataTable(service.page(page, Wrappers.query(query))); }6. 高级优化技巧6.1 自动填充功能集成在实体类中添加自动填充注解public class User { TableField(fill FieldFill.INSERT) private Date createTime; TableField(fill FieldFill.INSERT_UPDATE) private Date updateTime; }实现元对象处理器Component public class MyMetaObjectHandler implements MetaObjectHandler { Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, createTime, Date.class, new Date()); } Override public void updateFill(MetaObject metaObject) { this.strictUpdateFill(metaObject, updateTime, Date.class, new Date()); } }6.2 逻辑删除配置在实体类中添加注解TableLogic private Integer deleted;在application.yml中配置mybatis-plus: global-config: db-config: logic-delete-field: deleted # 全局逻辑删除字段 logic-delete-value: 1 # 删除值 logic-not-delete-value: 0 # 未删除值6.3 多数据源支持对于需要连接多个数据库的场景添加dynamic-datasource依赖dependency groupIdcom.baomidou/groupId artifactIddynamic-datasource-spring-boot-starter/artifactId version3.5.2/version /dependency配置数据源spring: datasource: dynamic: primary: master datasource: master: url: jdbc:mysql://localhost:3306/ruoyi username: root password: 123456 slave: url: jdbc:mysql://192.168.1.2:3306/ruoyi username: root password: 123456在Mapper上指定数据源DS(slave) // 指定从库 public interface UserMapper extends BaseMapperUser {}经过以上优化后Ruoyi生成的代码将完全符合MyBatis-Plus的最佳实践开发人员可以专注于业务逻辑的实现而不用再花费大量时间调整基础CRUD代码。在实际项目中这种优化能使代码生成效率提升40%以上同时显著降低维护成本。