简介:本资源是面向Java全栈开发者与若依平台二次开发者的工程实践包,聚焦于在若依前后端分离版中深度集成Mybatis-Plus代码生成器,解决重复编写CRUD基础代码、数据库变更后手动同步效率低等典型痛点。资源共2010个文件,主体为1605份Markdown文档(含环境配置说明、生成策略详解、避坑指南)、251个Java类(覆盖Entity/Controller/Service/Mapper全层生成代码)、101个JS前端适配脚本及31个XML映射配置,压缩包大小71.55MB,结构完整、开箱即用。已有540人学习下载,适合中高级开发者快速搭建标准化后端骨架、理解若依+Mybatis-Plus协同机制,并复用其生成逻辑支撑多模块迭代。包内含《若依环境使用手册.docx》等实操指引,结合大量.ds_store占位文件可推断其源自真实开发环境导出,目录层级清晰,便于按模块定位生成规则与自定义扩展点。
1. 若依前后端分离版集成Mybatis-Plus代码生成器:不是加个依赖就能跑通的“一键生成”,而是要动刀改三处核心配置、绕过两个硬编码拦截、重写一个模板引擎路径的实战闭环
你刚拉下若依(RuoYi)前后端分离版最新源码,兴冲冲想用 MyBatis-Plus 的AutoGenerator快速生成 Controller/Service/Mapper 层——结果连DataSourceConfig都配不进 Spring Boot 启动上下文;或者好不容易跑通了生成逻辑,生成的 XML 文件里<resultMap>标签全被删光,DTO 字段映射全乱套;更常见的是,生成的@TableName("sys_user")注解里表名还是带前缀的ry_sys_user,而你数据库里实际用的是无前缀规范命名。这不是工具不行,是若依的工程结构、包扫描机制、模板加载路径和 MyBatis-Plus 默认行为之间存在四层隐性耦合。这个资源包不是“开箱即用”的插件,而是一套经过某高校实验室在真实中台项目中压测验证的集成方案:它把mybatis-plus-generator3.5.3.1 版本深度嵌入若依 4.7.0 的 Maven 多模块体系,覆盖从数据库连接池初始化、自定义模板变量注入、字段类型自动映射(如tinyint(1)→Boolean)、到前端 Vue 页面字段校验规则同步生成的完整链路。适合正在做二次开发、需要高频增删业务模块、又不愿手动维护三层重复代码的中高级后端工程师。别信“一行命令生成全部”的宣传,这里每一步都得你亲手确认包路径、检查模板占位符、验证@TableField(fill = FieldFill.INSERT)是否生效——但只要你走完这五步,后续新增一张表,从建表到上线接口,12 分钟内可完成。
2. 为什么必须放弃 MyBatis-Plus 官方 Generator Starter?若依的三层架构决定了你得自己接管模板引擎与数据源生命周期
若依不是普通 Spring Boot 单体应用,它的模块划分极其严格:ruoyi-admin(启动模块)、ruoyi-system(系统核心)、ruoyi-common(通用工具)。而官方mybatis-plus-generator-spring-boot-starter的设计假设是:所有配置集中于application.yml,模板文件放在resources/templates下,且DataSource是全局唯一 Bean。但在若依中,ruoyi-system模块通过DruidDataSource自定义配置类管理数据源,ruoyi-common封装了BaseEntity和DataScopeFilter,而ruoyi-admin的SpringApplication.run()启动时根本不会扫描ruoyi-system下的generator包——这意味着你直接在ruoyi-admin加 starter,AutoGenerator找不到DataSource;放在ruoyi-system加,又因@MapperScan范围限制,生成的 Mapper 接口无法被ruoyi-admin的SqlSessionFactory识别。这是典型的“框架假设 vs 工程现实”冲突。我们不 hack starter,而是回归AutoGenerator原生 Java API,用最可控的方式重建生成流程:手动构建DataSourceConfig、显式传入PackageConfig、用TemplatePath指向独立模板目录、最后将生成结果写入指定模块的src/main/java和src/main/resources目录。这样做的好处是:你能精确控制每个环节——比如当发现生成的ServiceImpl类里@Service注解缺失,立刻定位到InjectionConfig中fileCreate回调未覆盖serviceImpl类型;当QueryWrapper构造方法报错,马上知道是strategy.setSuperEntityClass()指向了若依的BaseEntity而非空父类。下面就是这套方案的落地步骤,每一步都对应一个真实翻车现场。
2.1 手动构建 DataSourceConfig:绕过若依的 Druid 数据源自动装配,直连 HikariCP
若依默认使用 Druid,但 MyBatis-Plus Generator 对 Druid 的DruidDataSource兼容性较差,尤其在获取数据库元数据时容易抛SQLException: validateConnection false。我们改用 HikariCP,且不走 Spring Boot 自动配置,而是用HikariConfig硬编码连接参数——因为AutoGenerator的DataSourceConfig只接受javax.sql.DataSource接口实现,不认@ConfigurationProperties绑定的 Bean。
// 在 ruoyi-system 模块下新建 generator/MybatisPlusGenerator.java public class MybatisPlusGenerator { public static void main(String[] args) { // 1. 手动构建 HikariCP 数据源(关键:关闭 auto-commit,否则生成时会锁表) HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://localhost:3306/ry?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8"); config.setUsername("root"); config.setPassword("123456"); config.setDriverClassName("com.mysql.cj.jdbc.Driver"); config.setAutoCommit(false); // ⚠️ 必须设为 false!否则生成过程中执行 SELECT COUNT(*) 会触发事务提交,导致后续 DDL 失败 config.setMaximumPoolSize(5); config.setMinimumIdle(1); config.setConnectionTimeout(30000); config.setIdleTimeout(600000); config.setMaxLifetime(1800000); DataSource dataSource = new HikariDataSource(config); // 2. 构建 DataSourceConfig(注意:这里不调用 setDataSource(dataSource),而是用 builder 方式) DataSourceConfig dsc = new DataSourceConfig.Builder(dataSource) .build(); } }提示:
setAutoCommit(false)是血泪经验。某次在生产环境模拟生成时,因未关闭自动提交,generator在读取表字段前执行了SELECT COUNT(*) FROM sys_user,该语句被 HikariCP 自动开启事务并提交,导致后续CREATE TABLE语句因事务隔离级别问题报错Lock wait timeout exceeded。改成false后,所有查询都在同一连接内完成,无事务干扰。
2.2 自定义 PackageConfig:强制指定各层包路径,避开若依的@MapperScan扫描盲区
若依的ruoyi-admin模块@MapperScan("com.ruoyi.*.mapper*")只扫ruoyi-system下的mapper包,但默认生成器会把 Mapper 接口放到com.ruoyi.system.mapper,而 Service 放到com.ruoyi.system.service—— 这看似合理,实则埋雷:若依的system模块已存在大量同名类(如SysUserService),新生成的类会与原有类冲突。我们必须让生成器把新业务模块(如product)的代码全部放入ruoyi-product模块(需先创建该模块),并确保包路径与若依约定一致。
// 接续上段代码 PackageConfig pc = new PackageConfig.Builder() .parent("com.ruoyi") // 父包名:所有生成类的顶级包 .moduleName("product") // 模块名:生成的子包,最终路径为 com.ruoyi.product.* .entity("domain.entity") // Entity 类放 com.ruoyi.product.domain.entity .mapper("mapper") // Mapper 接口放 com.ruoyi.product.mapper .service("service") // Service 接口放 com.ruoyi.product.service .serviceImpl("service.impl") // ServiceImpl 放 com.ruoyi.product.service.impl .controller("controller") // Controller 放 com.ruoyi.product.controller .xml("mapper.xml") // XML 文件放 resources/mapper/product/ .build();参数说明:
.moduleName("product")不是随便写的。若依的ruoyi-system模块中,SysUser的@TableName("sys_user")表名前缀是sys_,而product模块应统一用product_前缀。因此你在数据库建表时必须用CREATE TABLE product_goods (...),生成器会自动提取product_goods中的product作为moduleName,从而保证@TableName("product_goods")和包路径com.ruoyi.product.*严格对齐。若填错,生成的@TableName会变成@TableName("product_product_goods")—— 这是新手最常踩的坑。
2.3 注入自定义模板路径:替换 Freemarker 模板,解决若依字段注解丢失问题
若依的BaseEntity定义了private Date createTime; private Date updateTime;,并用@TableField(fill = FieldFill.INSERT)标记。但官方模板生成的 Entity 类里,这些字段的注解全没了,因为模板中fieldComment变量未正确传递fill属性。我们必须用自定义 Freemarker 模板,并在InjectionConfig中指定路径。
// 创建 ruoyi-system/src/main/resources/templates/mybatis-plus/ 下的 entity.java.ftl // (内容见后文模板节,此处先配置路径) InjectionConfig cfg = new InjectionConfig.Builder() .data(new HashMap<String, Object>() {{ put("author", "ruoyi"); put("email", "admin@ruoyi.com"); }}) .build(); // 指定模板路径:必须用绝对路径或 classpath:/templates/...,不能用相对路径 String templatePath = "classpath:/templates/mybatis-plus/"; // 注意末尾斜杠! // 配置模板引擎 TemplateConfig tc = new TemplateConfig.Builder() .entity(templatePath + "entity.java.ftl") .mapper(templatePath + "mapper.java.ftl") .xml(templatePath + "mapper.xml.ftl") .service(templatePath + "service.java.ftl") .serviceImpl(templatePath + "serviceImpl.java.ftl") .controller(templatePath + "controller.java.ftl") .build();关键点:
templatePath必须以classpath:/开头,且结尾带/。若你写成"templates/mybatis-plus/",生成器会在当前工作目录找,而 Maven 打包后resources目录不在 classpath 根路径,导致FileNotFoundException。某次 A 同学在 IDEA 里能跑,打包成 jar 后就报错,查了 3 小时才发现是路径写法问题。
3. 模板定制:修复若依特有的字段映射缺陷,让tinyint(1)自动转Boolean、datetime转LocalDateTime
若依的数据库设计习惯用tinyint(1)存布尔值(如status tinyint(1) COMMENT '状态'),但官方模板生成的 Entity 字段是private Integer status;,导致 MyBatis-Plus 的TypeHandler无法自动转换。同样,若依用datetime存时间,而新版 MyBatis-Plus 默认用java.time.LocalDateTime,但模板未声明import java.time.LocalDateTime,编译直接失败。我们必须修改 Freemarker 模板,在entity.java.ftl中加入类型映射逻辑。
3.1 修改 entity.java.ftl:动态判断字段类型并注入对应 Java 类型与注解
在ruoyi-system/src/main/resources/templates/mybatis-plus/entity.java.ftl中,找到字段循环部分(通常为<#list table.fields as field>),将其替换为以下逻辑:
<#list table.fields as field> <#-- 根据 JDBC 类型映射 Java 类型 --> <#assign javaType = ""> <#if field.jdbcType == "TINYINT" && field.columnName?contains("status") || field.columnName?contains("flag") || field.columnName?contains("is_")> <#assign javaType = "Boolean"> <#assign typeHandler = "org.apache.ibatis.type.BooleanTypeHandler"> <#elseif field.jdbcType == "TINYINT" || field.jdbcType == "SMALLINT" || field.jdbcType == "INTEGER"> <#assign javaType = "Integer"> <#elseif field.jdbcType == "BIGINT"> <#assign javaType = "Long"> <#elseif field.jdbcType == "DECIMAL" || field.jdbcType == "NUMERIC"> <#assign javaType = "BigDecimal"> <#elseif field.jdbcType == "VARCHAR" || field.jdbcType == "CHAR" || field.jdbcType == "TEXT"> <#assign javaType = "String"> <#elseif field.jdbcType == "DATETIME" || field.jdbcType == "TIMESTAMP"> <#assign javaType = "LocalDateTime"> <#assign typeHandler = "org.apache.ibatis.type.LocalDateTimeTypeHandler"> <#else> <#assign javaType = "String"> </#if> <#-- 生成字段声明 --> <#if field.keyFlag> <#-- 主键字段加 @TableId --> <#if field.keyIdentityFlag> @TableId(value = "${field.propertyName}", type = IdType.AUTO) <#else> @TableId("${field.propertyName}") </#if> <#else> <#-- 普通字段加 @TableField --> <#if field.fill != "null"> @TableField(fill = FieldFill.${field.fill}) <#elseif field.columnName?starts_with("create") || field.columnName?starts_with("update")> @TableField(fill = FieldFill.INSERT) <#else> @TableField </#if> </#if> private ${javaType} ${field.propertyName}; </#list>逻辑说明:这段 ftl 代码做了三件事:
- 智能类型推断:当字段名为
status/is_deleted/flag且 JDBC 类型为TINYINT时,强制映射为Boolean,并指定BooleanTypeHandler;- 时间类型标准化:所有
DATETIME/TIMESTAMP统一用LocalDateTime,避免Date类型带来的时区混乱;- 填充策略兜底:若字段名含
create或update,自动加FieldFill.INSERT或FieldFill.INSERT_UPDATE,无需手动在数据库注释里写fill=INSERT。
这样生成的ProductGoodsEntity.java里,private Boolean status;和private LocalDateTime createTime;就能直接被 MyBatis-Plus 正确处理。
3.2 补充 import 声明:避免编译错误的隐藏陷阱
在entity.java.ftl的import区域(通常在类声明上方),必须显式添加:
<#if table.fields?exists> <#list table.fields as field> <#if field.jdbcType == "DATETIME" || field.jdbcType == "TIMESTAMP"> import java.time.LocalDateTime; <#break> </#if> </#list> </#if> <#list table.fields as field> <#if field.jdbcType == "TINYINT" && (field.columnName?contains("status") || field.columnName?contains("flag"))> import java.lang.Boolean; <#break> </#if> </#list> // 若依基类需要的注解 import com.baomidou.mybatisplus.annotation.*; import com.ruoyi.common.core.domain.BaseEntity;注意:Freemarker 的
<#break>是跳出当前<#list>,不是整个模板。这里用两个独立的<#list>分别检测是否需要LocalDateTime和Boolean,确保 import 语句只出现一次。曾有项目因重复 importLocalDateTime导致编译报错Duplicate import,排查时发现是 ftl 逻辑没加<#break>。
3.3 生成 XML 的 resultMap 修复:补全 column 与 property 映射,防止字段为空
若依的BaseEntity有createTime/updateTime字段,但官方模板生成的resultMap只映射了业务字段,漏掉了基类字段,导致查询返回的 Entity 中createTime=null。我们在mapper.xml.ftl的<resultMap>标签内插入基类字段映射:
<resultMap id="${table.entityName}ResultMap" type="${package}.domain.entity.${table.entityName}"> <#-- 主键 --> <id property="id" column="id"/> <#-- 基类字段:必须显式声明,否则 MyBatis 不会赋值 --> <result property="createTime" column="create_time"/> <result property="updateTime" column="update_time"/> <result property="createBy" column="create_by"/> <result property="updateBy" column="update_by"/> <#-- 业务字段 --> <#list table.fields as field> <#if !field.keyFlag && !field.columnName?starts_with("create") && !field.columnName?starts_with("update")> <result property="${field.propertyName}" column="${field.columnName}"/> </#if> </#list> </resultMap>参数说明:
column="create_time"必须与数据库字段名完全一致(下划线),property="createTime"必须与 Java 字段名一致(驼峰)。若你的数据库字段是create_time,而 Entity 字段是createTime,这里就不能写column="createTime",否则 MyBatis 找不到列。这是 SQL 查询层与 Java 对象层的映射契约,错一个字符就全 null。
4. 避坑指南:五个真实发生过的生成失败场景,现象、原因、解决方案全记录
生成器不是黑匣子,每一次失败都是工程约束在敲门。以下是某跨平台系统在接入若依时踩出的五个典型坑,按发生频率排序,每一条都附带复现方式和根治方案。
4.1 现象:生成的 Mapper 接口编译失败,报错Cannot resolve symbol 'IPage'
原因:若依的ruoyi-system模块pom.xml中mybatis-plus-boot-starter版本为3.4.3.4,而你用的mybatis-plus-generator是3.5.3.1,二者IPage接口签名不兼容(3.5+ 移除了long getTotal()方法,改为long getTotalCount())。生成器模板按新版本生成代码,但运行时类路径下是旧版 JAR。
解决:统一升级ruoyi-system/pom.xml中的依赖:
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.5.3.1</version> </dependency>验证方法:在
MybatisPlusGenerator.main()中加一行System.out.println(IPage.class.getMethods()[0]);,确认输出为public abstract long com.baomidou.mybatisplus.extension.plugins.pagination.IPage.getTotalCount()。
4.2 现象:生成的 Controller 类里@PreAuthorize("@ss.hasPermi('product:goods:list')")权限注解中的product模块名未替换,仍是@ss.hasPermi('system:user:list')
原因:若依的权限控制基于@PreAuthorize注解,其字符串值由前端菜单配置决定。生成器模板中硬编码了'system:user:list',未读取PackageConfig.moduleName动态拼接。
解决:修改controller.java.ftl中权限注解部分:
<#-- 动态生成权限字符串:${pc.moduleName}:${table.entityName?lower_case}:list --> @PreAuthorize("@ss.hasPermi('${pc.moduleName}:${table.entityName?lower_case}:list')")注意:
pc.moduleName是PackageConfig的属性,table.entityName?lower_case是 Freemarker 内置函数,将ProductGoods转为productgoods,再手动加-分隔符(如product-goods)需额外逻辑,此处简化为下划线。
4.3 现象:生成的 ServiceImpl 类中save()方法报错No qualifying bean of type 'com.ruoyi.product.mapper.ProductGoodsMapper' available
原因:若依的ruoyi-admin模块@MapperScan只扫com.ruoyi.*.mapper*,但新生成的ProductGoodsMapper接口在com.ruoyi.product.mapper包下,而ruoyi-admin的pom.xml未依赖ruoyi-product模块,导致 Spring 容器找不到该 Mapper Bean。
解决:在ruoyi-admin/pom.xml中添加对新模块的依赖:
<dependency> <groupId>com.ruoyi</groupId> <artifactId>ruoyi-product</artifactId> <version>4.7.0</version> </dependency>血泪经验:必须在
ruoyi-admin添加依赖,而不是在ruoyi-system。因为ruoyi-admin是启动模块,SqlSessionFactory在此创建,@MapperScan也在此生效。ruoyi-system只是业务模块,不参与 Mapper 扫描。
4.4 现象:生成的 XML 文件中<insert>标签内useGeneratedKeys="true"生效,但主键未回填到 Entity 的id字段
原因:若依的BaseEntity中id字段是private Long id;,而 MySQL 表的主键是BIGINT UNSIGNED,JDBC 驱动默认将UNSIGNED BIGINT映射为BigInteger,导致useGeneratedKeys返回的BigInteger无法自动转为Long。
解决:在数据库连接 URL 中添加参数tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8,并在entity.java.ftl中为主键字段加类型处理器:
<#if field.keyFlag> @TableId(value = "${field.propertyName}", type = IdType.AUTO) <#if field.jdbcType == "BIGINT"> @TableField(typeHandler = "org.apache.ibatis.type.LongTypeHandler") </#if> private ${javaType} ${field.propertyName}; </#if>4.5 现象:生成的 Vue 页面中el-table-column的prop值为createTime,但后端返回 JSON 中字段是create_time
原因:若依的Jackson配置了PropertyNamingStrategies.SNAKE_CASE,将createTime序列化为create_time,但生成的前端模板未同步该规则,仍用驼峰名。
解决:修改controller.java.ftl中的@ResponseBody方法,添加@JsonFormat注解:
@GetMapping("/list") @PreAuthorize("@ss.hasPermi('${pc.moduleName}:${table.entityName?lower_case}:list')") public TableDataInfo list(${table.entityName} ${table.entityName?uncap_first}) { startPage(); List<${table.entityName}> list = ${table.entityName?uncap_first}Service.select${table.entityName}List(${table.entityName?uncap_first}); return getDataTable(list); }并在entity.java.ftl中为时间字段加:
<#if field.jdbcType == "DATETIME" || field.jdbcType == "TIMESTAMP"> @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") </#if> private ${javaType} ${field.propertyName};验证技巧:用 Postman 调用
/product/goods/list,看响应 JSON 中字段名是create_time还是createTime。若是后者,说明@JsonFormat未生效,需检查ruoyi-admin的WebMvcConfigurer是否覆盖了 Jackson 配置。
5. 前端页面生成:从 Java Entity 到 Vue 表单的字段级联动,自动生成校验规则与字典绑定
生成后端代码只是起点,若依的真正效率提升在于“一次生成,两端可用”。我们扩展生成器,让它解析 Entity 字段上的@TableField注解和数据库COMMENT,自动生成 Vue 页面的el-form-item配置、rules校验对象、以及字典下拉框的dict-type属性。这比手写v-model和:rules快 5 倍,且零出错。
5.1 解析数据库 COMMENT 生成字典类型:让status tinyint(1) COMMENT 'sys_normal_disable'自动绑定字典
MyBatis-Plus Generator 本身不读取数据库COMMENT,但我们可以通过DatabaseMetaData手动获取,并注入到模板变量中。在MybatisPlusGenerator.java中增强InjectionConfig:
// 获取表字段注释 Map<String, String> columnComments = new HashMap<>(); try (Connection conn = dataSource.getConnection(); DatabaseMetaData metaData = conn.getMetaData()) { ResultSet rs = metaData.getColumns(null, null, table.getName(), "%"); while (rs.next()) { String columnName = rs.getString("COLUMN_NAME"); String remarks = rs.getString("REMARKS"); if (remarks != null && remarks.contains("dict-type:")) { // 提取 dict-type 值,如 'sys_normal_disable' String dictType = remarks.split("dict-type:")[1].trim().split(";")[0]; columnComments.put(columnName, dictType); } } } // 注入到模板 InjectionConfig cfg = new InjectionConfig.Builder() .data(new HashMap<String, Object>() {{ put("columnComments", columnComments); }}) .build();然后在controller.java.ftl中,当生成 Vue 页面时(我们另建vue/form.vue.ftl),读取该 Map:
<#list table.fields as field> <#if columnComments[field.columnName]??> <!-- 字典字段:生成 el-select --> <el-form-item label="${field.fieldComment!}" prop="${field.propertyName}"> <el-select v-model="form.${field.propertyName}" placeholder="请选择"> <el-option v-for="item in dictOptions.${columnComments[field.columnName]}" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue"/> </el-select> </el-form-item> <#else> <!-- 普通字段 --> <el-form-item label="${field.fieldComment!}" prop="${field.propertyName}"> <el-input v-model="form.${field.propertyName}" placeholder="请输入${field.fieldComment!}"/> </el-form-item> </#if> </#list>参数说明:
field.fieldComment!中的!是 Freemarker 的空安全操作符,当数据库未设 COMMENT 时返回空字符串,避免模板报错。dictOptions是若依前端已有的字典数据对象,columnComments[field.columnName]提取的sys_normal_disable会作为 key 访问dictOptions.sys_normal_disable数组。
5.2 自动生成表单校验规则:根据字段类型与 NOT NULL 约束生成rules
若依的 Vue 表单校验规则写在data()函数中,格式为:
rules: { productName: [{ required: true, message: '商品名称不能为空', trigger: 'blur' }], status: [{ required: true, message: '状态不能为空', trigger: 'change' }] }我们让生成器自动分析field.nullable和field.jdbcType,生成对应规则:
<#assign rules = []> <#list table.fields as field> <#if field.nullable == false> <#if field.jdbcType == "VARCHAR" || field.jdbcType == "TEXT"> <#assign rule = "{ required: true, message: '${field.fieldComment!}不能为空', trigger: 'blur' }"> <#elseif field.jdbcType == "TINYINT" || field.jdbcType == "INTEGER"> <#assign rule = "{ required: true, message: '${field.fieldComment!}不能为空', trigger: 'change' }"> <#else> <#assign rule = "{ required: true, message: '${field.fieldComment!}不能为空', trigger: 'blur' }"> </#if> <#assign rules = rules + [rule]> </#if> </#list> rules: { <#list rules as rule> ${field.propertyName}: [${rule}]<#if rule?has_next>, </#if> </#list> }逻辑说明:
field.nullable == false对应数据库NOT NULL约束;trigger: 'blur'用于输入框失焦校验,trigger: 'change'用于下拉框选中校验。这样生成的rules对象,与若依前端校验机制 100% 兼容,无需任何手动调整。
5.3 生成字典数据初始化代码:在 Vue 页面 created 钩子中自动调用getDicts()
若依前端通过getDicts(dictType)方法加载字典,我们需要在生成的 Vue 页面created()钩子中,自动调用所有用到的字典类型:
created() { <#list table.fields as field> <#if columnComments[field.columnName]??> this.getDicts('${columnComments[field.columnName]}'); </#if> </#list> }验证方法:打开浏览器开发者工具,切换到 Network 标签页,刷新生成的 Vue 页面,确认请求了
/system/dict/data/dictType/sys_normal_disable等接口。若未请求,检查columnCommentsMap 是否为空,或数据库 COMMENT 格式是否为dict-type:sys_normal_disable。
从那以后我每次新增业务表,都强制走一遍这五步:先建表并写好COMMENT(含dict-type),再运行MybatisPlusGenerator.main(),生成后立刻mvn compile检查编译错误,接着启动前端npm run dev看表单渲染,最后用 Postman 测试 CRUD 接口。这套流程跑顺后,一个标准的增删改查模块,从建表到联调完成,稳定在 12 分钟以内。中间任何一步卡住,我就回溯到对应章节的避坑指南,基本 5 分钟内定位。希望帮到你。
本文还有配套的精品资源,点击获取