文章目录
MyBatis-Plus 代码生成器 的 作用 为:
基于数据库表结构,自动生成 与表对应的实体类、Mapper 接口及 XML 文件、Service 接口与实现类、Controller 控制器等全套基础代码,大幅减少 手动编写重复性代码的工作量,保证代码结构规范统一,且支持自定义生成规则适配不同项目的命名、注解等规范,提升开发效率。
目前 MyBatis-Plus 代码生成器有旧版和新版两种,官网指出:新的代码生成器更加的简洁与强大,推荐大家都升级到新的代码生成器。
以下总结 MyBatis-Plus 新版代码生成器 的使用步骤。
1、导入依赖
需要导入的依赖有:
- MyBatis-Plus 核心依赖;
- MyBatis-Plus 新版代码生成器依赖;
- 模板引擎依赖(新版默认内置 Velocity,也可选择 Freemarker/Beetl 等)。
特别注意 :MyBatis-Plus 核心依赖需要根据 Spring Boot 版本来选择,否则会因为兼容性问题报错。可以查看这篇博客:分别与 Spring Boot 2.x/3.x/4.x 版本兼容的最新 MyBatis-Plus 依赖。
我项目中使用的 Spring Boot 版本为 4.0.3,并选用了 Freemarker 模板引擎,以下是导入的依赖:
xml
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot4-starter</artifactId>
<version>3.5.15</version>
</dependency>
<!-- mybatis-plus-generator -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.15</version>
</dependency>
<!-- freemarker -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.34</version>
</dependency>
2、编写代码生成器类
可以在项目目录中新建一个专门的包 generator(与 controller、mapper 包同级),然后在 generator 包中创建一个代码生成器类 CodeGenerator.java,这样既不污染业务代码,也方便管理。
CodeGenerator.java 模板代码如下,可直接复制后修改:
java
package com.sun3285.backend.generator;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.annotation.IdType;
import java.util.Collections;
public class CodeGenerator {
public static void main(String[] args) {
// ====================== 1. 数据库配置(必须与 application.yaml 保持一致) ======================
// 数据库连接地址
String url = "jdbc:oceanbase://xxx.xxx.xxx.xxx:xxx/xxx?useUnicode=true&characterEncoding=utf8&useSSL=false";
// 数据库用户名
String username = "xxx";
// 数据库密码
String password = "xxx";
// ====================== 2. 代码生成核心配置 ======================
FastAutoGenerator.create(url, username, password)
// ---------------------- 全局配置:影响所有生成文件的基础配置 ----------------------
.globalConfig(builder -> {
builder.author("Sun3285") // 生成代码的作者注释
// 代码输出根目录,需要适配项目结构
.outputDir(System.getProperty("user.dir") + "/backend/src/main/java")
.enableSpringdoc() // 开启 SpringDoc,无需则删除
.commentDate("yyyy-MM-dd"); // 注释中的日期格式
})
// ---------------------- 包配置:指定各层代码的包名和输出路径 ----------------------
.packageConfig(builder -> {
builder.parent("com.sun3285.backend") // 父包名,必填,与项目基础包一致
.moduleName("") // 子模块名
.entity("pojo") // 实体类包名,适配项目的 pojo 目录
.mapper("mapper") // Mapper 接口包名,适配项目的 mapper 目录
.xml("mapper") // Mapper XML 逻辑包名,仅标识,实际路径由 pathInfo 控制
.service("service") // Service 接口包名,适配项目的 service 目录
.serviceImpl("service.impl") // Service 实现类包名,适配项目的 service/impl 目录
.controller("controller") // Controller 类包名,适配项目的 controller 目录
// 指定 Mapper XML 文件输出路径,适配 resources/mapper 目录
.pathInfo(Collections.singletonMap(OutputFile.xml,
System.getProperty("user.dir") + "/backend/src/main/resources/mapper"));
})
// ---------------------- 策略配置:各层代码的生成规则 ----------------------
.strategyConfig(builder -> {
builder.addInclude("user") // 要生成代码的表名,必填,替换为实际表名,多表用 "," 分隔
.addTablePrefix("t_") // 表前缀过滤,如 t_user → User,无则删除
// 实体类生成策略
.entityBuilder()
.enableLombok() // 开启 Lombok 注解,生成 @Data 等,未引入 Lombok 则删除
.enableTableFieldAnnotation() // 生成 @TableField 字段注解,便于字段映射
.idType(IdType.AUTO) // 主键生成策略,AUTO=自增,ASSIGN_ID=雪花算法
// Controller 生成策略
.controllerBuilder()
.enableRestStyle() // 生成 @RestController,RESTful 风格
.enableHyphenStyle() // 接口路径驼峰转连字符,如userInfo → user-info,符合 RESTful 接口规范
// Service 生成策略
.serviceBuilder()
.formatServiceFileName("%sService") // Service 接口命名,如 UserService
.formatServiceImplFileName("%sServiceImpl") // Service 实现类命名,如 UserServiceImpl
// Mapper 生成策略
.mapperBuilder()
.enableMapperAnnotation() // 生成 @Mapper 注解
.enableBaseResultMap() // 生成通用 ResultMap,便于复杂查询
.enableBaseColumnList(); // 生成通用字段列表,便于查询复用
})
// ---------------------- 模板引擎配置 ----------------------
.templateEngine(new FreemarkerTemplateEngine()) // 使用 Freemarker 模板引擎,如果用默认 Velocity,可去掉这一行
// 执行代码生成
.execute();
}
}
3、关键配置调整
将第 2 步代码生成器类中的部分配置,按照项目的具体情况进行调整。
常见的配置主要分为以下 4 个部分:
- 全局配置(globalConfig)
- 包配置(packageConfig)
- 策略配置(strategyConfig)
- 模板引擎配置(templateEngine)
配置调整的方法可参考以下途径:
下面对配置中的一些常见问题进行总结:
-
在生成器里面配置的数据源信息 url、username 和 password,和已经在
application.yaml中配置的数据源信息有关系吗?-
本质是两个独立的配置,但目标都是对接同一个数据库,只是作用阶段、使用方完全不同,无直接关联;
配置位置 作用阶段 使用方 核心目的 代码生成器类 代码生成阶段(运行 main 方法时) MyBatis-Plus 代码生成器 让生成器连接数据库,读取表结构信息(字段名、类型、主键等),从而生成对应实体类以及 Mapper 等代码 application.yaml 项目运行阶段(启动 Spring Boot 时) Spring Boot + MyBatis-Plus 让项目运行时能连接数据库,执行 CRUD 操作,如调用 userService.list() -
必须保证两者的数据库 url、username 和 password 完全一致,否则生成的代码可能适配错数据库,或项目运行时连不上库;
-
最佳实践 :可以直接复制
application.yaml的数据源信息到生成器即可,避免重复编写出错。
-
-
System.getProperty("user.dir")是什么意思?.outputDir(...)配置后,代码输出根目录是到java这一层吗?System.getProperty("user.dir")用于获取当前项目的工作根目录,即项目文件夹的路径;- 拼接
/xxx/src/main/java后,输出根目录 为:项目根目录/xxx/src/main/java,生成器会在此目录下,按包配置 中配置的包路径及包名自动创建多级子包并放入对应代码,并非仅到java层。
-
.moduleName("")子模块名什么时候需要配置?- 仅在多模块项目 中使用:当项目拆分为
backend-core、backend-api等子模块时,需指定子模块名,让生成器将代码输出到对应子模块的源码目录; - 如果是单模块项目,只有一个模块的情况下,直接留空即可,配置值会额外创建子包,破坏现有结构。
- 仅在多模块项目 中使用:当项目拆分为
-
.xml("mapper")是 Mapper XML 逻辑包名,若改为.xml("mapper.xml"),是否需要在mapper包下新建xml子包放 XML?- 不需要 。
.xml("mapper")是逻辑包名 ,仅影响 XML 文件的namespace命名,不决定实际存储路径; - XML 文件的实际位置 由
.pathInfo(...)控制,始终输出到resources/mapper目录;改为.xml("mapper.xml")只会让namespace变成com.xxx.xxx.mapper.xml.xxxMapper,不符合规范,建议保持xml("mapper")。
- 不需要 。
-
已手动编写
user表代码,再次执行生成器会覆盖还是报错?- 跳过该表,不覆盖也不报错,控制台提示:文件已存在,跳过生成;
- 建议手动修改过的表,执行前在
addInclude中移除该表名。
-
数据库已配置主键自增,为什么还要配
.idType(IdType.AUTO)?- 数据库自增是存储层规则 ,
idType(IdType.AUTO)是 MyBatis-Plus 框架识别规则 :- 不配置时,框架默认策略可能导致插入数据时主键赋值冲突,自增失效;
- 配置后,框架明确识别主键为数据库自增,插入时自动跳过主键赋值,保证框架与数据库行为一致。
- 数据库自增是存储层规则 ,
-
.enableHyphenStyle()驼峰转连字符符合 RESTful 规范,能举个例子吗?- 该配置会将接口路径的驼峰命名转为小写 + 连字符,示例:
- 未开启 :
getUserInfo()生成接口路径/userInfo/{id}; - 开启后 :
getUserInfo()生成接口路径/user-info/{id},更符合 RESTful 规范的可读性要求。
- 未开启 :
java// 开启 enableHyphenStyle() 后生成的 Controller 方法 @GetMapping("/user-info/{id}") public Result<User> getUserInfo(@PathVariable Long id) { return Result.success(userService.getById(id)); } - 该配置会将接口路径的驼峰命名转为小写 + 连字符,示例:
-
.formatServiceFileName("%sService")中的%s是什么意思?%s是字符串占位符 ,代表表名对应的实体类名 ,例如:- 表
user→ 实体类User→ 替换%s后生成UserService; - 若改为
I%sService,则生成IUserService,可灵活适配团队命名规范。
- 表
-
.enableBaseResultMap()和.enableBaseColumnList()有什么用?能举例吗?-
enableBaseResultMap():生成通用ResultMap,复用字段映射关系,避免复杂查询时重复写映射配置:xml<resultMap id="BaseResultMap" type="com.sun3285.backend.pojo.User"> <id column="id" property="id" jdbcType="BIGINT"/> <result column="user_name" property="userName" jdbcType="VARCHAR"/> <result column="age" property="age" jdbcType="INTEGER"/> </resultMap> <!-- 复杂查询时直接复用 --> <select id="getUserWithOrder" resultMap="BaseResultMap"> SELECT u.id, u.user_name, u.age, o.order_no FROM user u LEFT JOIN order o ON u.id = o.user_id WHERE u.id = #{id} </select> -
enableBaseColumnList():生成通用字段列表 SQL 片段,避免重复写字段名:xml<sql id="Base_Column_List"> id, user_name, age </sql> <!-- 查询时直接复用 --> <select id="listUserByAge" resultType="com.sun3285.backend.pojo.User"> SELECT <include refid="Base_Column_List"/> FROM user WHERE age > #{age} </select>
-
-
代码生成器只能在项目初期用一次吗?后期加新表还能用吗?
- 不是,全生命周期都可使用 :
- 初期:批量生成所有基础表代码,快速搭建项目骨架;
- 后期 :新增表时,仅在
addInclude中指定新表名,如addInclude("new_table"),执行生成器即可单独生成该表的全套代码。
- 不是,全生命周期都可使用 :
4、执行代码生成
直接运行 CodeGenerator.java 类的 main 方法。
执行成功后,会按照第 3 步中的相应配置,在对应包下生成以下文件:
pojo包:实体类,如User.java;mapper包:Mapper 接口,如UserMapper.java;resources/mapper包:Mapper XML 文件,如UserMapper.xml;service包:Service 接口,如UserService.java;service/impl包:Service 实现类,如UserServiceImpl.java;controller包:Controller 类,如UserController.java。
代码生成器执行前

