ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

EasyCode实战:用IDEA插件一键生成CRUD代码的完整指南

EasyCode实战:用IDEA插件一键生成CRUD代码的完整指南 干这行最烦躁的一件事就是项目刚开始时那几十张表的 CRUD 代码。我上个月接了个内部管理系统数据库里躺着七十多张表每个业务都不复杂但每个菜单背后都得配齐 entity、dao、mapper、service、serviceImpl、controller 这一整套。按老办法手写一张表二十来分钟七十张表就是二十多个小时更别说复制粘贴时最容易漏改字段名。当时组里一个同事打开 IDEA 插件市场装了个 EasyCode在 Database 窗口选中一张表右键 Generate Code几秒钟就把六层文件全部生成了。我第一反应是这种插件是不是早就过时了结果自己动手跑了一遍才意识到是我把它想简单了。这篇内容就是把这次完整实践记下来从环境准备、表结构设计到模板原理、一键生成再到我踩过的各种坑全部摊开讲。适合正在用 IDEA 做 Spring Boot 项目的开发者尤其是还在一张表一张表手写 CRUD 的朋友。1. 为什么表结构驱动的“六件套”生成依然值得写进团队流程1.1 一个让我重新拾起EasyCode的真实场景那个项目的表结构出来后我第一次意识到什么叫“机械劳动”。每张表都要写一个 Java Bean字段要一个个对着表结构敲dao 接口要继承基础接口、声明泛型mapper XML 要写 resultMap、写 CRUD SQL、写条件查询service 接口定义方法serviceImpl 里再把 dao 的方法包装一遍controller 再开一套 RESTful 接口。单个功能不难难的是七十张表重复做七十遍。就算用 MyBatis Generator还得另外配置生成规则而且生成的 XML 风格不一定和自己的项目一致。当时组里同事用 EasyCode 现场演示了一遍选中表配置包名勾选要生成的模板点击后 IDEA 底部文件列表刷刷冒出来。我仔细看了生成的实体类、dao、service、controller虽然不能说可以直接上生产但作为第一版代码骨架已经非常完整尤其在字段映射、注解、命名规范上比我手写的还稳定。那次之后我做了个决定新项目的表结构定了第一版 CRUD 代码全部用 EasyCode 生成生成之后我再在基础上去加业务逻辑。省下来的时间不是一点半点。1.2 EasyCode到底“生成”了什么它和手写代码的分界线在哪里很多人一听代码生成器脑子里冒出来的印象是“模板代码一堆坑”。其实要分清楚EasyCode 这类工具做的事情非常窄它根据数据库表的元数据自动生成数据模型到 Java 模型、持久层接口、Mapper XML、Service 壳子、Controller 壳子的这一整条链路。这条链路本质上是“翻译”翻译这种活儿机器做比人做可靠。真正需要人来设计的部分是复杂查询 SQL、跨表聚合、状态机流转、权限控制、缓存策略、事务边界。这些不在这类工具的能力范围内也不应该交给工具做。我的经验是给团队立一个清晰的边界适合生成的实体字段映射、Mapper 基础 CRUD、Service 空实现、Controller 参数接收和转发。不适合生成的业务校验规则、多表关联查询的条件拼接、订单状态流转这种有状态逻辑、涉及第三方接口同步的部分。工具把底层的样板代码铺好我们直接在上面写真正的业务这是代码生成器最正确的打开方式。EasyCode 的价值不在于“代码自动完成”而在于把重复劳动从人的身上剥离掉。2. 安装与数据源先把IDEA右侧的Database窗口用明白2.1 安装EasyCode前的三个前置检查EasyCode 是 IDEA 插件不是独立软件它的工作前提是 IDEA 里的 Database 工具窗口能正常连上数据库。我见过不少人安装完插件后一脸懵右键没有菜单或者生成报错一查全是准备工作没做。安装之前先确认三件事。第一IDEA 版本别太老。我目前用的是 2024.1 版本直接在插件市场搜 EasyCode 就能搜到并安装成功。如果你在 Marketplace 搜不到大概率是插件的版本兼容范围没覆盖到你当前的 IDEA 版本这时候可以去插件的 GitHub Release 页下载对应版本的 zip 包通过 Settings - Plugins - Install Plugin from Disk 安装。别去下那些来路不明的“离线包”指不定里面塞了什么。第二项目本身要能正常构建。生成出来的代码最终要落进你的 Maven/Gradle 工程里如果项目依赖本身都有问题生成后一堆红色报错很难判断是生成器的问题还是工程的问题。建议先用一个干净的 Spring Boot 项目做第一次验证。第三Database 窗口里必须能看到目标库的表。这是 EasyCode 对 IDE 的核心依赖它从数据库元数据里拿表名、字段、类型、注释而不是从你的代码反推。下面详细说这块。2.2 在Database工具窗口里配置MySQL数据源打开 IDEA 右侧的 Database 工具窗口默认快捷键是 Alt1不同版本可能不同点击加号选 Data Source - MySQL。填主机、端口、用户名、密码和要连接的数据库名。有几点我每次都要检查URL 里必须带?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/ShanghaiuseSSLfalse少了 serverTimezone新版驱动大概率直接连不上少了 characterEncoding后面生成出来的中文注释就等着乱码。如果数据库密码里有、#这类特殊字符用 URL 方式连接时容易解析出错我一般会碰到这种情况就改用驱动属性面板去填或者先改个临时密码跑通流程。连接测试时提示缺少驱动文件直接按提示点下载一般都能自动完成。公司内网限制下载的话就手动下载对应版本的 MySQL Connector/J jar 包在数据源设置里指定驱动路径。测试连接通过后左侧会展示库里的表。这一步能展开看到表、列、注释、主键才说明 IDEA 真正读到了表结构EasyCode 也就有了数据来源。2.3 为什么必须“先看到表再生成”我遇到过有人装完插件跳过了 Database 配置这一步直接在编辑器里右键选表自然什么都找不到。EasyCode 不像某些插件那样靠识别你打开的实体类来反推生成它只认数据库表。所以库里的表必须能展开看到字段列表否则插件拿不到元数据菜单都不会出现。视图也能选但我不推荐很多视图不暴露主键生成出来的代码在主键相关逻辑上会有问题。不同数据库驱动版本读到的元数据可能有细微差别比如有些版本会把 tinyint(1) 映射成 Byte有些映射成 Boolean。这些差异都要到后面的 Type Mapper 里去调。简单说数据库连接是 EasyCode 的命根子。连接配好等于成功了一半连接没配好后面全是报错。3. 建表时的几个细节决定了生成代码是“能看”还是“能跑”3.1 注释、主键、下划线命名如何映射到Java代码EasyCode 的生成逻辑是“表结构决定代码质量”。你和它之间的约定很直接表注释会成为实体类的类注释也会出现在 service 接口的注释里。字段注释会成为实体字段的注释以及 controller 中参数相关的注释。主键列id会被识别成主键字段生成TableId这类注解。下划线字段名会转成驼峰user_name变成userNamecreate_time变成createTime。所以表结构设计本身就在影响代码可读性。如果表字段全是没有注释的拼音缩写生成出来的实体类同样没人看得懂。数据库类型到 Java 类型的映射是有规律可循的大部分场景下这样对应数据库列类型默认映射的Java类型BIT / TINYINT(1)Boolean 或 Byte取决于驱动和配置TINYINT / SMALLINTByte / ShortINTIntegerBIGINTLongFLOAT / DOUBLEFloat / DoubleDECIMALBigDecimalVARCHAR / CHAR / TEXTStringDATEDate / LocalDateDATETIME / TIMESTAMPDate / LocalDateTimeJSONString 或对应JSON类型这些映射全部可以在 Settings - Other Settings - EasyCode - Type Mapper 里改。如果你项目用的是 Java 8 及以上我强烈建议把 DATETIME 映射成 LocalDateTime而不是 java.util.Date否则后面处理时间格式会很难受。3.2 一个正确的示例表和三种会“带歪”生成结果的表先看一张我常用的订单表设计CREATE TABLE t_order ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主键, order_no varchar(32) NOT NULL COMMENT 订单号, user_id bigint NOT NULL COMMENT 下单用户ID, total_amount decimal(10,2) DEFAULT NULL COMMENT 订单金额, status tinyint(1) NOT NULL DEFAULT 0 COMMENT 状态0-待支付 1-已支付 2-已取消, create_time datetime NOT NULL COMMENT 创建时间, update_time datetime NOT NULL COMMENT 更新时间, deleted tinyint(1) NOT NULL DEFAULT 0 COMMENT 逻辑删除标记, PRIMARY KEY (id) ) COMMENT 订单主表;这张表注释完整、主键清晰、字段类型规整生成出来的代码基本不用大改。反过来三种表结构会把生成结果带歪。第一种是完全没有主键的表。EasyCode 生成时拿不到主键信息实体类上就不会有主键对应注解后续按主键更新的方法直接废掉。更麻烦的是如果表中存在联合主键默认模板只对单主键友好生成后需要手工大改。第二种是字段全用拼音缩写、没有注释的表。比如user_id写成yhbhcreate_time写成cjsj生成出来的实体就是一堆yhbh、cjsj字段代码完全不可读。第三种是类型不规律的表。比如金额用 varchar 存日期用 string 存bool 用 int 存但语义不统一Type Mapper 再怎么配都救不了“设计时埋下的雷”。我的建议是在团队里定一个建表规范必须有主键、必须有注释、遵循下划线命名、金额一律 decimal、时间统一 datetime然后在开始新功能前先让表结构评审过一遍。表结构稳了生成代码才是真正的提效。4. 模板引擎不是黑魔法读懂EasyCode内置变量就能定制自己的生成风格4.1 一次生成动作中会用到的主要变量EasyCode 的模板引擎是 Velocity它的工作方式不复杂插件拿到表的元数据后把数据塞进一个上下文对象再渲染模板字符串。你在模板里看到的那些$tableInfo.name、$columnInfo.comment实际上就是上下文里的变量。只要搞懂这些变量代表什么就能自己改模板。我自己常用的变量表格整理如下变量名含义$tableInfo.name实体类名由表名转换得到如t_order-TOrder取决于模板转换逻辑$tableInfo.table.name数据库表原始名如t_order$tableInfo.table.comment表注释$tableInfo.pkColumn主键列信息对象$tableInfo.fullColumn全部列信息对象集合$tableInfo.otherColumn非主键列信息对象集合$columnInfo.name实体类属性名如userName$columnInfo.comment字段注释$columnInfo.obj.typeJava 类型全限定名如java.lang.Long$classInfo.name类名在 service、controller 模板中更常用$classInfo.packageName包名$classInfo.moduleName模块名取决于生成时填的 Module 名称$packageName生成代码要用的包名$author/$datetime作者名和当前时间来自 Javadoc 配置不同小版本对变量命名可能有差异最靠谱的方式是打开 Settings - Other Settings - EasyCode - Template点开任意一个内置模板看它里面引用了哪些变量。默认模板就是最好的学习资料别自己去背变量名。4.2 从内置模板走到自定义Lombok、Swagger和统一返回默认模板生成的实体类通常是一堆带 getter/setter 的 POJO现在团队里基本都用 Lombok直接在实体类上加Data代码量立刻少一半。再配合 Swagger 注解接口文档也能自动生成。这是我改过的一个实体类模板核心片段package $!{packageName}.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($!{tableInfo.table.name}) public class $!{tableInfo.name} { #foreach($column in $tableInfo.fullColumn) /** $!{column.comment} */ #if($column.name id) TableId(type IdType.AUTO) #end private $!{column.obj.type} $!{column.name}; #end }这个模板有几个关键点TableName($!{tableInfo.table.name})把实体类和表名绑定MyBatis-Plus 才能直接做实体操作。TableId(type IdType.AUTO)让自增主键生效如果你的主键是分布式 ID可以把 IdType 换成 ASSIGN_ID这个要按项目实际主键策略来定。字段类型用$!{column.obj.type}它自带全限定名所以模板里已经把常用类型的 import 写好否则生成的代码会缺导入导致编译失败。Controller 模板我改成了统一返回格式package $!{packageName}.controller; import $!{packageName}.entity.$!{tableInfo.name}; import $!{packageName}.service.$!{tableInfo.name}Service; import $!{packageName}.common.Result; import $!{packageName}.common.PageQuery; import $!{packageName}.common.PageResult; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; RestController RequestMapping(/$!{tableInfo.table.name.toLowerCase()}) public class $!{tableInfo.name}Controller { Resource private $!{tableInfo.name}Service $!{tableInfo.name.toLowerCase()}Service; PostMapping(/page) public ResultPageResult$!{tableInfo.name} page(RequestBody PageQuery query) { return Result.ok($!{tableInfo.name.toLowerCase()}Service.page(query)); } PostMapping(/add) public ResultBoolean add(RequestBody $!{tableInfo.name} entity) { return Result.ok($!{tableInfo.name.toLowerCase()}Service.add(entity)); } }这里有个细节默认模板生成的 service 实例名往往直接用的类名首字母大写比如private OrderService OrderService;语法没错但可读性很差。我在模板里用$!{tableInfo.name.toLowerCase()}把类名转成全小写得到orderService这是 Velocity 对 Java String 方法的直接调用很好用。如果你不想用小写也可以自己在模板里写一个#set($serviceName $!{tableInfo.name})再配合 substring 处理原理一样。模板改完后生成的代码就是自己团队的风格不再需要每次生成完手工批量改。5. 一次完整实操从t_order表到controller、service、dao、mapper的全部产物5.1 建立Spring Boot项目和依赖我用 Spring Initializr 快速建了一个演示项目groupId 用com.exampleartifactId 用order-demo依赖选了 web、mysql-connector-j、mybatis-plus-boot-starter、lombok。如果你项目里用的是 MyBatis-Plus注意 EasyCode 默认 dao 模板生成的接口可能是继承通用 Mapper 风格比如tk.mybatis.mapper.common.MapperT和 MyBatis-Plus 的BaseMapperT不是一回事。两种方式我在团队里都对比过最后还是选了 MyBatis-Plus因为它对 Lambda 查询、分页、逻辑删除支持更丝滑。所以我的做法是在 Settings - Other Settings - EasyCode - Template 里把 dao 模板的继承对象改成com.baomidou.mybatisplus.core.mapper.BaseMapperT保存后用自己模板生成。5.2 右键生成建档的完整操作路径在 Database 窗口中找到t_order表右键选择 EasyCode - Generate Code。弹窗里要做几个配置选择生成到哪个包根目录。我一般选择src/main/java下的包目录比如com.example.order。填模块名。这里填了order那么生成文件会落在类似com.example.order.controller、com.example.order.service的包路径下。勾选需要的模板。我通常勾选 entity、dao、mapperXml、service、serviceImpl、controller 六项。确认输出路径是否正确别生成到了其他 module 里多模块工程这一步特别容易踩。点击确定后IDEA 底部会弹出生成日志和文件列表逐个点开检查。多表批量生成也支持在 Database 窗口按住 Ctrl 多选几张表然后右键执行同一个操作几十张表一次搞定。5.3 生成产物逐个检查我以前习惯生成完直接写业务后来发现生成的代码还是有必要花十分钟检查一下。检查顺序我固定如下。先看 entity。字段类型是否映射正确主键注解和表名注解是否到位Lombok 注解有没有加上。如果表里有create_time、update_time那么字段类型应该已经是 LocalDateTime。再看整个类是否干净有没有多余的 import。看 dao/mapper 接口。它应该继承BaseMapperOrder泛型对应正确的实体类。如果模板默认生成的是通用 Mapper 风格就需要手动改或者用我第 4 节说的自定义模板。看 mapper XML。namespace 要对resultMap 的列名和属性名要能对应上基础的 insert、update、delete、select 语句都在。EasyCode 生成的 XML 基本不会缺东西但列名和属性名的驼峰对应关系值得扫一眼。看 service 接口和 serviceImpl。接口方法是否完整impl 里对 dao 的注入是否没问题。这里有个常见现象生成的 serviceImpl 里很多方法是空实现只写了 return null。这很正常本身就是留给你填业务逻辑的。看 controller。接口路径、请求方式、参数接收方式是否和前端约定一致。我检查最多的是RequestMapping里的路径确保是/t_order还是/order这个要根据自己对接口风格的定义去调整。5.4 把分页和统一返回结构合并进生成代码生成代码第一次编译不过最常见的原因是 controller 模板里引用了项目里不存在的类。默认模板里可能有一个R返回对象但你的工程里根本没有这个类所以会爆红。我的做法是在模板里直接写死自己的统一返回类Result和分页查询参数PageQuery。这两个类在项目里一定存在而且所有接口都统一使用。生成后controller 里的接口返回类型就是项目通用的ResultT分页接口接收PageQuery返回PageResultT整个风格就跟团队其他接口完全一致。这样做的好处是生成完 CRUD 之后不用再花时间改返回包装直接进入业务实现。如果你项目里还没有统一的返回类和分页查询对象建议先在 common 模块里把这两个基础类建好再来改模板。6. 高频报错与我的排查链路右键没菜单、模板报错、字段映射失真6.1 场景右键看不到EasyCode菜单这个现象最容易发生在新装插件的机器上。我的排查链路是固定的确认插件已启用Settings - Plugins搜 EasyCode看状态是 Installed 而不是 Disabled。确认 Database 窗口已经配置数据源并且连接成功这个窗口里能展开表结构才行。确认选中的节点是表本身而不是数据库连接节点或 schema 节点。EasyCode 只认表节点选中连接节点右键是没有 Generate Code 的。如果表结构以前能看到现在看不到了右键表节点选 Refresh 刷新元数据。如果以上都正常重启 IDEA。插件安装后偶尔需要重启才能加载右键菜单。6.2 场景生成中途模板渲染报错我最早自己改模板时经常生成到一半弹个红色异常内容大概是模板文件里某处引用的变量不识别。排查方法很直接弹窗里的错误信息会指向模板名和大概位置点开对应的模板检查变量名拼写。模板变量是区分大小写的$tableinfo.name和$tableInfo.name就是两个完全不同的东西前者在模板上下文里不存在必然报错。另一个常见问题是模板里写了自定义的扩展字段但表没配扩展字段。EasyCode 在表配置里可以加自定义列模板里可以引用但如果对应关系不对会渲染出空值或者直接报错。我的经验是每次改完模板先用一张最简单的表跑一次生成不要拿生产环境的大表直接试。小表结构简单报错定位更快。6.3 场景实体类属性与表字段对不上生成出来的属性名和数据库字段完全对不上这种情况我遇到的基本是三个原因。第一表的字段名不是标准的蛇形命名。比如字段就叫userName驼峰直接写进表里EasyCode 转换时会按自己的规则解析结果可能是username或者user_name和你预想的不一致。数据库字段建议统一用全小写下划线这是和 EasyCode 配合最顺畅的格式。第二Type Mapper 里缺少对应类型的映射。数据库里出现了一个模板没覆盖到的类型插件会映射成 Object生成出来的实体字段直接变成 Object编译过不去。解决办法是到 Type Mapper 里把类型补上。第三连接元数据过期。表结构改了但 IDEA 缓存里还是旧的右键表节点点 Refresh 就好。6.4 场景中文注释变成乱码或生成文件是GBK这个是老项目中特别常见的坑。表注释是中文生成的实体类里注释全是问号或类似订åÂÂ的乱码看着就头疼。排查链路数据库连接 URL 里必须有characterEncodingUTF-8没有的话 IDE 读出来的元数据就是乱的后面生成自然乱。IDEA 的 File Encodings 设置为 UTF-8Settings - Editor - File Encodings把 Global Encoding、Project Encoding 和 Properties Files 都改成 UTF-8。检查数据库本身的字符集历史表如果是 latin1 编码连接参数加了也救不回来这种只能从源头改表。我建议项目第一天就把所有编码统一成 UTF-8后面能省掉大量这种莫名其妙的排错时间。6.5 一个容易忽视的坑重新生成把手工代码覆盖了EasyCode 生成的文件如果已经存在默认会提示是否覆盖。刚开始用的时候我没注意改完业务逻辑后重新点了生成结果刚写的几十行业务代码直接被覆盖git diff 一看全没了。从那以后我就记住了生成时只勾选当前真正需要生成的模板不要每次都全选。配置生成策略时尽量选择“跳过已存在文件”或“生成到单独目录”。用 Git 的话生成前先 commit 一次生成后 diff 着看避免误伤。这个坑不在插件本身而在使用习惯。工具能帮你把时间省回来也能几秒钟把一天的活全冲掉。7. 我沉淀下来的配置清单和使用习惯最后把我的 EasyCode 配置习惯整理出来算是给这篇文章收个尾。Settings - Other Settings - EasyCode 里我会固定检查四部分Javadoc作者写自己或者团队公共名称日期格式用yyyy-MM-dd HH:mm:ss。Template把内置模板复制一份改造成当前团队的技术栈。实体类加 Lombokdao 继承 MyBatis-Plus BaseMappercontroller 用统一 Result 和 PageQuery。Type Mapper把 DATETIME 映射成 LocalDateTimeDATE 映射成 LocalDateDECIMAL 映射成 BigDecimalTINYINT(1) 映射成 Boolean。Path默认输出到当前 module 的src/main/java不要跑到其他模块去。使用上我还有一个坚持到现在的小习惯每次新表生成完成后我不会立刻上去写业务而是先做一次全量编译确认生成的代码干净了提交一个 Commit算是给底层代码打个底。之后再写业务逻辑改的东西在 git 里看起来全是对着这个底子做的增量review 起来特别清楚。代码生成器这个东西用好了是副驾驶用不好就是草稿机。EasyCode 在你理解它的模板机制之后上限其实很高团队规范越清晰生成出来的东西越接近可直接上线的代码。希望这篇实践记录能帮你们把这条路走顺一点。
返回列表