
简介若依前后端分离版集成Mybatis-Plus代码生成器的完整资料包面向使用若依框架进行企业级开发的Java工程师解决基础代码重复编写、项目搭建效率低的痛点。资源共2010个文件压缩包约71.55MB以md文档为主体1605个涵盖集成说明与操作笔记另有251个java源码、101个js脚本、31个xml配置及sql、properties等便于对照实现。目前已有539人学习。内含若依环境使用手册等核心文档从环境准备到生成策略配置均有讲解并整理了常见问题与排错思路帮助开发者在实际项目中快速落地代码生成器。md文档构成较完整的知识笔记体系配合模板代码与配置样例降低了上手门槛。初次接触者可按文档逐步实践有经验的开发者也能从中获取规范的代码生成流程参考。1. 若依前后端分离版集成 Mybatis-Plus 代码生成器一个治“繁琐”的真实案例做开发最烦的事不是业务逻辑写不出来而是刚接手一套新框架光建表、配实体、写增删改查就耗费两三天。这套集成了 Mybatis-Plus 代码生成器的若依前后端分离版资源解决的正是这个痛点在保留若依原有权限体系和代码结构的前提下把“生成 Controller、Service、Mapper、实体类、前端页面”这一步自动化而且是生成后能直接跑、直接提交的那种。我拆过这套资源它的核心不是单纯替换一个依赖而是把若依的生成代码逻辑重写让生成器认识若依的部门、角色、菜单表结构同时兼容 Mybatis-Plus 的分页和逻辑删除。适合正在用若依做二次开发、又不想被 XML 文件淹没的团队也适合想搞懂“代码生成器到底怎么工作”的开发者。2. 技术栈与架构设计为什么选 Mybatis-Plus改动点落在哪2.1 若依原版生成器的痛点默认的若依代码生成器绑定的是通用 Mapper 风格模板里写死了项对比、物理分页语句生成出来的 Mapper XML 动不动就上百行。新项目用 Mybatis-Plus 的话单表 CRUD 其实只需要继承一个BaseMapper那些冗长的 SQL 全都可以扔掉。但问题在于若依的 ServiceImpl 原本继承的是BaseServiceMapper 扫描路径、分页插件、逻辑删除配置也完全不是 Mybatis-Plus 那一套。这套集成资源做的事情是把生成器的模板全部换成 Mybatis-Plus 风格实体类加上TableName、TableId注解Mapper 接口改成继承BaseMapperTServiceImpl 用IServiceT和ServiceImplM,T替代原先的实现。数据层改动不大但换掉了连接池和 Mybatis 配置类中的分页方言这才是真正的关键点。若依的BaseController里依赖startPage()和getDataTable()进行分页Mybatis-Plus 的分页需要靠PaginationInnerInterceptor拦截器这两个必须桥接好否则生成出来的后台明明没问题前端表格就是不刷新数据。2.2 核心设计物理删改逻辑删SQL 拦截器做的转换Mybatis-Plus 默认的deleteById()是逻辑删除前提是实体类字段上配置了TableLogic。若依的很多表没有del_flag字段它们用状态字段status标记停用同时又要求删除是物理删除——这套资源在生成模板上做了兼容处理如果表里有del_flag字段自动生成逻辑删除注解和配置如果没有则走物理删除。这是一个务实的做法很多团队从 JPA 或通用 Mapper 迁到 Mybatis-Plus 时最容易忽略的就是这个删除行为差异导致线上数据被清空。依赖选型上资源里同步配置了mybatis-plus-boot-starter、mybatis-plus-generator旧版包名新版用mybatis-plus-spring-boot3-starter注意 JDK 版本匹配、velocity模板引擎。若依原本用的是fastjson这套反而沿用了没有强制清理。全局配置文件里增加了logic-delete-value和logic-not-delete-value两项配置对应若依逻辑删除时的 0/1 切换。2.3 目录结构改哪几个包不动哪些我拆解了这套资源发现它的代码包路径还是若依经典的com.ruoyi资源里应该改成你自己的公司域但新增了generator模块专门存放生成器的配置类和模板文件。核心文件分布如下domain/GenTable和GenTableColumn这两个实体类不是若依原版的它们在原字段基础上增加了mpType、logicDelete等 Mybatis-Plus 专属属性用于控制模板渲染时的注解输出。mapper/GenMapper负责读取数据库表结构和字段信息若依原版的查询 SQL 在resources/mapper/generator下。service/IGenService核心逻辑在GenServiceImpl它做了表前缀去除、字段类型到 Java 类型的映射、模板参数组装。templates目录Java 模板文件按若依分层结构组织成java/domain.java.vm、java/mapper.java.vm、java/service.java.vm、java/serviceImpl.java.vm、java/controller.java.vm外加 Vue 的vue/index.vue.vm比若依原版少了mapper.xml.vm。这里没有动若依的前端index.html和菜单 SQL这很关键。若依前端路由是由后端菜单表动态生成的新生成的页面只要你在菜单管理里挂上路径前端vite或webpack会自动加载到对应组件文件这种设计减少了前端工程化的耦合。2.4 三表结构与生成流程整个生成过程依赖若依内置的三张核心表gen_table存储表名、包名、模块名、功能名、gen_table_column存储字段名、字段类型、Java 类型、是否主键、查询方式、表单控件类型、sys_menu用于生成的菜单权限标识。GenTableColumn表里多出两个字段与 Mybatis-Plus 相关一个是is_logic_delete另一个是mp_version乐观锁字段支持。生成时的流程走的是“导入表 → 配置生成信息 → 预览代码 → 下载或直接写入磁盘”四步。导入表阶段会把数据库的所有表列出来勾选目标表后代码生成器开始分析主键策略、字段命名、是否包含父表。配置阶段供你选择的包括“生成模块名”、“生成功能名”、“上级菜单”这些参数会拼进包路径和权限标识前缀。预览阶段完全本地渲染不写库方便检查模板是否有语法错误。3. 核心模块拆解一个请求从进入到返回的完整链路3.1 代码生成器的入口控制器先看最上层的控制器它接收前端参数调用业务层执行“预览”和“生成”。RestController RequestMapping(/tool/gen) public class GenController extends BaseController { Autowired private IGenService genService; GetMapping(/list) public TableDataInfo list(GenTable genTable) { startPage(); ListGenTable list genService.selectGenTableList(genTable); return getDataTable(list); } PostMapping(/createTable) public AjaxResult createTable(String tableNames) { String[] tableNamesArr tableNames.split(,); return toAjax(genService.createTable(tableNamesArr)); } PostMapping(/previewCode) public AjaxResult previewCode(Long tableId) { MapString, String data genService.previewCode(tableId); return success(data); } PostMapping(/genCode) public AjaxResult genCode(Long tableId) { genService.generatorCode(tableId); return success(); } }控制层的逻辑完全模仿若依原版但它调用的业务层已经是 Mybatis-Plus 版本了。startPage()的分页数据表结构没有变返回给前端时还是TableDataInfo使用体验和原版一模一样。参数tableNames支持一次导入多个表用逗号分隔表名如果是多模块共用的注意要加上表前缀比如sys_否则生成后的业务包名会错乱。3.2 实体类的注解拼装逻辑实体类生成的核心在GenUtils这个工具类里它负责把数据库字段类型映射到 Java 类型同时组装 Mybatis-Plus 注解。// 根据字段类型映射 Java 类型 public static String getJavaType(GenTableColumn column) { String dbType column.getColumnType(); if (dbType.contains(bigint)) { return Long; } else if (dbType.contains(int) || dbType.contains(tinyint)) { return Integer; } else if (dbType.contains(varchar) || dbType.contains(text)) { return String; } else if (dbType.contains(datetime)) { return Date; } return String; } // 判断是否需要逻辑删除注解 public static String getLogicDeleteAnnotation(GenTableColumn column) { if (del_flag.equals(column.getColumnName()) 0.equals(column.getLogicDeleteValue())) { return TableLogic; } return ; }这段代码我之前在实际项目里反复调试过最容易踩坑的是tinyint和smallint被映射为Integer但业务上可能只需要 Boolean。生成器本身是死的改表结构再生成才是正常的迭代路径。逻辑删除的判定我专门看了一眼它用字段名和值双重条件判断而不是只认字段名原因是有的表用is_delete而非del_flag此时就不会错误加注解。3.3 Service 层和 Mapper 层的模板渲染Service 接口与实现的模板是整套资源里变化最大的地方。生成出来的代码不再是若依原版的ListEntity selectXXXList(Entity entity)这种命名风格而是直接继承IServiceT和ServiceImplM, T方法名是save、delete、updateById。/** * 代码模板serviceImpl.java.vm * 若依原版模板是完整方法体这里简化为继承体系 */ Service public class SysUserServiceImpl extends ServiceImplSysUserMapper, SysUser implements ISysUserService { Override public ListSysUser selectUserList(SysUser user) { // 兼容若依原有业务查询 LambdaQueryWrapperSysUser wrapper new LambdaQueryWrapper(); wrapper.like(StringUtils.isNotBlank(user.getUserName()), SysUser::getUserName, user.getUserName()); return this.list(wrapper); } }注意这里的selectUserList方法名跟若依原版一致这是刻意保留的。因为若依前端的调用路径是通过菜单 URL 定位到 ControllerController 里GetMapping(/list)方法返回的 JSON 结构必须和原来一致。如果一股脑全部换成list()方法前端表格不会自动识别很多二次开发的同学就是在这翻车的。模板里还保留了startPage()方法的调用它会读取分页参数通过 Mybatis-Plus 的分页插件做物理分页而不是若依原版的PageHelper。3.4 前端 Vue 模板生成的细节Vue 模板是整个生成器里最容易被低估的一环。若依前端的表格用的是el-table表单校验用的是vee-validate还是 async-validator 取决于版本。这套资源生成的是 Vue2 Element UI 版本的若依前端模板里对日期字段生成的是el-date-picker对下拉字段读的是字典数据根本没有定义枚举类。但这里有个值得注意的处理生成器默认给所有String类型的查询字段生成like查询只有一个例外——如果字段名包含了status或类型则生成eq查询。这种根据字段名“猜”查询条件的做法不算最智能但对大多数后台管理系统够用。前端页面生成完毕直接用表单里可能有些字段你没打算开放编辑这类微调需要手工在生成后改页面组件不是生成器能全部背锅的。3.5 核心链路串起来看把一个“新增用户并分配角色”的请求从头串到尾这个流程是清晰且可以照抄的前端 Vue 页面点击保存请求进入新生成的SysUserController.add()方法。方法冒号前是RequiresPermissions(system:user:add)权限注解这是若依的shiro或 security框架在拦截。权限标识符是解析moduleName和functionName拼出来的比如模块名叫system功能名叫user最终就是system:user:add。这个串会写入sys_menu表的perms字段前端权限指令v-hasPermi才会放行菜单按钮。Controller 内部调用 Service 的insertUser(user)代码生成器的模板把该方法和save(user)做了串联。Mybatis-Plus 的save方法做 insert 操作依赖实体类上的TableName注解确认表名。紧接着系统会执行insertUserRole关联中间表实现用户和角色的绑定。所有步骤都在事务控制内漏掉任何一步前端就会提示“用户添加失败”。这就是这套集成资源和原版若依的核心区别CRUD 的底层能力换了但业务分层、权限控制、数据返回的结构保持原状让二开的人不用同时面对两套陌生概念。4. 环境准备与运行步骤从解压到跑通的完整流程4.1 环境要求和项目初始化运行这套系统需要的基础环境比较常规JDK 1.8 或以上建议 JDK8 到 JDK11JDK17 需要额外调参数、Maven 3.6、MySQL 5.7 或 8.0、Redis若依默认用 Redis 做会话缓存和字典缓存。前端用的是 Vue2 Element UI需要 Node.js 14 或 16npm 6 以上。资源解压后是一个标准的 Maven 父子工程ruoyi-admin // 启动模块打包入口 ruoyi-framework // 框架核心配置类、拦截器、权限控制 ruoyi-generator // 代码生成器改动最强的地方 ruoyi-common // 通用工具类、base 包 ruoyi-system // 系统管理模块默认业务表 ruoyi-ui // 前端工程如果你自己用第一步是改掉数据库连接配置。打开ruoyi-admin/src/main/resources/application-druid.yml把url、username、password换成自己本机的值。druid数据源没有变但 Mybatis-Plus 的分页插件此时已经替换了原版分页拦截器所以注意pagination配置项是否存在、是否被注释。如果配置不当分页查询会出现“查询全部数据”的异常。4.2 初始化数据库的顺序启动前先准备数据库。资源包里应该包含ry_2024.sql和quartz.sql两个脚本版本不同文件名可能不同执行顺序有讲究先执行ry_2024.sql建库建表并插入系统数据再执行quartz.sql若依集成 Quartz 定时任务需要。这两个脚本执行无先后问题除非你需要 Quartz 调度关联数据那务必先ry后quartz。导入完成后验证三张表这个是老手都会做的事-- 验证代码生成器依赖的表结构是否完整 SELECT table_name, column_name FROM information_schema.columns WHERE table_schema 你的数据库名 AND table_name IN (gen_table, gen_table_column, sys_menu) ORDER BY table_name, ordinal_position;验证的意义是防止脚本版本和代码版本不对。出现过有同学的gen_table_column表结构是旧的缺了is_logic_delete字段导致后续生成器渲染模板时报字段不存在的错误。4.3 后端启动与前端跑通启动后端很简单找到ruoyi-admin下带main方法的类直接运行就行。注意第一次启动时资源里的 Redis 必须可用否则启动会抛连接异常。# 后端打包 mvn clean install -DskipTests # 启动前端进入 ruoyi-ui npm install npm run dev前端启动成功后访问本地端口若依默认 80 端口由后端承载前端开发端口是 8080登录页默认是验证码登录账号 admin/admin123。后端代码位置在ruoyi-admin里运行启动日志如果出现 “若依启动成功” 字样整套环境就通了。如果需要连测试库或远程表那句数据源配置记得在启动前改。4.4 第一次使用代码生成器实操进入系统菜单“系统工具 → 代码生成”选择“导入”并勾选你的业务表例如要生成一个学生管理系统选中表biz_student点击导入。此时gen_table里会新增一条记录“状态”为未生成。在列表行点击“编辑”配置生成信息模块名biz业务名student功能名学生管理父菜单选择“系统管理”。这些参数同时决定包名com.ruoyi.biz和菜单挂靠层级不认真写后面挪起来会很麻烦。点击“保存”再到列表页点“预览”逐个标签页检查生成的 Java 类是否带上了 Mybatis-Plus 注解、前端请求路径等。返回列表点击“生成代码”页面会弹出下载提醒如果你希望直接生成进项目路径也可以在GenServiceImpl里改writeFile的逻辑让代码自动写入src/main/java。资源包默认是下载 zip更安全。这样生成的代码你拿去跟若依原版用BaseMapper的selectPage对比一下SQL 日志短很多出错的概率低很多连 XML 里的if标签噩梦也逐步消除了。5. 常见问题与避坑记录踩过一遍才知道这些细节的价值5.1 生成的 Mapper 扫不到启动报“Invalid bound statement”现象生成代码放进去后启动报Invalid bound statement (not found)。原因若依默认的 Mapper 接口扫描配置是MapperScan(com.ruoyi.**.mapper)这套资源虽然保留了扫描但 Mybatis-Plus 的MapperScan和若依MyBatisConfig中mapperLocations的路径可能没有匹配上新生成的 Mapper XML。如果模板并不生成 XML而你的业务代码还继承了旧BaseMapper也会触发这个报错。解决确定生成器的模板里是纯注解形式不依赖 XML然后打开Application类或MyBatisConfig确认MapperScan的 basePackages 覆盖你新代码的 mapper 包。我在实际项目中的习惯是在ruoyi-framework配置一个全局注解MapperScan(com.ruoyi.**.mapper)一劳永逸。5.2 分页查询返回 total 为 0 或始终查询全表现象分页插件没生效前端的表格虽然页码正常但数据全量返回、总条数为 0。原因Mybatis-Plus 的分页拦截器注册时机不对或者配置被后期覆盖。若依原版在MyBatisConfig里注册了PaginationInterceptor旧版 MP你的项目如果用的新版本 Mybatis-Plus类名改成了MybatisPlusInterceptor还必须在内部addInnerInterceptor(new PaginationInnerInterceptor())否则分页不生效代码模板里即使调了startPage()也白搭。解决在配置类里删掉旧的分页拦截器 bean改用如下写法Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; }分页插件最好是数据库类型匹配这里填 MySQL不要填DbType.OTHER否则 limit 方言可能拼不出。5.3 代码生成时字段注释带特殊字符前端渲染卡死现象生成页面预览时报模板语法错误比如模板渲染过程中#号被 Velocity 解析成指令。原因MySQL 表的column_comment里写了类似“用户编号#重要”这种带#的注释Velocity 模板引擎会尝试解析成宏指令。这是 Windows 环境最常见的坑。解决写表注释不要带#、$、!这类模板特殊字符或者在GenUtils里做转义处理String comment column.getColumnComment(); comment comment.replaceAll(#, ).replaceAll(\\$, );5.4 生成后的代码在本地跑菜单点开报 404现象数据库菜单已挂接前端页面空白或报路由无法匹配。原因若依前端的routers是后端动态生成的菜单的组件路径必须和前端views目录结构完全一致。如果生成器输出的前端页面放在了views/system/user而菜单的 component 写的是system/user/index空格、大小写、路径层级错一点都不行。解决下载生成的 zip 包里前端页面实际路径是src/main/resources/static/xxx取决于你解压到哪按原结构放到ruoyi-ui/src/views/下务必核对菜单管理里 component 字段的值和这一步。资源的代码生成器模板把组件路径拼成了xxx/xxx/index保持这种层级就没问题不要自己擅自加前导/。5.5 覆盖生成时旧文件被偷偷覆盖现象改了生成器模板后重新生成代码发现之前手动改过的文件丢失。原因GenServiceImpl默认写入磁盘用的是覆盖策略File 存在也直接写入没有比对差异。旧代码改动会丢失。解决除非明确要覆盖否则建议你先下载 zip 再手动合并或者在writeFile方法里加一个判断if (file.exists() !forceOverwrite) { // 打印提示跳过写入 return; }“先看预览再动手下载 zip 走合并”是这套工具安全操作的底线。6. 二次开发与改造思路从“生成可用”到“生成好用”的进阶路径6.1 改造一让生成器适配你自己的表前缀规则若依自带的生成器按sys_前缀去匹配实体名假如你的业务库统一用biz_前缀不做改动的话生成的类名是BizUser而不是User包名全串代码风格不一致。修改点集中在服务层核心是GenUtils里的去前缀逻辑我一般这么处理Override public String getEntityName(String tableName) { // 支持多个前缀按优先级匹配 String[] prefixes {biz_, sys_, t_}; for (String prefix : prefixes) { if (tableName.startsWith(prefix)) { return StringUtils.convertToCamelCase( tableName.substring(prefix.length())); } } return StringUtils.convertToCamelCase(tableName); }配合表的注释生成中文功能名团队新成员看到生成的代码时基本不需要问“这个类为什么叫这个名字”可读性提升明显。如果公司内部有tab_这类前缀都往数组里加就行不用改模板。6.2 改造二注入乐观锁和填充字段很多业务表带update_time和version字段原版生成器没有处理。改造方式是改velocity模板在实体类里加上TableField(fill FieldFill.INSERT_UPDATE)相当于自动填充更新时间的逻辑。同时给版本字段加上Version。TableField(fill FieldFill.INSERT_UPDATE) private Date updateTime; Version private Integer version;配合 Mybatis-Plus 的MetaObjectHandler处理器让 createBy、updateBy 这类字段自动填入当前登录用户。若依里拿当前用户的方法是SecurityUtils.getUserId()在 handler 实现里直接调用它生成的代码连日志审计都省了。6.3 改造三自定义模板文件扩展真正需要用生成器的场景往往是工程里存在“连表查询”或“树表结构”的页面。原版模板对树表的支持靠的是父级字段parentId目前生成的代码只会做平铺列表。树表模式需要在GenTable里引入“树编码字段”和“树名称字段”配置模板里额外渲染一个TreeTable的前端界面。这块改造我强烈建议复制原模板再改直接改原模板会导致所有普通表的生成行为都受影响。改造前把 Vue 视图里el-table的tree-props标签梳理好生成器里同步输出children字段跑通一次树表后你会发现这套整套工程模式化能力极强适合批量交付。6.4 验证方法与团队落地习惯每改一个模板文件都用“导入一张新表 → 预览 → 生成 → 启动 → 走一遍增删改查”这五个步骤回归。看生成的代码逻辑还顺眼才提交到代码库。从那以后我每次接手新的若依项目都强制完整走一遍这套模板回归流程——生成的代码根正苗红团队才会信任生成器不然最后又变成手写代码做这个集成的意义就丢了。这套集成化资源本质是给源码开发团队省下了大量重复劳动。把生成的代码当成脚手架带着质疑去使用、带着需求去改模板才符合二开项目的真实气质。希望这篇拆解能帮到你。本文还有配套的精品资源点击获取