代码生成器执行后

5、其他配置
-
在启动类上添加 Mapper 扫描:
- 打开项目启动类
xxxApplication.java; - 添加
@MapperScan注解,如@MapperScan("com.xxx.xxx.mapper")。
- 打开项目启动类
在以下场景可不配置:
- Mapper 接口上都加了
@Mapper注解;- 代码生成器中已开启
.enableMapperAnnotation()配置(会自动在 Mapper 接口上生成@Mapper注解)。但出于规范管理的考虑,建议配置 ,可以明确指定的扫描路径,同时避免遗漏,防止某个 Mapper 接口忘记添加
@Mapper注解。
-
在 application.yml 中配置 MyBatis-Plus:
yamlmybatis-plus: mapper-locations: classpath*:/mapper/**/*.xml # 为默认值,扫描 xxxMapper.xml 文件 type-aliases-package: com.sun3285.backend.pojo # 实体类包名
mapper-locations:
- 可省场景 :XML 文件放在了
resources/mapper目录(或子目录)下;- 不可省场景:XML 文件放在了其他路径,此时必须配置指定路径。
type-aliases-package:
- 不配置 :无妨,XML 中 resultType 可以使用实体类的全限定名,如:
resultType="com.sun3285.backend.pojo.User";- 配置 :更好,可以简化 XML 配置,无需写全限定名,例如:
resultType="User"。