1. 为什么我会折腾代码生成工具
干后端开发的,谁没被CRUD折磨过。业务接口、DAO层、Mapper文件、Service实现,写来写去就那么几套固定的套路:查列表、查单条、插入、更新、删除。每个表都得来一遍,新表多了以后,一上午时间基本就耗在这上面了。我最早是手动复制模板再改表名,后来也试过自己写freemarker脚本生成,但维护脚本本身也是成本。直到有个同事给我推荐了EasyCode这个IDEA插件,我才真正觉得这问题算是彻底解决了。
EasyCode是一个基于IntelliJ IDEA的代码生成插件,核心思路很直接:你连上数据库,选中一张表,它就能按照你预设的模板批量生成对应的实体类、Mapper接口、XML映射文件、Service、ServiceImpl和Controller。它本身不绑定任何框架,Spring Boot配MyBatis、MyBatis Plus、JPA都能用,关键在于模板完全可定制,用的是Velocity模板引擎。
这个工具适合谁?如果你是每天要处理大量数据表的业务开发,或者团队刚立项想统一代码规范,又或者你只是不想一遍遍敲那些重复的getter和setter,EasyCode都值得花半小时研究一下。它不挑项目规模,一个小接口也能用,一套微服务照样能跑。这篇文章我按自己的实操路线,把从安装、配置、生成到自定义模板的完整流程写一遍,顺便把我踩过的坑都列出来,照着做基本能少走一半弯路。
2. 安装配置与前置准备
2.1 插件安装:两个路径随便选
EasyCode的安装没什么特殊门槛。打开IDEA,进入File -> Settings -> Plugins,在Marketplace搜索框里输入EasyCode,找到那个图标是绿色闪电的工具,点击Install然后重启IDE就行。如果你的网络环境访问插件市场不太稳定,也可以去JetBrains插件仓库直接下载zip包,然后通过Install Plugin from Disk安装,注意选压缩包而不是解压后的文件夹。
有一点要留个心眼:EasyCode的版本和你的IDEA版本有兼容性要求。旧版IDEA(2020之前)装新版插件,很可能直接提示插件版本不兼容导致无法启用。我见过有人卡在这里,怎么装都装不上,最后发现就是IDE版本太老。装机前先确认一下自己IDEA的版本号,能省不少事。
安装完成之后,IDEA右侧工具栏会出现一个EasyCode的侧边栏面板,里面能看到数据库连接信息、模板列表和生成记录。如果你打开后是空的,别急,那是还没配置数据源。
2.2 数据库连接:生成代码的前提
EasyCode本身不带数据库连接功能,它依赖IDEA内置的Database面板。也就是说,你先得让IDEA能连上你的库,EasyCode才能读表结构来生成代码。这个先后顺序很多人弄反了,一直在EasyCode面板里找连接入口,自然找不到。
操作路径是:IDEA右侧Database面板 -> 左上角加号 -> Data Source -> 选择你的数据库类型(MySQL、PostgreSQL、Oracle、SQL Server都支持)。以最常见的MySQL为例,填Host、Port、User、Password、Database名称。填完先点Test Connection测试连通性,显示Succeeded之后再点OK保存。
这里有个常见坑:测试连接报Server returns invalid timezone。这是MySQL驱动8.x版本对时区敏感导致的。解决办法是在Connection URL末尾加上参数,比如jdbc:mysql://localhost:3306/demo_db?serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true。这三个参数我建议都写上,serverTimezone解决时区报错,useSSL=false避免SSL握手告警,allowPublicKeyRetrieval=true解决某些MySQL版本需要获取公钥的问题。
2.3 连接配置里的细节参数
如果你用的是公司内网数据库,可能还要涉及SSH隧道或者只读账号,这些在Database面板的Advanced/SSH标签页里都有对应配置项,按公司提供的参数填即可。我个人建议连库用一个有SELECT权限的账号就够了,EasyCode只需要读取表结构和字段元数据,不需要写权限,用最小权限原则能避免误操作。
另外有个小细节:连上数据库之后,记得在Database面板里展开表列表,右键选择要生成的表,会看到EasyCode的入口菜单。如果你的表特别多(比如几百张),可以配合IDEA的搜索过滤功能先筛选,不然下拉列表看着也累。
3. 模板体系:EasyCode的心脏
3.1 内置模板到底帮我们生成了什么
EasyCode的魅力不在生成按钮,而在那套模板体系。它默认带了一套基于Spring Boot + MyBatis风格的模板,包括entity.java、dao.java、service.java、serviceImpl.java、controller.java和mapper.xml这六个文件。你选中一张表执行生成,它会在指定包路径下把这六个文件全部创建出来,对应关系大致是这样的:
| 模板文件 | 生成的类 | 主要职责 |
|---|---|---|
| entity.java | 实体类 | 对应表字段,含Getter/Setter |
| dao.java | DAO接口 | 定义数据访问方法 |
| mapper.xml | MyBatis映射文件 | SQL语句与结果映射 |
| service.java | Service接口 | 业务逻辑接口定义 |
| serviceImpl.java | Service实现 | 业务逻辑实现 |
| controller.java | 控制器 | REST接口入口 |
理解这个结构之后,你就会明白为什么说EasyCode是模板驱动的生成工具:它生成的代码长什么样,完全由模板决定,而不是插件写死的。默认模板生成的是经典MyBatis风格的代码,如果你的项目用的是MyBatis Plus,默认模板生成的DAO接口其实不太合适,需要自己调整模板让DAO继承BaseMapper<T>。这个我们在后面自定义模板的部分细说。
3.2 Velocity模板语法速通
EasyCode的模板基于Apache Velocity引擎,写起来比Freemarker还要简洁。核心语法就三个,记熟了基本就能改模板:
变量渲染用$符号开头,比如$!tableInfo.name表示当前表的表名,加!的意思是如果变量为空就输出空字符串而不是"null"。整表遍历用#foreach($column in $tableInfo.fullColumn),循环体里面$column.name是字段名、$column.comment是注释、$column.obj是对应Java类型信息。条件判断用#if($column.type.equals("String"))这种形式,配合#end结束。
模板里的换行和缩进会直接带进生成结果。这个细节很关键,我就因为模板里多了一个多余的空行,生成的实体类里每两个字段之间都有一个空行,代码风格检查直接报错。所以改模板时,宁可紧凑一点,也别留游离的空行,调一次Scalar格式成本很高。
3.3 类型映射:数据库字段到Java类型的桥梁
数据库里的一张表,在模板里通过$tableInfo这个对象访问,字段列表通过$tableInfo.fullColumn拿到。每个字段对象$column身上带着数据库类型、Java类型、注释、字段名等属性。其中类型映射的逻辑是:EasyCode会读数据库字段类型,然后映射到对应的Java类型,比如数据库的varchar映射为String,bigint映射为Long,datetime映射为Date。
这个映射关系是可配置的。在EasyCode面板里有个Type Mapper的Tab页,列出了各种数据库类型到Java类型的对应表。如果你的项目里时间字段用的是LocalDateTime而不是java.util.Date,直接在这个映射表里改即可。改完之后所有模板里的$column.obj.type都会跟着变,比到每个模板里逐个改要高效得多。
4. 一键生成代码的完整实操
4.1 生成前的工程准备
到了实操环节,我建议你先花两分钟把包路径想清楚。EasyCode生成代码时要求你指定一个根包路径(packageName),它会在这个包下面按controller、service、dao、entity、mapper这样的子包结构自动建目录并放文件。比如你的项目groupId是com.example.demo,通常填com.example.demo作为rootPackage,生成时自然会创建出com.example.demo.controller这样的包。
如果你的项目是多模块工程,每个子模块有自己的根路径,那就分别对每个模块执行生成,选对应的路径。另外确认一下项目里是否已经存在同名的文件,EasyCode默认会跳过已存在的文件不会覆盖,除非你在生成对话框勾选了覆盖选项。第一次用的人容易困惑"怎么没生成?",其实大部分情况就是文件已存在被跳过了。
4.2 选中表和生成参数
在Database面板里,右键点击目标表(可以多选),选择EasyCode -> Generate Code。此时会弹出生成对话框,左侧是模板分组列表,右侧是根包路径、实体类名、是否需要Lombok等选项。
我的习惯是这样的:单表操作直接右键生成;多张表一起生成时,先按业务模块筛选好表再一起选,这样生成的包结构整齐。对话框里的模板分组如果之前没自定义过,就选默认Default分组。实体类名默认是表名去掉下划线转驼峰,比如user_info变成UserInfo,这个规则一般不用动。
有一个值得注意的参数是"实体类名后缀",很多项目习惯在实体类后面加Entity后缀,比如UserEntity。模板里默认没有这个后缀,你可以在生成对话框里直接改,或者去模板配置里加全局变量统一控制。我更推荐改模板,因为对话框里每次都要手动填,容易漏。
4.3 生成结果验收:我的检查清单
代码生成不是点完按钮就完事了,我每次都会按下面这个清单过一遍:
第一,检查实体类字段类型。特别是那些数据库里定义得很随意的小数字段,比如tinyint默认映射成了Byte,但业务上这个字段可能是个状态码,用Integer更合适。这个在Type Mapper里可以全局改,但更稳妥的做法是生成完肉眼扫一遍。
第二,检查Mapper XML里的SQL语法。EasyCode生成的SQL基础语句基本可靠,但遇到多表关联、复杂where条件还是得自己补。生成结果只能算脚手架,别指望它完成全部业务逻辑。
第三,编译测试。生成完先跑一下mvn compile,确认没有任何引用错误再继续往下写代码。引入EasyCode之后我养成的习惯是:生成完第一时间编译,有问题当场处理,不要堆到后面。
5. 自定义模板实战:把团队规范固化到模板里
5.1 为什么不满足于默认模板
默认模板生成的代码能跑,但真的只停留在"能用"的水平。比如默认模板生成的Controller里没有统一返回格式,没有全局异常处理注解,实体类上也没有@TableName这种MyBatis Plus注解。说白了,默认模板是给一个干净的新项目准备的,如果你的项目有自己的一套代码规范,比如所有Controller必须继承一个BaseController,或者所有实体类必须实现序列化接口,那默认模板生成的代码就得一个个手动改,生成了等于没生成。
所以我的建议是:拿到插件先别急着用,花半小时把模板改成符合自己团队规范的样子,这是一次性投入长期受益的事情。代码质量的核心其实不是生成工具本身,而是模板内容的约束能力。模板写好了,每一个新表生成的代码都是齐整的,代码review的压力会小很多。
5.2 模板编辑器里怎么动手改
EasyCode面板的第二个Tab就是Template模板列表,双击某个模板可进入编辑界面。界面左边是模板代码,右边是变量说明和语法提示,改动保存后立即生效,不需要重启IDEA。
举个例子。默认的dao.java模板生成的是纯粹的接口方法定义。如果你的项目用MyBatis Plus,想让生成的DAO接口继承BaseMapper<UserInfo>,只需要在模板里把接口声明改成这样:
public interface $!{tableInfo.name}Dao extends BaseMapper<$!{tableInfo.name}> { }同时把Mapper XML里内置的那些基础SQL删掉,因为MyBatis Plus内置了通用方法,再生成一遍xml反而会有重复的select/insert语句。这个改动看着小,但能让生成的代码一下子贴合MyBatis Plus的开发方式。
再比如Controller模板,我习惯让生成的类带上@RestController和@RequestMapping注解,并且方法统一返回项目自定义的Result<T>包装类。模板里直接写死返回类型,生成出来每个Controller就都统一了。
5.3 一套我常用的模板写法参考
这里分享一个我改过的Service接口模板片段,算是抛砖引玉:
package $!{package.Service}; import $!{package.Entity}.$!{tableInfo.name}; import com.baomidou.mybatisplus.extension.service.IService; /** * $!{tableInfo.name} 服务接口 */ public interface $!{tableInfo.name}Service extends IService<$!{tableInfo.name}> { /** * 分页查询 */ Page<$!{tableInfo.name}> queryPage($!{tableInfo.name} query, int pageNum, int pageSize); }注意模板里用到$!{package.Service}和$!{package.Entity}这两个变量,它们是EasyCode根据根包路径自动计算出来的子包路径。模板写多了之后你会发现,EasyCode提供了一套上下文变量,包括当前表信息、包路径、作者、日期等,在编辑界面右侧都能查到说明。
改模板的核心原则就一条:以你项目里手写最顺手的那个类为蓝本,把它提炼成模板。不要把别处的规范硬塞进模板,比如你们项目本身不用Lombok,模板里就不该出现@Data注解,生成的代码要符合团队真实工作方式才算好模板。
5.4 模板分组的妙用
EasyCode支持配置多个模板分组(Group),每个分组里可以放完全不同的一套模板。这功能微服务场景下特别好用。比如你的基础服务用MyBatis Plus,报表服务用原生MyBatis,两个项目的代码风格不一样,那就配两个分组,生成时选对应的分组就行,不用来回改模板。
分组之间支持复制,如果新的分组只是某些模板不一样,可以先复制再增量修改,效率高很多。
6. 常见问题排查实录
6.1 高频问题速查表
我把这一年多用到EasyCode的典型问题整理了张表,按出现频率排了个序:
| 现象 | 原因 | 解决办法 |
|---|---|---|
| 测试连接失败,报timezone错误 | MySQL驱动时区问题 | URL加serverTimezone=Asia/Shanghai |
| 右键表没有Generate Code选项 | 未打开Database面板且选中表 | 确认表是在Database面板里右键 |
| 生成后文件没出现 | 文件已存在被跳过 | 勾选覆盖选项,或先删旧文件 |
| 生成的实体类字段是乱码 | 数据库表注释/字段注释编码异常 | 连接URL加characterEncoding=utf-8 |
| 生成代码报模板语法错 | Velocity模板里有未定义变量 | 加!使变量为空时输出空串 |
| 接口方法生成了但XML没有对应SQL | 模板组里没勾选mapper.xml | 进入模板分组把xml模板勾上 |
bigint映射成了Long但我想用String | 类型映射默认规则 | 在Type Mapper里修改对应映射 |
6.2 三个典型案例的排查思路
第一个案例是"生成出来的Controller类名不对"。我们有个表叫t_order_detail_info,EasyCode默认转驼峰生成TOrderDetailInfo,但项目规范要求类名去掉前缀T_变成OrderDetailInfo。这个处理有两个思路:一是改模板,在类名取值时做字符串处理;二是直接改表名(如果表名前缀是历史遗留,改表名就不现实)。我用的方案是在模板里加一行velocity判断,判断表名以t_开头则截取后续部分,实现起来也很简单:
#set($className = $!tableInfo.name.substring($!tableInfo.name.indexOf("_") + 1))然后所有用到类名的地方都换成$className变量。
第二个案例是"生成的Mapper XML无法正常绑定"。现象是运行时报Invalid bound statement (not found)。排查后发现原因是我生成的xml文件被放到了resources目录之外,MyBatis扫描不到。解决方案是确保生成路径选的resources里对应的mapper目录,而且mybatis配置里的mapper-locations要指向那个路径。这个和EasyCode本身无关,但用生成工具的人十个有八个会遇到,特此记录。
第三个案例是数据库驱动缺失问题。IDEA的Database面板里如果没下载对应数据库的驱动,连接就会报Cannot connect: Driver not found。处理办法是在数据源配置界面点Download Driver按钮让IDEA自动下载驱动。内网环境如果下载不了,就手动把驱动的jar包加到IDEA的驱动库路径里。
6.3 排查思路总结
用EasyCode遇到问题,我的排查顺序是先看数据库连接是否正常,再看模板是否有语法问题,最后再看生成路径是否正确。九成问题都出在这三个环节。与其每次排查一遍,不如把这些检查项记下来形成一个自己的清单,时间长了基本看一眼报错就能定位。
7. 我踩过的坑和一些心得
讲几个只有实际用才会发现的细节。
第一,关于覆盖策略。EasyCode默认不覆盖已有文件这个特性,既是保护也是坑。有时候我改了模板,重新生成同一批表,本以为能覆盖更新,结果发现文件压根没变。后来我养成一个习惯:改完模板需要重新生成时,先手动清理掉旧的生成文件,再执行生成。虽然多一步操作,但心里有底,不会出现新旧代码混在一起的局面。
第二,关于Lombok的取舍。默认实体类模板生成的是一堆Getter/Setter方法,代码量很大。如果你的项目引入了Lombok,强烈建议把实体类模板改成只保留@Data注解加字段定义。生成出来十几行的类看着神清气爽。但有一点要提醒:Lombok编译期生效,如果团队里有人不开Lombok插件或者用的IDE版本不兼容,编不过,这就不是生成工具能管的事了。
第三,关于生成代码的责任边界。EasyCode能帮你生成基础骨架,但别把一次性代码生成工具当成代码维护工具。不要想着以后每次表结构变了都重新生成一次来覆盖代码,那会把你在业务方法里写的逻辑全冲掉。正确姿势是:表结构稳定的阶段用生成器建好骨架,之后业务代码全部手写迭代。表结构变动时,用数据库迁移工具去改表,再手动同步修改相关代码。这样既享受了生成效率,又不会让生成器成为代码的隐患。
第四,关于模板版权和团队沉淀。公司内部的代码模板其实是一笔隐形财富。我建议模板统一改好后,导出成文件放到团队内部的代码仓库里,新同事入职拉下来直接导入IDEA,大家生成出来的代码风格天然一致。这种标准化带来的好处,比想象中大得多。
我自己用EasyCode一年多,最深的感受是:这类工具的上限不取决于插件本身,而取决于你愿不愿意花时间去打磨模板。默认模板只解决了从零到一的问题,自定义模板才真正解决了从一到统一规范的问题。花半小时把模板改成适合自己的样子,后面每天都能省出至少一两个小时,这笔账怎么算都划算。