简介:这是一款面向IntelliJ IDEA开发者的独立代码生成插件,尤其适合使用Spring Boot + MyBatis框架的中高级Java工程师。插件不依赖任何现有项目代码,只需配置数据库连接并读取表结构,即可一键生成mybatis映射配置文件、实体类、Service接口、Service实现类以及增删改查Controller,帮助快速搭建分层清晰的Web项目骨架,大幅减少手写重复代码的时间。压缩包共包含52个文件,其中42个class类为插件核心逻辑,5个jar包提供MyBatis生成器、MySQL连接等依赖支持,另有3张使用示意图片和2个插件描述文件,整体仅2.05MB,轻量易部署。目前已有362人学习下载。无论是日常快速开发、数据库模型频繁调整,还是团队统一代码规范,这款插件都能有效提升开发效率,让开发者专注于业务逻辑而非基础CRUD代码。
1. 从逆数据库表到自动代码:独立IDEA插件解决的是哪一类麻烦
看到“无需项目代码支持”这几个字,做过代码生成的人应该立刻明白它的价值:以前跑一套生成器,要么往项目的构建脚本里塞插件,要么扛着整个项目的依赖和类路径一起编译,依赖冲突、版本兼容、模块顺序全得伺候一遍。而根据数据库表自动代码的独立IDEA插件,自己管理数据库驱动和模板引擎,打开IDEA连上数据源、勾选几张表、填好包名,就能直接产出实体类、Mapper接口和XML映射文件,跟当前项目是Spring Boot还是老式SSH没有关系。这篇笔记要讲清楚它和项目内生成器的本质差异、最小可复现的操作流程、参数怎么调,以及那些最容易翻车的连接和覆盖问题。
2. 独立插件与项目内生成器的本质差异:为什么它能不碰项目代码
2.1 类路径、模板上下文与生成时机的三点区别
市面上常见的代码生成方案可以按运行位置分成两类:一类是塞进项目构建脚本里的生成器,另一类是运行在IDE进程里的独立插件。前者最常见的形式是Maven插件,执行时要读取当前项目的编译类路径,数据库连接配置也从项目的配置文件里取,驱动能否加载受项目依赖树影响。后者则不读项目类路径,插件自己维护一份JDBC驱动,连接参数由IDE的数据源窗口管理,生成代码这个动作本质上是“连库、读表结构、套模板、写文件”。
这两条路在模板上下文上差别很大。项目内生成器能访问项目里已有的类,比如可以用自定义类型处理器处理特殊字段,也能把生成的代码与项目编译顺序绑定;独立插件碰不到项目代码,只能靠插件内置模板加上少量外部模板文件来生成文本。这个限制反过来也成了优点:产物格式非常统一,不受项目里各种全局配置、注解处理器和代码风格干扰。
生成时机是另一个容易被忽略的分水岭。项目内生成器可以在构建阶段自动执行,适合在CI流水线里跑,但每次执行都要经历项目编译周期的初始化;独立插件是鼠标触发的交互式动作,先由人确认哪些表、哪种风格、生成到哪个目录,再一次性出结果。从我的使用经验看,独立插件更适合那种“不打算把生成器写进业务项目、但又要频繁给不同项目出CRUD代码”的场景。
2.2 什么时候选独立插件:场景与取舍
| 对比维度 | 项目内生成器 | 独立IDEA插件 |
|---|---|---|
| 依赖范围 | 依赖项目类路径与依赖树 | 独立管理驱动,不读项目依赖 |
| 执行方式 | 构建阶段自动执行 | 数据源选表后手动触发 |
| 模板上下文 | 可访问项目内类和配置 | 只能访问插件模板与外部模板文件 |
| 产物一致性 | 受项目配置影响 | 统一 |
| 老项目适配 | 容易被依赖冲突拖累 | 只要IDE能连库就能生成 |
| 适合场景 | 新项目、强CI集成 | 遗留系统、多技术栈、原型开发 |
我一般这样判断:如果是一个全新项目,技术栈单一,还希望每次构建都自动同步数据库里的表结构变化,那就用项目内生成器,自动化收益更高;如果是一个运行了好几年的老系统,模块里既有Spring Boot也有SpringMVC,甚至有些模块根本没有标准的构建规范,这时候独立插件就比往每个模块里塞生成依赖省心得多。
到了教学和原型验证场景,独立插件几乎是首选。团队里新同学要想在半天内理解“订单表对应哪些数据访问代码”,直接拿一张真实表生成一遍比翻十分钟文档更直观。反过来,如果公司有统一代码规范,生成器内置模板又改不动,那还是得找能自定义模板的独立插件版本,这条后面第六章专门说。
3. 从连接数据库到生成代码:最小可复现的操作流程
3.1 安装插件与建立数据源:URL、驱动与Schema三件套
拿到的是zip包,安装方式就很简单:打开IDEA的插件设置页,点击齿轮按钮,选择从磁盘安装插件,选中这个zip文件后重启IDE。重启后左侧会出现数据库工具窗口的入口,生成相关菜单会挂在表节点的右键菜单里。注意插件安装后不需要在具体项目里加任何依赖,这正好对应标题里说的“无需项目代码支持”。
接下来建立数据源。打开数据库工具窗口,点击加号选择数据库类型。以MySQL为例,连接信息里最核心的是JDBC URL,我经常用的一段配置长这样:
jdbc:mysql://localhost:3306/biz_mall?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true这段URL里的参数值得逐一说清楚。useUnicode=true和characterEncoding=utf8解决中文注释乱码问题,少了它们生成的实体注释大概率是“?”;serverTimezone=Asia/Shanghai在处理DATETIME字段时能避免时区偏移;allowPublicKeyRetrieval=true是MySQL 8.0以上版本常见的连接报错来源,缓存SHA2密码插件在首次连接时需要这个开关。另一个常被忽略的是驱动本身:如果IDE自动下载驱动失败,可以手动下载驱动jar包,然后在数据源设置里选择“替换驱动”,指定本地jar路径。
数据源连接成功后,还有一个隐藏坑:MySQL里库就是schema,但SQL Server和Oracle不是,它们的实例下面有多个schema,必须在下拉框里选中目标schema,否则表列表是空的。这个选择动作直接影响后面能不能看到表,值得在连接信息里先确认一遍。
3.2 选表与配置生成项:包名、目标目录与覆盖策略
连接建好后,展开目标库,能看到表清单。按住Ctrl或Cmd可以多选,选完右键,菜单里找到生成代码入口。弹窗里通常会有下面这组配置,不同插件的命名略有差异,但核心参数基本一致:
| 配置项 | 默认值 | 建议 |
|---|---|---|
| 输出根目录 | 弹出时指向当前模块 | 先生成到临时目录或独立目录,确认产物再移动 |
| 包名 | 无 | 用业务域名逆写,如com.example.mall |
| 实体类 | 勾选 | 保留 |
| Mapper接口 | 勾选 | 保留 |
| XML映射文件 | 视项目而定 | MyBatis项目必勾 |
| Service/ServiceImpl | 按需 | 不需要就关掉 |
| 覆盖策略 | 存在则跳过 | 先跳过,避免覆盖手写逻辑 |
| Lombok注解 | 关闭 | 项目用Lombok再开 |
| Swagger注解 | 关闭 | 接口要接文档再开 |
这里最需要注意的是输出目录。很多插件默认指向当前模块的src/main/java,但我建议第一次生成时改到一个独立目录,比如项目外的generated-code目录。生成完先扫一眼产物,确认实体字段、注释、类型映射都符合预期,再手动拷进项目里。这样即使用错了覆盖策略,也不会直接伤害业务代码。
选择表时可以按前缀过滤,比如t_biz_order、t_biz_user这样的表,可以在插件里配置表前缀,生成出来的类名会是BizOrder而不是TBizOrder。这一步在参数面板里通常叫“表前缀”,配置了能省掉后面改类名的工作。
3.3 生成后的目录落位与IDEA源码根标记
一次典型的生成结果长这样:
generated-code/ ├── entity/ │ └── Order.java ├── mapper/ │ ├── OrderMapper.java │ └── xml/ │ └── OrderMapper.xml └── service/ ├── OrderService.java └── impl/ └── OrderServiceImpl.java生成完成后,IDEA里经常出现一种“半翻车”状态:文件在磁盘上能看到,编辑器里也能打开,但Java文件里所有相关类都标红,提示找不到符号。原因多数是生成目录没有被标记为源码根。解决方法是右键生成的目录,选择“将目录标记为→源根”;如果XML文件也要放进classpath,则把xml目录标记为“资源根”。
这一步做完,还要留意生成目录是否被版本控制忽略。我的习惯是在.gitignore里控制生成目录的提交策略:如果团队希望生成代码进仓库,就正常提交;如果希望每个人本地自己生成,就忽略掉。无论哪种策略,都要在README里写清楚生成命令和参数,不然新同学第一次跑完会困惑为什么自己生成的代码和别人的不一样。
4. 生成参数体系:类型映射、继承与命名策略怎么调
4.1 数据库字段到Java类型的默认映射表
插件里最值得先摸清的是字段类型映射表,这决定了生成出来的实体类到底能不能直接用。以MySQL为例,常见的默认映射关系如下:
| 数据库类型 | Java类型 | 备注 |
|---|---|---|
| INT / INTEGER | Integer | 无符号INT建议用Long |
| BIGINT | Long | 主键常用 |
| TINYINT | Byte | TINYINT(1)有的插件映射Boolean |
| VARCHAR / CHAR | String | 注意长度不产生校验 |
| TEXT / LONGTEXT | String | 可能建议改用业务字段拆分 |
| DECIMAL / NUMERIC | BigDecimal | 金额字段一定要用它 |
| DATE | LocalDate | 新项目默认时间类型 |
| DATETIME / TIMESTAMP | LocalDateTime | 带时区要用正确连接参数 |
| BLOB | byte[] | 一般不建议生成 |
这张表里最容易翻车的是TINYINT(1)。很多插件的默认规则会把TINYINT统一映射成Byte,但业务表里“deleted”这种布尔标记在MySQL里常用TINYINT(1)表示,Byte类型的实体字段配合前端JSON序列化时会出现类型不匹配。如果插件提供“TINYINT(1)映射为Boolean”的开关,建议开启,否则生成后需要手动改字段类型。
DECIMAL字段则是另一个经典问题。数据库里price DECIMAL(10,2)如果生成成Double,后面在计算金额时会有精度损失。默认规则里DECIMAL映射BigDecimal是比较稳妥的,但要注意有些插件需要额外开启“使用BigDecimal”选项,否则会退回Double。生成后检查一遍金额字段和状态字段的类型,基本能避开这两个最常见的映射坑。
4.2 必须调校的三组参数:基类、注解与注释头
第一组参数是基类设置。很多项目在规划表结构时会约定所有业务表都带id、create_time、update_time这几个公共字段,如果每个实体都重复生成这几个字段,代码冗余不说,后面加审计字段要改几十个类。插件一般允许指定一个实体基类,比如BaseEntity,生成时子类里只保留业务字段,公共字段从基类继承。
第二组参数是注解开关。Lombok、MyBatis-Plus、Swagger这三类注解是按项目实际情况决定的。一个典型的生成结果长这样:
package com.example.mall.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; @Data @TableName("t_biz_order") public class Order { @TableId(type = IdType.AUTO) private Long id; private String orderNo; private BigDecimal amount; private LocalDateTime createTime; }这段代码里@Data是Lombok生成的getter和setter,@TableName把实体映射到物理表名,@TableId标记主键并指定自增策略。如果项目里用的是MyBatis-Plus,这三个注解是后续写条件构造器的基础;如果项目是原生MyBatis,TableName和TableId这些注解就不会引入,XML里的resultMap承担字段映射职责。
第三组参数是类注释和作者信息。有些插件会在每个类头上生成@author,值默认取系统用户名。团队规范里如果要求统一注释模板,这里要手动改成固定值。我一般建议把注释头里的“生成日期”保留,但作者信息用团队公共账号,避免代码评审时出现一堆私有用户名。
4.3 命名策略:下划线转驼峰与字段前缀的边界
命名策略决定了user_name变成userName还是username。绝大多数插件默认开启下划线转驼峰,这个没问题。但有几个边界情况需要确认:带有多个连续下划线的列名,比如user__name,不同插件的处理逻辑不一样,有的会变成UserName,有的直接去掉所有下划线变成userName,这会在生成后引起字段不一致。
表前缀处理也在这里配置。像t_biz_order这样的表,生成类名时要先剥离t_biz_再转驼峰,否则类名会带着前缀后缀,看起来非常别扭。插件里的“表前缀”一般支持多个值,逗号分隔,生成时会取匹配最长的一个前缀剥离。
布尔字段的is_前缀是另一个容易踩的地方。数据库列名is_deleted,生成时如果剥掉is会变成deleted,配合Lombok的@Data生成的getter是getDeleted();如果不剥,字段名是isDeleted,生成的getter变成getIsDeleted()。这两种风格在Java序列化时行为有差异,一定要在生成前确认团队规范里用的是哪种,否则后面联调时对接方会疑惑字段名对不上。
5. 避坑与排查:独立插件最容易翻车的五个实操细节
5.1 连接类坑:驱动装上却连不上、表列表为空、中文注释乱码
现象:数据源设置里驱动已经选择成功,点“测试连接”却报Connection refused或Access denied。原因往往是URL端口写错,或者MySQL版本服务端使用缓存SHA2密码明文传输需要额外参数。解决:确认数据库端口,MySQL默认3306,如果本机装了多个实例很容易连到错误的端口;在URL里补充allowPublicKeyRetrieval=true&useSSL=false再测试。
现象:连接成功,但数据源下面展开后看不到任何表。原因:连接的是实例级信息,没有选中具体schema。MySQL还好一些,库里schema和database等同,但SQL Server和Oracle必须在下拉框里选定schema。解决:编辑连接,在“Schema”标签页勾选目标库,重新展开。
现象:表能看到,但生成出来的类里中文字段注释变成???或者乱码。原因:连接URL里缺少characterEncoding=utf8和useUnicode=true,或者IDEA的文件编码与数据库传输编码不一致。解决:补上字符集参数后重连;如果文件里局部乱码,检查IDEA右下角文件编码标识,改成UTF-8后重新生成。
5.2 生成结果类坑:目录不被识别、XML没资源标记、覆盖手写逻辑
现象:生成后的Java文件在编辑器里打开,所有符号都标红,项目编译直接失败。原因:生成目录没有被标记为源码根,IDEA不把它当作可编译代码。解决:右键目录选择“将目录标记为→源根”;对XML文件则要标记为“资源根”,否则启动时提示找不到Mapper对应XML。
现象:重新生成之后,发现之前手动修改的逻辑没了。原因:插件没有合并能力,覆盖策略设置成了“总是覆盖”,相同输出路径下直接文本级覆盖。解决:把覆盖策略改成“存在则跳过”;如果确实需要更新,先用git看一遍diff,确认手写改动已经提交或备份。我的习惯是生成目录和手写目录分开,生成代码只做初版,后续所有修改变动都挪到手写目录或直接在生成文件上改并提交。
5.3 主键类坑:主键识别错误、联合主键、逻辑删除字段
现象:生成的updateById方法里条件只带了id,但表其实没有主键,或者主键字段名叫order_id,而插件默认把第一个叫id的字段当主键。原因:插件读取表元数据时依赖驱动返回的主键信息,没有主键的表或非标准主键命名会影响判断。解决:在生成前对表执行SHOW KEYS FROM 表名看主键情况;如果没有主键,最好在数据库侧补上,否则生成出的更新操作可能把整行字段都写进条件,造成批量误更新。
现象:联合主键的表现在只生成了一个@TableId。原因:大多数插件只支持单主键策略,联合主键需要框架支持。解决:生成后手动为联合主键补充注解;如果用的是MyBatis-Plus,可以在实体里对第二个主键字段标注普通@TableField,并在XML里手写复合条件SQL。
现象:表里有deleted字段,生成出来的实体没有逻辑删除注解,执行删除时走了物理删除。原因:插件默认不会识别业务约定字段。解决:在插件参数里配置逻辑删除字段名和乐观锁字段名,比如deleted、version,让它自动生成@TableLogic和@Version。忽略这个配置,上线后误删数据是迟早的事。
6. 进阶用法:把插件变成团队内的半自动脚手架
6.1 自制模板与变量清单
独立插件的优势之一是模板可以拿出来改。多数插件在设置里提供导出模板功能,导出后会看到一组包含Velocity或FreeMarker语法的模板文件。以实体类模板为例,核心变量通常是$table.name、$table.remark、$table.columns,一个简化版模板长这样:
package $packageName; import java.math.BigDecimal; import java.time.LocalDateTime; /** * $table.remark */ public class $table.camelName { #foreach($column in $table.columns) /** $column.remark */ private $column.javaType $column.camelName; #end }模板里的$table.camelName是表名转驼峰后的类名,$column.javaType是根据映射表算出的Java类型,$column.remark是数据库列注释。改模板前先打印一次变量列表,确认字段名再动手,避免改完语法不对反复试错。修改模板后重新生成,就能得到团队统一风格的代码。
6.2 生成后的验证清单与使用习惯
生成动作完成不代表可以放心提交,我每次生成后会按这份清单过一遍:
| 检查项 | 检查方式 |
|---|---|
| 表数量与生成文件数一致 | 对比数据源表清单与目录文件 |
| 主键字段正确 | 看实体里的@TableId或XML的resultMap主键项 |
| 金额字段类型是BigDecimal | 搜索Double排除异常 |
| 时间字段是LocalDateTime | 搜索java.util.Date排除旧类型 |
逻辑删除字段带@TableLogic | 全局搜索TableLogic |
| XML文件未被上次生成覆盖 | 用git diff查看变动文件 |
我最早的教训是在一张订单表上直接覆盖生成,把同事手动调过的状态枚举逻辑冲掉了,那次之后我养成了两个习惯:第一,生成目录和手写目录从物理上分开;第二,每次生成后第一件事是git status看文件变动清单,再决定哪些文件要保留。如果你也准备在团队里引入这套独立插件的生成流程,把这个检查习惯当作默认动作,希望帮到你。
本文还有配套的精品资源,点击获取