首页 / 资讯中心 / 文章详情

若依集成Mybatis-Plus代码生成器实战:DTO校验与Controller适配

若依集成Mybatis-Plus代码生成器实战:DTO校验与Controller适配 ★ FEATURED ARTICLE
简介本资源是面向Java全栈开发者与若依平台二次开发者的工程实践型集成方案聚焦于在若依前后端分离版VueSpring Boot中高效集成Mybatis-Plus代码生成器解决重复编写CRUD基础代码、数据库表变更后手动同步困难等典型开发痛点。压缩包共2010个文件主体为1605份Markdown文档含环境配置说明、生成器使用指南、常见问题排查、251个Java类覆盖Entity、Mapper、Service及Controller模板、101个JS前端适配脚本辅以31个XML配置与2个SQL建表脚本整体71.55MB结构完整、开箱即用。已有538人学习下载资源包含《若依环境使用手册.docx》等实操指引目录组织清晰支持按模块快速定位生成逻辑、自定义模板及前后端联调要点可直接用于企业级项目快速搭建与迭代维护。1. 若依前后端分离版集成Mybatis-Plus代码生成器为什么你改了三遍模板还是生成不出带DTO和校验注解的Controller在某高校实验室做教务系统二期时A同学花两天配通若依RuoYi-Vue前后端分离版的数据库连接第三天兴冲冲点开「代码生成」菜单——结果生成的Controller里连Valid都没有ServiceImpl里还硬编码着new Date()DTO字段全是String类型连Long id都变成了String id。这不是个例我去年帮三个团队落地若依项目87%的首次集成失败都卡在Mybatis-Plus代码生成器与若依原有生成逻辑的冲突上而不是SQL写错或依赖没引对。根本原因在于若依自带的生成器走的是Velocity模板自定义Java类路径扫描的老路而Mybatis-Plus的AutoGenerator默认只认DataSourceConfigPackageConfig两者对“包结构语义”“字段类型映射规则”“校验注解注入时机”的理解完全错位。本文不讲Mybatis-Plus基础语法也不复述若依部署流程而是聚焦一个具体动作——如何让Mybatis-Plus的CodeGenerator真正接管若依的代码生成入口且生成物能直接进Git、过SonarQube、被前端Vue组件无感调用。适合已跑通若依基础功能、正卡在“增删改查重复劳动”瓶颈的后端开发者。2. 拆解若依生成链路先停掉原生生成器再定位Mybatis-Plus可插拔节点若依的代码生成不是黑匣子它的核心是GenController.java里的genCode方法该方法最终调用GenUtils.generatorCode而后者又委托给VelocityInitializer.java加载.vm模板。Mybatis-Plus的生成器则完全不同它通过AutoGenerator组装DataSourceConfig、PackageConfig、StrategyConfig、TemplateConfig四大配置块最后执行execute()触发模板渲染。二者不兼容的根源在于若依把“表名→Java类名”的转换逻辑写死在GenUtils.java的getClassName方法里而Mybatis-Plus默认用NamingStrategy.underline_to_camel且允许用户自定义TableNameConverter。强行混合会导致生成的Mapper接口名和XML文件名不匹配比如表sys_user生成SysUserMapper.java却去找SysUserMapper.xml或者DTO字段类型全崩成Object。2.1 停用若依原生生成器三步物理隔离提示不要试图在若依源码里魔改GenController那会污染升级路径。我们采用“入口劫持模块替换”策略。第一步注释掉若依前端路由中代码生成菜单的访问权限。打开ruoyi-ui/src/router/index.js找到{ path: /tool/gen, component: () import(/views/tool/gen/index), name: Gen, meta: { title: 代码生成, icon: code } }这一行在前面加//注释掉。这一步不是删除而是让前端彻底收不到该路由避免用户误点旧入口。第二步移除若依后端的生成器依赖。打开ruoyi-admin/pom.xml找到包含artifactIdruoyi-common/artifactId且classifiergen/classifier的依赖项通常在profiles里整段删除。若依的ruoyi-common-gen模块封装了所有Velocity模板和工具类留着它会和Mybatis-Plus的模板引擎抢资源。第三步确认ruoyi-admin模块的application.yml中没有gen:开头的配置块。若依旧版会在yml里定义gen.author、gen.email等这些参数对Mybatis-Plus无效且可能被GenUtils读取后干扰包路径计算。# 验证是否清理干净在ruoyi-admin目录下执行 mvn clean compile -Dmaven.test.skiptrue | grep -i gen\|velocity # 正常输出应无任何含gen或velocity的编译日志2.2 定位Mybatis-Plus可插拔节点四个必须重写的配置对象Mybatis-Plus的AutoGenerator本质是个配置组装器其扩展性全部落在四个Config类上。若依的包结构约定com.ruoyi.project.system.*和Mybatis-Plus的默认策略com.baomidou.mybatisplus.generator.config.*必须对齐否则生成的类会散落在错误包下Spring Boot启动时报ClassNotFoundException。DataSourceConfig若依用DruidMybatis-Plus需显式指定driverName为com.alibaba.druid.pool.DruidDataSource而非HikariCP的默认值PackageConfig这是最关键的冲突点。若依要求Controller在com.ruoyi.project.system.controller而Mybatis-Plus默认生成到com.example.demo.controller。必须重写setParent(com.ruoyi)并手动拼接setModuleName(project.system)StrategyConfig若依的表前缀是sys_但Mybatis-Plus的setTablePrefix(sys_)只影响类名去前缀不影响XML中的namespace。必须额外调用setRestControllerStyle(true)启用REST风格否则生成的Controller没有RestControllerTemplateConfig若依的模板是.vmMybatis-Plus默认用.ftl。我们必须指定setController(templates/mybatis-plus/controller.java.vm)且该路径必须是src/main/resources/templates/下的相对路径。注意TemplateConfig中的controller.java.vm不能直接用Mybatis-Plus官方模板因为若依的Controller需要继承BaseController、注入ISysUserService等特定Bean而官方模板只生成裸RestController。我们将在第4章提供适配后的模板。3. 构建可落地的Mybatis-Plus生成器从零手写Config类与启动入口现在开始构建真正能跑通的生成器。不要用网上流传的“一键替换jar包”方案——那种方案把AutoGenerator塞进PostConstruct里导致每次启动都生成一遍代码污染Git历史。我们要的是按需触发、路径可控、模板可维护的方案。3.1 创建独立生成模块ruoyi-generator在ruoyi根目录下新建模块ruoyi-generator其pom.xml仅保留必要依赖!-- ruoyi-generator/pom.xml -- dependencies dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-generator/artifactId version3.5.3.1/version !-- 注意若依3.8.x对应MP 3.5.x勿升到4.x -- /dependency dependency groupIdorg.freemarker/groupId artifactIdfreemarker/artifactId version2.3.32/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency !-- 不引入spring-boot-starter-web避免与ruoyi-admin冲突 -- /dependencies关键点不引入任何Spring Boot Starter。生成器是纯Java工具不需要Web容器。这样能彻底规避与若依主应用的Bean冲突。3.2 手写GeneratorConfig精准控制包路径与命名策略创建ruoyi-generator/src/main/java/com/ruoyi/generator/GeneratorConfig.java这是整个集成的核心。它必须解决三个若依特有需求① 表名sys_user→ Controller类名SysUserController去掉sys_前缀② 字段user_name→ DTO属性private String userName下划线转驼峰③ 生成的DTO必须带NotBlank(message用户名不能为空)等JSR-303注解。// ruoyi-generator/src/main/java/com/ruoyi/generator/GeneratorConfig.java public class GeneratorConfig { // 数据库连接信息从ruoyi-admin/application.yml复制 private static final String URL jdbc:mysql://localhost:3306/ry-cloud?useUnicodetruecharacterEncodingutf8zeroDateTimeBehaviorconvertToNulluseSSLtrueserverTimezoneGMT%2B8; private static final String USERNAME root; private static final String PASSWORD 123456; public static AutoGenerator createGenerator(String... tableNames) { AutoGenerator mpg new AutoGenerator(); // 1. 数据源配置 DataSourceConfig dsc new DataSourceConfig(); dsc.setUrl(URL); dsc.setDriverName(com.mysql.cj.jdbc.Driver); // 若依3.8用MySQL 8驱动 dsc.setUsername(USERNAME); dsc.setPassword(PASSWORD); mpg.setDataSource(dsc); // 2. 全局配置 GlobalConfig gc new GlobalConfig(); String projectPath System.getProperty(user.dir) /ruoyi-generator; gc.setOutputDir(projectPath /src/main/java); // 生成到本模块java目录 gc.setAuthor(ruoyi); gc.setOpen(false); // 生成后不自动打开文件夹 gc.setSwagger2(true); // 启用Swagger注解 gc.setFileOverride(true); // 覆盖已有文件开发期必需 mpg.setGlobalConfig(gc); // 3. 包配置严格对齐若依约定 PackageConfig pc new PackageConfig(); pc.setParent(com.ruoyi); // 父包名 pc.setModuleName(project.system); // 模块名拼出com.ruoyi.project.system pc.setController(controller); pc.setEntity(domain); pc.setMapper(mapper); pc.setXml(mapper.xml); pc.setService(service); pc.setServiceImpl(service.impl); mpg.setPackageInfo(pc); // 4. 策略配置解决若依前缀与驼峰问题 StrategyConfig strategy new StrategyConfig(); strategy.setNaming(NamingStrategy.underline_to_camel); // 表名、字段名转驼峰 strategy.setColumnNaming(NamingStrategy.underline_to_camel); strategy.setSuperEntityClass(com.ruoyi.common.core.domain.BaseEntity); // 继承若依基类 strategy.setEntityLombokModel(true); // 用Lombok strategy.setRestControllerStyle(true); // 生成RestController strategy.setControllerMappingHyphenStyle(true); // URL路径用短横线 strategy.setTablePrefix(sys_); // 去掉sys_前缀但保留XML中namespace为sys_user strategy.setInclude(tableNames); // 指定生成哪些表 mpg.setStrategy(strategy); // 5. 模板配置指向自定义模板 TemplateConfig tc new TemplateConfig(); tc.setController(/templates/mybatis-plus/controller.java.vm); tc.setEntity(/templates/mybatis-plus/entity.java.vm); tc.setMapper(/templates/mybatis-plus/mapper.java.vm); tc.setXml(/templates/mybatis-plus/mapper.xml.vm); tc.setService(/templates/mybatis-plus/service.java.vm); tc.setServiceImpl(/templates/mybatis-plus/serviceImpl.java.vm); mpg.setTemplate(tc); return mpg; } }参数说明setTablePrefix(sys_)是玄学点——它只影响Java类名SysUser不影响XML的namespace仍是com.ruoyi.project.system.mapper.SysUserMapper。若依的SqlSessionTemplate依赖这个完整路径所以不能动。setSuperEntityClass必须指向若依的BaseEntity否则生成的Entity缺少createBy、createTime等审计字段。3.3 编写启动类支持命令行传参避免硬编码表名创建ruoyi-generator/src/main/java/com/ruoyi/generator/CodeGeneratorApp.java用main方法接收表名参数这样运维同事只需java -jar generator.jar sys_user,sys_role就能生成// ruoyi-generator/src/main/java/com/ruoyi/generator/CodeGeneratorApp.java public class CodeGeneratorApp { public static void main(String[] args) { if (args.length 0) { System.err.println(Usage: java -jar generator.jar table1,table2,table3); System.exit(1); } String[] tables args[0].split(,); AutoGenerator mpg GeneratorConfig.createGenerator(tables); mpg.execute(); // 执行生成 System.out.println(✅ 代码生成完成生成路径 System.getProperty(user.dir) /ruoyi-generator/src/main/java); } }打包命令cd ruoyi-generator mvn clean package -Dmaven.test.skiptrue # 生成 target/ruoyi-generator-1.0-SNAPSHOT.jar血泪经验mpg.execute()必须放在main里不能放PostConstruct。曾有团队把它塞进ruoyi-admin的某个Component里结果每次重启服务都重新生成Git提交记录里全是generated xxx.javaCode Review直接崩溃。4. 适配若依的FreeMarker模板让生成的Controller能直接编译运行Mybatis-Plus官方模板生成的Controller是“裸”的而若依的Controller必须满足三个硬性条件① 继承BaseController② 注入对应Service如ISysUserService③ 方法返回AjaxResult而非R。直接套用官方模板会导致编译报错。我们必须重写controller.java.vm。4.1 创建模板目录与基础结构在ruoyi-generator/src/main/resources/下创建目录templates/mybatis-plus/放入以下5个.vm文件内容精简只列关键差异controller.java.vmentity.java.vmmapper.java.vmmapper.xml.vmservice.java.vm注意serviceImpl.java.vm和entity.java.vm可沿用Mybatis-Plus官方模板因为若依的BaseService和BaseEntity已覆盖了通用逻辑无需大改。4.2 重写controller.java.vm注入Service与返回AjaxResult这是最易翻车的部分。官方模板生成RestController RequestMapping(/sys/user) public class SysUserController { Autowired private ISysUserService sysUserService; PostMapping public R add(RequestBody SysUser sysUser) { ... } }而若依要求RestController RequestMapping(/system/user) public class SysUserController extends BaseController { Autowired private ISysUserService sysUserService; PostMapping public AjaxResult add(Valid RequestBody SysUser sysUser) { if (sysUserService.insertUser(sysUser) 0) { return success(); } return error(); } }关键差异点RequestMapping路径必须是/system/user若依网关路由规则不是/sys/user必须extends BaseController否则success()、error()方法找不到Valid必须存在且RequestBody前要加否则JSR-303校验不生效Service方法名要匹配若依规范如insertUser而非save。以下是controller.java.vm的核心片段省略import和class声明package ${package.Controller}; import ${package.Entity}.${entity}; import ${package.Service}.${service}; import ${package.Service}.impl.${serviceImpl}; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.page.TableDataInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import java.util.List; /** * ${table.comment!}控制器 */ RestController RequestMapping(/system/${package.ModuleName?replace(project., )?replace(., /)}/${controllerName?uncap_first}) public class ${controllerName} extends BaseController { Autowired private ${service} ${objectName?uncap_first}Service; /** * 查询${table.comment!}列表 */ GetMapping(/list) public TableDataInfo list(${entity} ${objectName?uncap_first}) { startPage(); List${entity} list ${objectName?uncap_first}Service.select${entity}List(${objectName?uncap_first}); return getDataTable(list); } /** * 新增${table.comment!} */ PostMapping public AjaxResult add(Valid RequestBody ${entity} ${objectName?uncap_first}) { return toAjax(${objectName?uncap_first}Service.insert${entity}(${objectName?uncap_first})); } /** * 修改${table.comment!} */ PutMapping public AjaxResult edit(Valid RequestBody ${entity} ${objectName?uncap_first}) { return toAjax(${objectName?uncap_first}Service.update${entity}(${objectName?uncap_first})); } /** * 删除${table.comment!} */ DeleteMapping(/{${table.pkColumns[0].name}}) public AjaxResult remove(PathVariable(${table.pkColumns[0].name}) Long ${table.pkColumns[0].name}) { return toAjax(${objectName?uncap_first}Service.delete${entity}ById(${table.pkColumns[0].name})); } }逻辑说明/system/${package.ModuleName?replace(project., )?replace(., /)}这段FreeMarker表达式把project.system转成system确保URL路径符合若依网关规则toAjax()是若依BaseController提供的方法将int返回值如1表示成功转为AjaxResult.success()select${entity}List等方法名由若依的ISysUserService接口定义生成器必须调用这些约定方法而非Mybatis-Plus的list()。4.3 重写entity.java.vm添加JSR-303校验注解与若依审计字段若依的Entity必须继承BaseEntity且每个字段需根据数据库约束自动加NotBlank、Size、Email等注解。我们在entity.java.vm中加入字段级校验逻辑#list table.fields as field #if field.keyFlag field.keyIdentityFlag TableId(value ${field.name}, type IdType.AUTO) #else TableField(${field.name}) /#if #-- 根据字段类型和约束自动加注解 -- #if field.type String #if field.columnKey PRI || field.columnKey UNI NotBlank(message ${field.comment}不能为空) #elseif field.length?number 0 field.length?number 50 Size(max ${field.length?number}, message ${field.comment}长度不能超过${field.length?number}个字符) /#if #elseif field.type Long || field.type Integer #if field.columnKey PRI NotNull(message ${field.comment}不能为空) /#if /#if private ${field.type} ${field.propertyName}; /#list参数说明field.columnKey取值为PRI主键、UNI唯一索引、MUL普通索引我们只对主键和唯一索引字段加NotBlank避免过度校验field.length来自数据库varchar(32)的32用于生成Size。这比手动写注解快10倍且保证前后端校验一致。5. 避坑指南生成后编译失败、运行报错、Git冲突的5个真实场景集成过程中的坑90%集中在“生成物与若依运行时环境不兼容”。以下是我在三个项目中踩过的血泪坑按发生频率排序5.1 现象生成的Controller编译报错“cannot find symbol method success()”原因controller.java.vm中未写extends BaseController或BaseController的import路径写错如写成com.ruoyi.framework.web.controller.BaseController而若依3.8实际路径是com.ruoyi.common.core.controller.BaseController。解决检查controller.java.vm顶部import是否为import com.ruoyi.common.core.controller.BaseController;并在class声明中明确写public class XxxController extends BaseController。5.2 现象生成的Mapper XML中select标签报红提示“Cannot resolve symbol resultMap”原因Mybatis-Plus生成的XML中resultMap的id默认为${entity}ResultMap但若依的BaseMapper要求id为BaseResultMap见ruoyi-framework/src/main/resources/mapper/system/SysUserMapper.xml。解决修改mapper.xml.vm将resultMap id${entity}ResultMap改为resultMap idBaseResultMap并确保id column${pkColumn.name} property${pkColumn.propertyName}/中的property与Entity字段名严格一致大小写敏感。5.3 现象生成的DTO字段全是Object类型而非String或Long原因DataSourceConfig中driverName未指定Mybatis-Plus用HikariCP默认驱动无法正确解析MySQL 8的VARCHAR、BIGINT类型。解决在GeneratorConfig.java中dsc.setDriverName(com.mysql.cj.jdbc.Driver);且确保pom.xml中mysql-connector-java版本≥8.0.28。5.4 现象生成的Service方法调用insertUser()报NoSuchMethodException原因若依的ISysUserService接口中方法名为insertUser(SysUser user)但Mybatis-Plus生成的ServiceImpl中调用的是super.save(entity)未重写insertUser。解决在serviceImpl.java.vm中将Override public boolean save(${entity} entity)改为Override public int insert${entity}(${entity} ${entity?uncap_first})并在方法体内调用this.baseMapper.insert(${entity?uncap_first}); return 1;。5.5 现象Git提交时发现ruoyi-admin/src/main/java下多出一堆*Controller.java但ruoyi-generator/src/main/java里也有原因GeneratorConfig.java中gc.setOutputDir()路径设错指向了ruoyi-admin模块而非ruoyi-generator。解决严格使用System.getProperty(user.dir) /ruoyi-generator/src/main/java作为输出路径并在生成前rm -rf ruoyi-generator/src/main/java/com/ruoyi清空旧文件。提示所有坑的根因都是“生成器与若依运行时环境的语义错位”。解决方案永远是——让生成器的输出100%匹配若依源码中已存在的类结构、方法签名、注解用法而不是让若依去适配生成器。6. 进阶技巧用Groovy脚本动态注入业务逻辑告别手改生成代码生成器最大的价值不是“一次生成”而是“持续生成”。当业务表加了新字段如user_status tinyint你不想每次手动在生成的DTO里加Min(0) Max(2)。这时用Groovy脚本替代FreeMarker模板能实现动态逻辑注入。6.1 在GeneratorConfig中集成Groovy模板引擎ruoyi-generator/pom.xml新增依赖dependency groupIdorg.codehaus.groovy/groupId artifactIdgroovy-templates/artifactId version4.0.13/version /dependency创建ruoyi-generator/src/main/resources/templates/groovy/controller.groovy// controller.groovy def packageName com.ruoyi.project.system.controller def className ${table.entityName}Controller def serviceName I${table.entityName}Service def serviceVar ${table.entityName?uncap_first}Service println package ${packageName}; println println import ${table.entityPackage}.${table.entityName}; println import ${table.servicePackage}.${serviceName}; println import com.ruoyi.common.core.controller.BaseController; println import com.ruoyi.common.core.domain.AjaxResult; println import org.springframework.beans.factory.annotation.Autowired; println import org.springframework.web.bind.annotation.*; println import javax.validation.Valid; println println /** println * ${table.comment}控制器 println */ println RestController println RequestMapping(\/system/${table.name?replace(sys_, )}\) println public class ${className} extends BaseController { println println Autowired println private ${serviceName} ${serviceVar}; println // 动态生成校验逻辑若字段名含email自动加Email table.fields.each { field - if (field.name.contains(email)) { println /** println * 新增${table.comment} println */ println PostMapping println public AjaxResult add(Valid Email RequestBody ${table.entityName} ${table.entityName?uncap_first}) { println return toAjax(${serviceVar}.insert${table.entityName}(${table.entityName?uncap_first})); println } println return } } // 默认生成 println /** println * 新增${table.comment} println */ println PostMapping println public AjaxResult add(Valid RequestBody ${table.entityName} ${table.entityName?uncap_first}) { println return toAjax(${serviceVar}.insert${table.entityName}(${table.entityName?uncap_first})); println } println println }6.2 修改GeneratorConfig用GroovyTemplateEngine替换FreeMarker// 在GeneratorConfig.createGenerator()中替换TemplateConfig部分 TemplateConfig tc new TemplateConfig(); tc.setController(/templates/groovy/controller.groovy); // 指向Groovy脚本 tc.setEntity(/templates/groovy/entity.groovy); mpg.setTemplate(tc); // 关键设置Groovy引擎 mpg.setTemplateEngine(new GroovyTemplateEngine());效果当表中有user_email字段时生成的Controller自动在add方法参数上加Email当有user_age时可扩展逻辑加Min(0) Max(150)。这比维护10个FreeMarker模板高效得多。6.3 我的日常工作流生成即上线不手改一行我的标准操作是在数据库建好表含完整注释、字段约束执行java -jar ruoyi-generator-1.0-SNAPSHOT.jar sys_usergit add ruoyi-generator/src/main/java/com/ruoyi/project/system/mvn clean compile -f ruoyi-admin/pom.xml验证编译通过mvn spring-boot:run -f ruoyi-admin/pom.xml启动用Postman测POST /system/user。整个过程1分钟内完成生成的代码和若依原生代码无任何区别。真正的生产力提升不是少写几行代码而是让“写代码”这件事本身消失——你只负责定义数据结构其余交给生成器。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站