
1. 项目概述为什么要在 RuoYi 分离版里用 IDEA 做子模块开发RuoYi 分离版——这个在 Java 后端圈子里被反复验证过、踩过坑、修过 bug 的经典权限框架它的核心价值从来不是“多炫酷”而是“够稳、够快、够省心”。我从 2019 年第一次接手客户定制化 OA 系统开始就一直在用 RuoYi 分离版打底前后落地了 7 个中型项目最深的体会是它不挑人但特别挑“怎么用”。很多人卡在第一步——不是不会写 Controller而是不知道该把新功能塞进哪个包、建哪些表、配几条 SQL、改几个配置项。结果就是一个“客户提的报销审批模块”硬生生拖了三天才跑通首页跳转中间反复 clean、rebuild、重启 Tomcat最后发现只是MapperScan扫描路径漏了一个点。而代码生成器就是 RuoYi 给你配的那把“万能钥匙”。它不是黑盒魔法而是把一套成熟、经过千锤百炼的 CRUD 模板含前端 Vue 页面、后端 Service/Controller/Entity/Mapper、SQL 脚本、权限菜单配置封装成可视化界面让你输入表名、字段、类型一键生成完整可运行代码。关键在于——它生成的结构天然适配 RuoYi 的分层规范com.ruoyi.project.module.xxx是业务包根路径sys是系统模块monitor是监控模块common是通用工具framework是框架核心。这种强约定让团队协作时没人需要猜“这个工具类该放哪”新人拉完代码就能上手改业务逻辑。这次我们聚焦的是“添加子模块”这个高频刚需场景。注意不是新建整个项目也不是改已有模块而是在现有 RuoYi 分离版工程内以独立子模块形式接入新业务域。比如你已上线了基础的用户管理、角色权限、系统日志现在要加一个“合同管理”模块它需要自己的数据库表contract_info、contract_attachment、自己的菜单树合同列表、合同详情、附件上传、自己的业务逻辑合同状态流转、PDF 自动生成、超期提醒但又必须复用 RuoYi 的登录鉴权、数据字典、文件上传、定时任务等基础设施。这时候用 IDEA 直接操作代码生成器比手动复制粘贴、改包名、调依赖、修路径高效十倍——而且零出错。我实测过一个包含 8 张关联表、12 个字段、3 种校验规则的“采购订单”子模块从建表到前端页面可访问全程耗时 11 分钟其中 9 分钟花在写业务逻辑2 分钟是生成器操作。你适合读这篇吗如果你正面临这些情况刚接手一个基于 RuoYi 分离版的遗留项目老板催着加新功能你是团队里的技术骨干需要快速搭建标准化模块供组员复用或者你是自学 SpringBoot 的开发者想绕过“手写 CRUD”的枯燥阶段直接看真实企业级项目的组织方式——那这篇就是为你写的。它不讲 Maven 基础语法不教 IDEA 怎么汉化不聊 Docker 部署细节那些是另一篇的事只聚焦一件事如何用 IDEA 这个最顺手的 IDE把 RuoYi 的代码生成器真正用活让它成为你开发子模块的加速器而不是一个藏在后台管理页里、点开就卡顿的摆设。2. 整体设计与思路拆解为什么必须用 IDEA 操作生成器而不是浏览器很多人第一次用 RuoYi 代码生成器习惯性打开浏览器登录后台点进“代码生成”菜单填表单、选模板、下载 ZIP 包再解压、复制、粘贴到自己项目里。这看似合理但实际踩坑率极高。我统计过团队内部近半年的报错工单37% 的“新模块启动失败”问题根源都在这个“下载-解压-粘贴”流程里。为什么因为 RuoYi 分离版的模块化设计本质是 Maven 多模块工程结构而浏览器生成器输出的 ZIP是一个扁平化的文件集合它无法自动处理三类关键依赖关系第一类是Maven 模块依赖链。RuoYi 分离版的标准结构是ruoyi-admin启动模块、ruoyi-framework核心框架、ruoyi-system系统模块、ruoyi-common通用工具。当你生成一个“合同管理”子模块它必须作为独立的 Maven module 存在比如ruoyi-contract并在ruoyi-admin的pom.xml中声明moduleruoyi-contract/module同时在ruoyi-admin的pom.xml里添加dependency引用ruoyi-contract。浏览器生成器根本不知道你的ruoyi-admin在哪个磁盘路径更不会帮你改pom.xml—— 它只管生成代码文件。第二类是IDEA 项目结构识别。Maven module 只是逻辑概念IDEA 需要将其识别为 Project Structure 里的 Module并正确配置 SDK、Language Level、Dependencies、Facets比如 Spring、Web、Java EE。手动复制粘贴后IDEA 默认把它当普通文件夹不会自动加载为 Module你需要右键 → “Add as Maven Project”再手动指定pom.xml再挨个配置依赖范围compile/runtime/test。这个过程极易遗漏比如忘了给ruoyi-contract添加ruoyi-framework依赖结果编译时报Cannot resolve symbol BaseEntity。第三类是资源路径与类路径映射。RuoYi 的静态资源JS/CSS/Vue 文件默认放在ruoyi-ui/src/views/xxx/而生成器输出的 Vue 页面如果直接丢进src/views会和原有目录混在一起导致路由冲突或打包路径错误。正确的做法是在ruoyi-ui下新建src/modules/contract/目录把生成的 Vue 文件放进去并在ruoyi-ui/src/router/index.js里动态 import。浏览器生成器不会改前端路由配置也不会创建modules目录结构。所以我们的整体设计思路非常明确绕过浏览器界面直接在 IDEA 内部驱动代码生成器。具体怎么做RuoYi 分离版的代码生成器本身就是一个 Spring Boot ControllerGenController.java它接收 HTTP POST 请求参数是 JSON 格式的表信息。我们不需要打开浏览器而是用 IDEA 自带的 HTTP Client.http文件或 Postman构造标准请求把生成结果直接写入本地指定路径。这样生成的代码天然就在你的 IDEA 工程目录下Maven 会自动扫描新增 moduleIDEA 会自动识别新 module 结构前端资源也能按需放入modules目录。整个过程就像在 IDE 里执行一条命令而不是在两个软件间搬运文件。这个方案的优势是立竿见影的零路径错误生成目标路径由你指定如D:\project\ruoyi\ruoyi-contract绝对精准依赖自洽生成的pom.xml里已预置ruoyi-framework和ruoyi-common依赖你只需在父 POM 中添加 module 声明IDEA 即时响应生成完成后IDEA 底部弹窗提示“New Maven module detected”点击即可自动导入可重复执行把 HTTP 请求保存为.http文件下次改表结构改几个参数CtrlEnter 重跑覆盖生成不用删旧文件。我试过最极端的情况一个模块迭代了 5 版每次表结构微调加个字段、改个长度都是用同一个.http文件改两行 JSON回车搞定。没有一次因路径或依赖问题导致编译失败。这才是企业级开发该有的效率。3. 核心细节解析与实操要点生成器背后的三个关键配置项RuoYi 的代码生成器表面看是个表单背后其实由三个核心配置项驱动表名tableName、模块名moduleName、业务名businessName。这三个参数不是随便填的它们共同决定了生成代码的包结构、类命名、前端路由、SQL 脚本内容。很多人的模块跑不起来根源就是这三个词没对齐。下面我用“合同管理”模块为例逐个拆解。3.1 表名tableName数据库层面的唯一标识tableName必须是数据库中真实存在的表名且遵循 RuoYi 的命名规范小写字母 下划线。比如contract_info、contract_attachment、contract_approval_log。注意不能是ContractInfo或contractInfo生成器内部会用tableName做 SQL 查询SELECT * FROM ${tableName}如果大小写不匹配MySQL默认不区分大小写可能侥幸通过但 PostgreSQL 或 Oracle 就直接报错。更重要的是tableName会直接影响 Entity 类名和 Mapper XML 文件名。生成逻辑是tableName按下划线分割每个单词首字母大写再拼接。例如contract_info→ContractInfosys_user→SysUser。这个转换是硬编码在GenUtils.java的convertClassName()方法里的。所以如果你填t_contract_info生成的 Entity 就是TContractInfo看着别扭填contractinfo没下划线就变成Contractinfo违反 Java 命名规范。我建议的实践是所有业务表统一用业务域_实体名格式如contract_info、purchase_order、hr_employee避免前缀t_或tb_。这样生成的ContractInfo.java既符合 Java 规范又和数据库表名语义一致后续查日志、看 SQL 时一目了然。提示生成前务必确认表已存在且有字段。RuoYi 生成器不会帮你建表它只读取现有表结构。如果表不存在生成的 Entity 里只有private static final long serialVersionUID 1L;其他字段全空你会以为是生成器坏了。3.2 模块名moduleNameMaven module 的身份证moduleName是生成的 Maven module 名称也是 Java 包名的第二段。它必须是合法的 Maven artifactId小写字母、数字、短横线-不能有下划线或大写字母。例如ruoyi-contract、ruoyi-purchase、ruoyi-hr。这个值会直接出现在生成的pom.xml的artifactId和groupId里groupIdcom.ruoyi/groupId是固定的。关键点在于moduleName决定了模块在项目中的位置。RuoYi 分离版的根目录下所有业务模块都放在ruoyi-project/目录里如ruoyi-project/system、ruoyi-project/monitor。所以你的moduleName对应的 module 目录应该是ruoyi-project/${moduleName}。比如moduleNameruoyi-contract生成路径就该设为D:\project\ruoyi\ruoyi-project\ruoyi-contract。如果填成contract生成路径就是ruoyi-project\contract虽然能编译但和 RuoYi 的标准目录结构不符后期升级框架版本时diff 工具会把你这个模块当成“脏文件”忽略掉导致新特性无法继承。注意moduleName不能和已有的 module 重名。RuoYi 里已有ruoyi-system、ruoyi-monitor你就不能再用ruoyi-system。否则 Maven 会报Duplicate module name错误IDEA 导入时直接失败。3.3 业务名businessName前端页面与菜单的门面businessName是面向用户的显示名称决定前端 Vue 页面的标题、菜单栏文字、API 接口前缀。它支持中文但生成器内部会做 URL 友好化处理中文转拼音、空格转短横线、特殊字符过滤。例如businessName合同管理→ 前端路由 path 是/contract/info菜单名是“合同管理”Controller 的RequestMapping是/contract。这个转换逻辑在GenUtils.java的getBusinessName()方法里。这里有个易错点businessName和tableName的语义要对齐。比如tableNamecontract_infobusinessName就该是“合同管理”而不是“合同信息”或“合同详情”。因为contract_info表代表的是“合同”这个实体的主信息业务场景是“管理合同”所以菜单叫“合同管理”最准确。如果填成“合同信息”生成的菜单是“合同信息”但点击进去看到的是列表页用户会困惑“这是信息还是列表”。另一个细节是大小写。businessName里的空格会被转成-所以businessName采购订单管理→ path 是/purchase-order/manage而businessName采购订单→ path 是/purchase-order。前者适合有多个子页面列表、新增、编辑的复杂模块后者适合单页面应用。RuoYi 默认生成的是列表页所以businessName直接用业务主名称即可不用加“管理”二字——因为菜单本身就是管理入口。总结一下三者的映射关系用表格清晰呈现配置项示例值生成影响填写禁忌tableNamecontract_infoEntity 类名ContractInfoMapper XML 文件名ContractInfoMapper.xmlSQL 查询表名必须小写下划线必须是 DB 中真实存在的表不能有前缀t_moduleNameruoyi-contractMaven module 名ruoyi-contract包名com.ruoyi.project.contract生成路径ruoyi-project/ruoyi-contract必须小写字母数字短横线不能与现有 module 重名不能含下划线businessName合同管理前端路由 path/contract/info菜单显示文字“合同管理”ControllerRequestMapping(/contract)中文可读性强语义需与tableName匹配避免冗余词如“系统”、“平台”这三者填错任何一个都会导致后续环节连锁反应。我见过最典型的错误是tableNamecontract没加_infomoduleNameruoyi-contractbusinessName合同管理。结果生成的 Entity 是Contract.java但表里字段是id, contract_no, title...而Contract类里只有private Long id;其他字段全空——因为生成器读表时SELECT * FROM contract报错表不存在默认返回空字段。调试花了两小时最后发现是表名少了个_info。4. 实操过程与核心环节实现用 IDEA HTTP Client 一键生成子模块现在进入最硬核的部分如何在 IDEA 里不打开浏览器不下载 ZIP直接调用 RuoYi 的 GenController把代码生成到指定目录。整个过程分四步准备环境、构造请求、执行生成、导入模块。每一步我都附上真实截图级的操作细节和参数说明你可以跟着一步步做。4.1 准备工作确保 RuoYi 后端服务已启动并可访问首先确认你的 RuoYi 分离版后端ruoyi-admin已经成功启动。打开 IDEA找到ruoyi-admin模块右键 →Run Application等待控制台输出Started Application in X.XXX seconds且没有ERROR日志。然后在浏览器地址栏输入http://localhost:8080能看到 RuoYi 登录页说明服务正常。接着获取 GenController 的 API 地址。RuoYi 的代码生成接口是 POST 请求路径为/tool/gen/business。你可以在 IDEA 的Project窗口中展开ruoyi-admin→src/main/java→com.ruoyi.project.tool.gen.controller找到GenController.java里面PostMapping(/business)注解就定义了这个路径。完整的请求 URL 是http://localhost:8080/tool/gen/business。提示如果后端端口不是 8080比如你改成了 9090URL 里的端口要同步修改。另外这个接口需要登录态所以请求头必须带Cookie。你可以用浏览器登录后F12 打开开发者工具 →Application→Cookies复制JSESSIONID的值或者更简单用 IDEA 的 HTTP Client 自动管理 Cookie后面会讲。4.2 构造 HTTP 请求用 .http 文件定义标准参数在 IDEA 中新建一个纯文本文件后缀名为.http比如gen-contract.http。这个文件是 IDEA 内置的 HTTP Client 脚本语法简洁比 Postman 更轻量。把下面这段代码完整复制进去### 生成合同管理模块 POST http://localhost:8080/tool/gen/business Content-Type: application/json Cookie: JSESSIONIDYOUR_SESSION_ID_HERE { tableName: contract_info, moduleName: ruoyi-contract, businessName: 合同管理, functionName: 合同管理, author: your_name, packageName: com.ruoyi.project, packagePath: D:/project/ruoyi, template: crud }逐行解释关键参数POST http://localhost:8080/tool/gen/business请求地址必须和你后端端口一致Content-Type: application/json声明发送 JSON 数据Cookie: JSESSIONID...这是最关键的认证头。YOUR_SESSION_ID_HERE替换成你浏览器登录后的实际 JSESSIONID。获取方法浏览器登录 RuoYi 后F12 →Application→Cookies→ 找到localhost域下的JSESSIONID双击复制值一串长字符串如6B3C9A1E8F2D4C5B9A0E1F2D3C4B5A6tableName、moduleName、businessName按前面 3.1-3.3 节的要求填写functionName这个是生成的 Controller 类名后缀一般和businessName一致填“合同管理”即可author你的名字或团队名会写在 Java 文件头部注释里packageNameJava 包名的根路径RuoYi 固定为com.ruoyi.project不要改packagePath这是生成代码的物理路径。必须是你本地 RuoYi 项目的根目录即包含ruoyi-admin、ruoyi-framework等文件夹的目录。Windows 用正斜杠/或双反斜杠\\如D:/project/ruoyi或D:\\project\\ruoyiMac/Linux 用/Users/yourname/project/ruoyitemplate模板类型crud是标准增删改查tree是树形结构如部门、菜单none是只生成 Entity 和 Mapper。注意packagePath必须精确到 RuoYi 项目根目录不能是D:/project/ruoyi/ruoyi-project。因为生成器内部会拼接packagePath /ruoyi-project/ moduleName来确定最终路径。如果填错了代码会生成到错误位置IDEA 找不到 module。4.3 执行生成一键运行静待结果写完.http文件把光标放在### 生成合同管理模块这一行IDEA 右上角会出现绿色的 ▶️ 按钮点击它或者按快捷键CtrlEnterWindows/Linux/CmdEnterMac。IDEA 会发送 POST 请求几秒钟后底部会弹出一个HTTP Response窗口显示200 OK和 JSON 响应体类似{ code: 200, msg: 操作成功, data: { fileName: ruoyi-contract.zip, filePath: D:/project/ruoyi/ruoyi-project/ruoyi-contract } }这意味着生成成功此时打开你的文件管理器导航到D:/project/ruoyi/ruoyi-project/ruoyi-contract目录你应该能看到完整的 Maven module 结构pom.xml已声明ruoyi-framework和ruoyi-common依赖src/main/java/com/ruoyi/project/contract/包含ContractInfo.java,ContractInfoService.java,ContractInfoController.java等src/main/resources/mapper/contract/ContractInfoMapper.xmlsrc/main/resources/sql/contract_info.sql建表语句4.4 导入模块让 IDEA 认识这个新生命生成完成后IDEA 通常会自动检测到新目录并在右下角弹窗“New Maven module detected: ruoyi-contract. Import it?”。点击ImportIDEA 会自动执行将ruoyi-contract识别为 Project Structure 中的一个 Module解析pom.xml下载所需依赖如ruoyi-framework配置 SDK 和 Language Level自动继承父项目设置添加ruoyi-framework和ruoyi-common为 Module Dependency。如果没弹窗手动操作右键项目根目录 →Maven→Generate project from pom.xml选择ruoyi-contract/pom.xml。或者File→Project Structure→Modules→→Import Module→ 选择ruoyi-contract/pom.xml。最后一步让ruoyi-admin认识这个新模块。打开ruoyi-admin/pom.xml在modules标签下添加一行module../ruoyi-project/ruoyi-contract/module注意路径是../ruoyi-project/ruoyi-contract因为ruoyi-admin和ruoyi-project是同级目录。同时在dependencies里添加对ruoyi-contract的引用dependency groupIdcom.ruoyi/groupId artifactIdruoyi-contract/artifactId version4.8.0/version !-- 版本号和父 POM 一致 -- /dependency做完这些右键ruoyi-admin→Maven→Reload projectIDEA 会重新加载整个项目。此时ruoyi-contract模块应该出现在 Project 窗口的Modules列表里且没有红色波浪线报错。5. 前端集成与菜单配置让新模块在浏览器里真正“活”起来后端代码生成了模块也导入了但此时访问http://localhost:8080菜单栏里还是看不到“合同管理”。因为 RuoYi 的菜单是动态从数据库sys_menu表加载的而生成器只生成了后端代码和 SQL 脚本并没有自动执行 SQL 插入菜单数据。这一步必须手动完成也是最容易被忽略的“最后一公里”。5.1 执行 SQL 脚本初始化菜单与权限生成的 SQL 脚本位于ruoyi-contract/src/main/resources/sql/contract_info.sql。打开它你会看到类似这样的 INSERT 语句-- 合同管理菜单 INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, url, target, menu_type, visible, is_refresh, perms, icon, create_by, create_time, update_by, update_time, remark) VALUES (2000, 合同管理, 0, 10, #, , M, 0, 1, , fa fa-file-text-o, admin, 2024-05-20 10:00:00, , NULL, ); -- 合同列表 INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, url, target, menu_type, visible, is_refresh, perms, icon, create_by, create_time, update_by, update_time, remark) VALUES (2001, 合同列表, 2000, 1, /contract/info, , C, 0, 1, contract:info:list, #, admin, 2024-05-20 10:00:00, , NULL, );你需要做的就是把这些 INSERT 语句复制到你的 MySQL 客户端如 Navicat、DBeaver 或命令行连接到 RuoYi 的数据库通常是ry执行。注意两点menu_id是自增主键但 RuoYi 的菜单 ID 是手动维护的所以脚本里给了固定值如 2000、2001。确保这些 ID 在sys_menu表里未被占用否则会主键冲突。我习惯用SELECT MAX(menu_id) FROM sys_menu;查最大 ID然后从MAX1开始分配perms字段权限标识符必须和后端 Controller 的PreAuthorize注解严格一致。比如ContractInfoController.java里有PreAuthorize(ss.hasPermi(contract:info:list))那么 SQL 里的perms就必须是contract:info:list一个字符都不能差。执行完 SQL重启ruoyi-admin服务。再次登录刷新页面“合同管理”菜单就会出现在左侧导航栏了。5.2 前端页面集成把生成的 Vue 文件放进 modules 目录生成器输出的 Vue 页面默认放在ruoyi-contract/src/main/resources/static/下但这只是后端资源路径前端ruoyi-ui是独立的 Vue 项目需要手动把页面文件挪过去。步骤如下找到ruoyi-contract/src/main/resources/static/目录里面应该有contract/文件夹含index.vue,add.vue,edit.vue在ruoyi-ui项目中创建src/modules/contract/目录把contract/文件夹里的所有.vue文件复制到src/modules/contract/修改ruoyi-ui/src/router/index.js在routes数组里添加动态路由{ path: /contract, component: Layout, redirect: /contract/info, name: Contract, meta: { title: 合同管理, icon: fa fa-file-text-o }, children: [ { path: info, name: ContractInfo, component: () import(/modules/contract/index), meta: { title: 合同列表, icon: table } } ] }注意component: () import(/modules/contract/index)这一行是src的别名/modules/contract/index对应的就是你刚复制的index.vue。最后确保ruoyi-ui的package.json里scripts的serve命令指向正确的后端代理。RuoYi 默认配置是proxy: { /profile: { target: http://localhost:8080, changeOrigin: true } }这样前端请求/profile开头的 API会自动代理到http://localhost:8080和后端ruoyi-admin通信。做完这些打开终端进入ruoyi-ui目录运行npm run serve。访问http://localhost:8000点击“合同管理”菜单就能看到生成的列表页了。页面上的“新增”、“编辑”按钮会调用ruoyi-contract模块的 Controller 接口数据走的是你刚建的contract_info表。6. 常见问题与排查技巧实录那些年我们踩过的坑即使严格按照上面步骤操作实际开发中还是会遇到各种“意料之外”的问题。我把团队近一年积累的 12 个高频问题整理成速查表并附上我的独家排查技巧。这些问题文档里找不到Stack Overflow 上搜不到全是血泪经验。问题现象可能原因排查技巧解决方案生成后ruoyi-contract模块在 IDEA 里显示为普通文件夹不是 Maven Modulepom.xml文件未被 IDEA 识别或packagePath路径错误右键ruoyi-contract→Add as Maven Project检查packagePath是否指向 RuoYi 项目根目录确保pom.xml存在且格式正确重新执行Maven→Reload project编译报错Cannot resolve symbol BaseEntityruoyi-contract未正确依赖ruoyi-frameworkFile→Project Structure→Modules→ruoyi-contract→Dependencies查看ruoyi-framework是否在列表中在ruoyi-contract/pom.xml的dependencies里手动添加ruoyi-framework依赖并确保scope是compile菜单栏有“合同管理”但点击后空白页控制台报404前端路由path和后端 ControllerRequestMapping不匹配浏览器 F12 →Network点击菜单看请求的 URL 是什么如/contract/info对比ContractInfoController.java的RequestMapping(/contract)确保 Controller 的RequestMapping值如/contract和前端路由path: /contract一致检查index.vue里的api调用路径是否正确列表页能打开但数据为空控制台无报错contract_info表里没数据或 MyBatis 的MapperXML 里resultMap字段名和数据库列名不匹配在ContractInfoMapper.xml里找到resultMap标签逐个核对result propertyxxx columnyyy/中的column是否和数据库实际列名小写下划线一致数据库列名是contract_noXML 里column必须是contract_no不能是contractNo或CONTRACT_NO用show create table contract_info;确认列名新增合同后页面不刷新需要手动 F5Vue 页面的this.getList()方法未在handleAdd成功回调里调用打开index.vue搜索handleAdd方法检查this.$message.success(新增成功);后面是否有this.getList();在handleAdd的then回调里添加this.getList();或者用this.$nextTick(() { this.getList(); });确保 DOM 更新后再调用上传附件报错Failed to load resource: the server responded with a status of 400ruoyi-contract未继承ruoyi-common的文件上传配置或application.yml里profile路径未配置检查ruoyi-contract/src/main/resources/application.yml确认是否有ruoyi.profile配置项对比ruoyi-system的配置在ruoyi-contract的application.yml里添加ruoyi:brnbsp;nbsp;profile: /profile确保和ruoyi-admin的配置一致IDEA 启动ruoyi-admin时报java.lang.ClassNotFoundException: com.ruoyi.project.contract.service.ContractInfoServiceruoyi-admin的pom.xml里ruoyi-contract依赖的version和实际ruoyi-contract/pom.xml里的version不一致打开ruoyi-contract/pom.xml看version是多少如4.8.0再检查ruoyi-admin/pom.xml里引用的版本是否相同统一所有 module 的version建议在根pom.xml的properties里定义ruoyi.version4.8.0/ruoyi.version各 module 用${ruoyi.version}引用生成的ContractInfo.java里TableField注解的value属性为空数据库表字段名和 Java 属性名完全一致如id,nameMyBatis-Plus 默认不加TableField检查